X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/9b9fbe8a4e9eec9072ee2697a6af59144442785f..079911cb6e26898e16f5bb56ef4f9d33cf92d32d:/ui/sdl2.c diff --git a/ui/sdl2.c b/ui/sdl2.c index faf9bdff5c..2696b95c79 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -38,8 +38,6 @@ static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static int gui_saved_grab; static int gui_fullscreen; -static int gui_noframe; -static int gui_key_modifier_pressed; static int gui_keysym; static int gui_grab_code = KMOD_LALT | KMOD_LCTRL; static SDL_Cursor *sdl_cursor_normal; @@ -141,11 +139,11 @@ static void sdl_update_caption(struct sdl2_console *scon) status = " [Stopped]"; } else if (gui_grab) { if (alt_grab) { - status = " - Press Ctrl-Alt-Shift to exit grab"; + status = " - Press Ctrl-Alt-Shift-G to exit grab"; } else if (ctrl_grab) { - status = " - Press Right-Ctrl to exit grab"; + status = " - Press Right-Ctrl-G to exit grab"; } else { - status = " - Press Ctrl-Alt to exit grab"; + status = " - Press Ctrl-Alt-G to exit grab"; } } @@ -169,10 +167,10 @@ static void sdl_hide_cursor(void) return; } - if (qemu_input_is_absolute()) { - SDL_ShowCursor(1); - SDL_SetCursor(sdl_cursor_hidden); - } else { + SDL_ShowCursor(SDL_DISABLE); + SDL_SetCursor(sdl_cursor_hidden); + + if (!qemu_input_is_absolute()) { SDL_SetRelativeMouseMode(SDL_TRUE); } } @@ -185,14 +183,16 @@ static void sdl_show_cursor(void) if (!qemu_input_is_absolute()) { SDL_SetRelativeMouseMode(SDL_FALSE); - SDL_ShowCursor(1); - if (guest_cursor && - (gui_grab || qemu_input_is_absolute() || absolute_enabled)) { - SDL_SetCursor(guest_sprite); - } else { - SDL_SetCursor(sdl_cursor_normal); - } } + + if (guest_cursor && + (gui_grab || qemu_input_is_absolute() || absolute_enabled)) { + SDL_SetCursor(guest_sprite); + } else { + SDL_SetCursor(sdl_cursor_normal); + } + + SDL_ShowCursor(SDL_ENABLE); } static void sdl_grab_start(struct sdl2_console *scon) @@ -248,6 +248,7 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data) if (qemu_input_is_absolute()) { if (!absolute_enabled) { absolute_enabled = 1; + SDL_SetRelativeMouseMode(SDL_FALSE); absolute_mouse_grab(&sdl2_console[0]); } } else if (absolute_enabled) { @@ -274,32 +275,10 @@ static void sdl_send_mouse_event(struct sdl2_console *scon, int dx, int dy, } if (qemu_input_is_absolute()) { - int scr_w, scr_h; - int max_w = 0, max_h = 0; - int off_x = 0, off_y = 0; - int cur_off_x = 0, cur_off_y = 0; - int i; - - for (i = 0; i < sdl2_num_outputs; i++) { - struct sdl2_console *thiscon = &sdl2_console[i]; - if (thiscon->real_window && thiscon->surface) { - SDL_GetWindowSize(thiscon->real_window, &scr_w, &scr_h); - cur_off_x = thiscon->x; - cur_off_y = thiscon->y; - if (scr_w + cur_off_x > max_w) { - max_w = scr_w + cur_off_x; - } - if (scr_h + cur_off_y > max_h) { - max_h = scr_h + cur_off_y; - } - if (i == scon->idx) { - off_x = cur_off_x; - off_y = cur_off_y; - } - } - } - qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, off_x + x, max_w); - qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, off_y + y, max_h); + qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, + x, 0, surface_width(scon->surface)); + qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, + y, 0, surface_height(scon->surface)); } else { if (guest_cursor) { x -= guest_x; @@ -332,22 +311,27 @@ static void toggle_full_screen(struct sdl2_console *scon) sdl2_redraw(scon); } -static void handle_keydown(SDL_Event *ev) +static int get_mod_state(void) { - int mod_state, win; - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + SDL_Keymod mod = SDL_GetModState(); if (alt_grab) { - mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) == + return (mod & (gui_grab_code | KMOD_LSHIFT)) == (gui_grab_code | KMOD_LSHIFT); } else if (ctrl_grab) { - mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL; + return (mod & KMOD_RCTRL) == KMOD_RCTRL; } else { - mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code; + return (mod & gui_grab_code) == gui_grab_code; } - gui_key_modifier_pressed = mod_state; +} + +static void handle_keydown(SDL_Event *ev) +{ + int win; + struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + int gui_key_modifier_pressed = get_mod_state(); - if (gui_key_modifier_pressed) { + if (!scon->ignore_hotkeys && gui_key_modifier_pressed && !ev->key.repeat) { switch (ev->key.keysym.scancode) { case SDL_SCANCODE_2: case SDL_SCANCODE_3: @@ -378,9 +362,16 @@ static void handle_keydown(SDL_Event *ev) toggle_full_screen(scon); gui_keysym = 1; break; + case SDL_SCANCODE_G: + gui_keysym = 1; + if (!gui_grab) { + sdl_grab_start(scon); + } else if (!gui_fullscreen) { + sdl_grab_end(scon); + } + break; case SDL_SCANCODE_U: - sdl2_window_destroy(scon); - sdl2_window_create(scon); + sdl2_window_resize(scon); if (!scon->opengl) { /* re-create scon->texture */ sdl2_2d_switch(&scon->dcl, scon->surface); @@ -418,28 +409,12 @@ static void handle_keydown(SDL_Event *ev) static void handle_keyup(SDL_Event *ev) { - int mod_state; struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + int gui_key_modifier_pressed = get_mod_state(); - if (!alt_grab) { - mod_state = (ev->key.keysym.mod & gui_grab_code); - } else { - mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT)); - } - if (!mod_state && gui_key_modifier_pressed) { - gui_key_modifier_pressed = 0; - if (gui_keysym == 0) { - /* exit/enter grab if pressing Ctrl-Alt */ - if (!gui_grab) { - sdl_grab_start(scon); - } else if (!gui_fullscreen) { - sdl_grab_end(scon); - } - /* SDL does not send back all the modifiers key, so we must - * correct it. */ - sdl2_reset_keys(scon); - return; - } + scon->ignore_hotkeys = false; + + if (!gui_key_modifier_pressed) { gui_keysym = 0; } if (!gui_keysym) { @@ -449,7 +424,7 @@ static void handle_keyup(SDL_Event *ev) static void handle_textinput(SDL_Event *ev) { - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + struct sdl2_console *scon = get_scon_from_window(ev->text.windowID); QemuConsole *con = scon ? scon->dcl.con : NULL; if (qemu_console_is_graphic(con)) { @@ -461,15 +436,20 @@ static void handle_textinput(SDL_Event *ev) static void handle_mousemotion(SDL_Event *ev) { int max_x, max_y; - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + struct sdl2_console *scon = get_scon_from_window(ev->motion.windowID); + + if (!scon || !qemu_console_is_graphic(scon->dcl.con)) { + return; + } if (qemu_input_is_absolute() || absolute_enabled) { int scr_w, scr_h; SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); max_x = scr_w - 1; max_y = scr_h - 1; - if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 || - ev->motion.x == max_x || ev->motion.y == max_y)) { + if (gui_grab && !gui_fullscreen + && (ev->motion.x == 0 || ev->motion.y == 0 || + ev->motion.x == max_x || ev->motion.y == max_y)) { sdl_grab_end(scon); } if (!gui_grab && @@ -488,7 +468,11 @@ static void handle_mousebutton(SDL_Event *ev) { int buttonstate = SDL_GetMouseState(NULL, NULL); SDL_MouseButtonEvent *bev; - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + struct sdl2_console *scon = get_scon_from_window(ev->button.windowID); + + if (!scon || !qemu_console_is_graphic(scon->dcl.con)) { + return; + } bev = &ev->button; if (!gui_grab && !qemu_input_is_absolute()) { @@ -508,10 +492,14 @@ static void handle_mousebutton(SDL_Event *ev) static void handle_mousewheel(SDL_Event *ev) { - struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + struct sdl2_console *scon = get_scon_from_window(ev->wheel.windowID); SDL_MouseWheelEvent *wev = &ev->wheel; InputButton btn; + if (!scon || !qemu_console_is_graphic(scon->dcl.con)) { + return; + } + if (wev->y > 0) { btn = INPUT_BUTTON_WHEEL_UP; } else if (wev->y < 0) { @@ -529,6 +517,7 @@ static void handle_mousewheel(SDL_Event *ev) static void handle_windowevent(SDL_Event *ev) { struct sdl2_console *scon = get_scon_from_window(ev->window.windowID); + bool allow_close = true; if (!scon) { return; @@ -553,6 +542,14 @@ static void handle_windowevent(SDL_Event *ev) if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) { absolute_mouse_grab(scon); } + /* If a new console window opened using a hotkey receives the + * focus, SDL sends another KEYDOWN event to the new window, + * closing the console window immediately after. + * + * Work around this by ignoring further hotkey events until a + * key is released. + */ + scon->ignore_hotkeys = get_mod_state(); break; case SDL_WINDOWEVENT_FOCUS_LOST: if (gui_grab && !gui_fullscreen) { @@ -566,20 +563,24 @@ static void handle_windowevent(SDL_Event *ev) update_displaychangelistener(&scon->dcl, 500); break; case SDL_WINDOWEVENT_CLOSE: - if (!no_quit) { - no_shutdown = 0; - qemu_system_shutdown_request(); + if (qemu_console_is_graphic(scon->dcl.con)) { + if (scon->opts->has_window_close && !scon->opts->window_close) { + allow_close = false; + } + if (allow_close) { + no_shutdown = 0; + qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); + } + } else { + SDL_HideWindow(scon->real_window); + scon->hidden = true; } break; case SDL_WINDOWEVENT_SHOWN: - if (scon->hidden) { - SDL_HideWindow(scon->real_window); - } + scon->hidden = false; break; case SDL_WINDOWEVENT_HIDDEN: - if (!scon->hidden) { - SDL_ShowWindow(scon->real_window); - } + scon->hidden = true; break; } } @@ -587,6 +588,7 @@ static void handle_windowevent(SDL_Event *ev) void sdl2_poll_events(struct sdl2_console *scon) { SDL_Event ev1, *ev = &ev1; + bool allow_close = true; int idle = 1; if (scon->last_vm_running != runstate_is_running()) { @@ -609,9 +611,12 @@ void sdl2_poll_events(struct sdl2_console *scon) handle_textinput(ev); break; case SDL_QUIT: - if (!no_quit) { + if (scon->opts->has_window_close && !scon->opts->window_close) { + allow_close = false; + } + if (allow_close) { no_shutdown = 0; - qemu_system_shutdown_request(); + qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); } break; case SDL_MOUSEMOTION: @@ -652,6 +657,11 @@ static void sdl_mouse_warp(DisplayChangeListener *dcl, int x, int y, int on) { struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + + if (!qemu_console_is_graphic(scon->dcl.con)) { + return; + } + if (on) { if (!guest_cursor) { sdl_show_cursor(); @@ -739,34 +749,24 @@ static const DisplayChangeListenerOps dcl_gl_ops = { }; #endif -void sdl_display_early_init(int opengl) +static void sdl2_display_early_init(DisplayOptions *o) { - switch (opengl) { - case -1: /* default */ - case 0: /* off */ - break; - case 1: /* on */ + assert(o->type == DISPLAY_TYPE_SDL); + if (o->has_gl && o->gl) { #ifdef CONFIG_OPENGL display_opengl = 1; #endif - break; - default: - g_assert_not_reached(); - break; } } -void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) +static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) { - int flags; uint8_t data = 0; char *filename; int i; SDL_SysWMinfo info; - if (no_frame) { - gui_noframe = 1; - } + assert(o->type == DISPLAY_TYPE_SDL); #ifdef __linux__ /* on Linux, SDL may use fbcon|directfb|svgalib when run without @@ -781,8 +781,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) setenv("SDL_VIDEODRIVER", "x11", 0); #endif - flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; - if (SDL_Init(flags)) { + if (SDL_Init(SDL_INIT_VIDEO)) { fprintf(stderr, "Could not initialize SDL(%s) - exiting\n", SDL_GetError()); exit(1); @@ -791,6 +790,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) memset(&info, 0, sizeof(info)); SDL_VERSION(&info.version); + gui_fullscreen = o->has_full_screen && o->full_screen; + for (i = 0;; i++) { QemuConsole *con = qemu_console_lookup_by_index(i); if (!con) { @@ -804,10 +805,13 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) sdl2_console = g_new0(struct sdl2_console, sdl2_num_outputs); for (i = 0; i < sdl2_num_outputs; i++) { QemuConsole *con = qemu_console_lookup_by_index(i); - if (!qemu_console_is_graphic(con)) { + assert(con != NULL); + if (!qemu_console_is_graphic(con) && + qemu_console_get_index(con) != 0) { sdl2_console[i].hidden = true; } sdl2_console[i].idx = i; + sdl2_console[i].opts = o; #ifdef CONFIG_OPENGL sdl2_console[i].opengl = display_opengl; sdl2_console[i].dcl.ops = display_opengl ? &dcl_gl_ops : &dcl_2d_ops; @@ -841,18 +845,29 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) g_free(filename); } - if (full_screen) { - gui_fullscreen = 1; + gui_grab = 0; + if (gui_fullscreen) { sdl_grab_start(0); } mouse_mode_notifier.notify = sdl_mouse_mode_change; qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier); - gui_grab = 0; - sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); sdl_cursor_normal = SDL_GetCursor(); atexit(sdl_cleanup); } + +static QemuDisplay qemu_display_sdl2 = { + .type = DISPLAY_TYPE_SDL, + .early_init = sdl2_display_early_init, + .init = sdl2_display_init, +}; + +static void register_sdl1(void) +{ + qemu_display_register(&qemu_display_sdl2); +} + +type_init(register_sdl1);