diff options
author | Timothy Pearson <tpearson@raptorengineering.com> | 2019-05-11 15:12:49 -0500 |
---|---|---|
committer | Timothy Pearson <tpearson@raptorengineering.com> | 2019-05-11 15:12:49 -0500 |
commit | 9e80202352dd49bdd9e67b8b906d86f058431505 (patch) | |
tree | 5673c17aad6e3833da8c4ff21b5a11f666ec9fbe /src/ui/sdl2.c | |
download | hqemu-master.zip hqemu-master.tar.gz |
Diffstat (limited to 'src/ui/sdl2.c')
-rw-r--r-- | src/ui/sdl2.c | 806 |
1 files changed, 806 insertions, 0 deletions
diff --git a/src/ui/sdl2.c b/src/ui/sdl2.c new file mode 100644 index 0000000..5cb75aa --- /dev/null +++ b/src/ui/sdl2.c @@ -0,0 +1,806 @@ +/* + * QEMU SDL display driver + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* Ported SDL 1.2 code to 2.0 by Dave Airlie. */ + +#include "qemu-common.h" +#include "ui/console.h" +#include "ui/input.h" +#include "ui/sdl2.h" +#include "sysemu/sysemu.h" + +static int sdl2_num_outputs; +static struct sdl2_console *sdl2_console; + +static SDL_Surface *guest_sprite_surface; +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; +static SDL_Cursor *sdl_cursor_hidden; +static int absolute_enabled; +static int guest_cursor; +static int guest_x, guest_y; +static SDL_Cursor *guest_sprite; +static Notifier mouse_mode_notifier; + +static void sdl_update_caption(struct sdl2_console *scon); + +static struct sdl2_console *get_scon_from_window(uint32_t window_id) +{ + int i; + for (i = 0; i < sdl2_num_outputs; i++) { + if (sdl2_console[i].real_window == SDL_GetWindowFromID(window_id)) { + return &sdl2_console[i]; + } + } + return NULL; +} + +void sdl2_window_create(struct sdl2_console *scon) +{ + int flags = 0; + + if (!scon->surface) { + return; + } + assert(!scon->real_window); + + if (gui_fullscreen) { + flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + } else { + flags |= SDL_WINDOW_RESIZABLE; + } + if (scon->hidden) { + flags |= SDL_WINDOW_HIDDEN; + } + + scon->real_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + surface_width(scon->surface), + surface_height(scon->surface), + flags); + scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0); + if (scon->opengl) { + scon->winctx = SDL_GL_GetCurrentContext(); + } + sdl_update_caption(scon); +} + +void sdl2_window_destroy(struct sdl2_console *scon) +{ + if (!scon->real_window) { + return; + } + + SDL_DestroyRenderer(scon->real_renderer); + scon->real_renderer = NULL; + SDL_DestroyWindow(scon->real_window); + scon->real_window = NULL; +} + +void sdl2_window_resize(struct sdl2_console *scon) +{ + if (!scon->real_window) { + return; + } + + SDL_SetWindowSize(scon->real_window, + surface_width(scon->surface), + surface_height(scon->surface)); +} + +static void sdl2_redraw(struct sdl2_console *scon) +{ + if (scon->opengl) { +#ifdef CONFIG_OPENGL + sdl2_gl_redraw(scon); +#endif + } else { + sdl2_2d_redraw(scon); + } +} + +static void sdl_update_caption(struct sdl2_console *scon) +{ + char win_title[1024]; + char icon_title[1024]; + const char *status = ""; + + if (!runstate_is_running()) { + status = " [Stopped]"; + } else if (gui_grab) { + if (alt_grab) { + status = " - Press Ctrl-Alt-Shift to exit grab"; + } else if (ctrl_grab) { + status = " - Press Right-Ctrl to exit grab"; + } else { + status = " - Press Ctrl-Alt to exit grab"; + } + } + + if (qemu_name) { + snprintf(win_title, sizeof(win_title), "QEMU (%s-%d)%s", qemu_name, + scon->idx, status); + snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name); + } else { + snprintf(win_title, sizeof(win_title), "QEMU%s", status); + snprintf(icon_title, sizeof(icon_title), "QEMU"); + } + + if (scon->real_window) { + SDL_SetWindowTitle(scon->real_window, win_title); + } +} + +static void sdl_hide_cursor(void) +{ + if (!cursor_hide) { + return; + } + + if (qemu_input_is_absolute()) { + SDL_ShowCursor(1); + SDL_SetCursor(sdl_cursor_hidden); + } else { + SDL_SetRelativeMouseMode(SDL_TRUE); + } +} + +static void sdl_show_cursor(void) +{ + if (!cursor_hide) { + return; + } + + 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); + } + } +} + +static void sdl_grab_start(struct sdl2_console *scon) +{ + QemuConsole *con = scon ? scon->dcl.con : NULL; + + if (!con || !qemu_console_is_graphic(con)) { + return; + } + /* + * If the application is not active, do not try to enter grab state. This + * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the + * application (SDL bug). + */ + if (!(SDL_GetWindowFlags(scon->real_window) & SDL_WINDOW_INPUT_FOCUS)) { + return; + } + if (guest_cursor) { + SDL_SetCursor(guest_sprite); + if (!qemu_input_is_absolute() && !absolute_enabled) { + SDL_WarpMouseInWindow(scon->real_window, guest_x, guest_y); + } + } else { + sdl_hide_cursor(); + } + SDL_SetWindowGrab(scon->real_window, SDL_TRUE); + gui_grab = 1; + sdl_update_caption(scon); +} + +static void sdl_grab_end(struct sdl2_console *scon) +{ + SDL_SetWindowGrab(scon->real_window, SDL_FALSE); + gui_grab = 0; + sdl_show_cursor(); + sdl_update_caption(scon); +} + +static void absolute_mouse_grab(struct sdl2_console *scon) +{ + int mouse_x, mouse_y; + int scr_w, scr_h; + SDL_GetMouseState(&mouse_x, &mouse_y); + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); + if (mouse_x > 0 && mouse_x < scr_w - 1 && + mouse_y > 0 && mouse_y < scr_h - 1) { + sdl_grab_start(scon); + } +} + +static void sdl_mouse_mode_change(Notifier *notify, void *data) +{ + if (qemu_input_is_absolute()) { + if (!absolute_enabled) { + absolute_enabled = 1; + absolute_mouse_grab(&sdl2_console[0]); + } + } else if (absolute_enabled) { + if (!gui_fullscreen) { + sdl_grab_end(&sdl2_console[0]); + } + absolute_enabled = 0; + } +} + +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), + }; + static uint32_t prev_state; + + if (prev_state != state) { + qemu_input_update_buttons(scon->dcl.con, bmap, prev_state, state); + prev_state = state; + } + + 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); + } else { + if (guest_cursor) { + x -= guest_x; + y -= guest_y; + guest_x += x; + guest_y += y; + dx = x; + dy = y; + } + qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_X, dx); + qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_Y, dy); + } + qemu_input_event_sync(); +} + +static void toggle_full_screen(struct sdl2_console *scon) +{ + gui_fullscreen = !gui_fullscreen; + if (gui_fullscreen) { + SDL_SetWindowFullscreen(scon->real_window, + SDL_WINDOW_FULLSCREEN_DESKTOP); + gui_saved_grab = gui_grab; + sdl_grab_start(scon); + } else { + if (!gui_saved_grab) { + sdl_grab_end(scon); + } + SDL_SetWindowFullscreen(scon->real_window, 0); + } + sdl2_redraw(scon); +} + +static void handle_keydown(SDL_Event *ev) +{ + int mod_state, win; + struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + + if (alt_grab) { + mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) == + (gui_grab_code | KMOD_LSHIFT); + } else if (ctrl_grab) { + mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL; + } else { + mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code; + } + gui_key_modifier_pressed = mod_state; + + if (gui_key_modifier_pressed) { + switch (ev->key.keysym.scancode) { + case SDL_SCANCODE_2: + case SDL_SCANCODE_3: + case SDL_SCANCODE_4: + case SDL_SCANCODE_5: + case SDL_SCANCODE_6: + case SDL_SCANCODE_7: + case SDL_SCANCODE_8: + case SDL_SCANCODE_9: + win = ev->key.keysym.scancode - SDL_SCANCODE_1; + if (win < sdl2_num_outputs) { + sdl2_console[win].hidden = !sdl2_console[win].hidden; + if (sdl2_console[win].real_window) { + if (sdl2_console[win].hidden) { + SDL_HideWindow(sdl2_console[win].real_window); + } else { + SDL_ShowWindow(sdl2_console[win].real_window); + } + } + gui_keysym = 1; + } + break; + case SDL_SCANCODE_F: + toggle_full_screen(scon); + gui_keysym = 1; + break; + case SDL_SCANCODE_U: + sdl2_window_destroy(scon); + sdl2_window_create(scon); + if (!scon->opengl) { + /* re-create scon->texture */ + sdl2_2d_switch(&scon->dcl, scon->surface); + } + gui_keysym = 1; + break; +#if 0 + case SDL_SCANCODE_KP_PLUS: + case SDL_SCANCODE_KP_MINUS: + if (!gui_fullscreen) { + int scr_w, scr_h; + int width, height; + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); + + width = MAX(scr_w + (ev->key.keysym.scancode == + SDL_SCANCODE_KP_PLUS ? 50 : -50), + 160); + height = (surface_height(scon->surface) * width) / + surface_width(scon->surface); + fprintf(stderr, "%s: scale to %dx%d\n", + __func__, width, height); + sdl_scale(scon, width, height); + sdl2_redraw(scon); + gui_keysym = 1; + } +#endif + default: + break; + } + } + if (!gui_keysym) { + sdl2_process_key(scon, &ev->key); + } +} + +static void handle_keyup(SDL_Event *ev) +{ + int mod_state; + struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + + 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; + } + gui_keysym = 0; + } + if (!gui_keysym) { + sdl2_process_key(scon, &ev->key); + } +} + +static void handle_textinput(SDL_Event *ev) +{ + struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + QemuConsole *con = scon ? scon->dcl.con : NULL; + + if (qemu_console_is_graphic(con)) { + return; + } + kbd_put_string_console(con, ev->text.text, strlen(ev->text.text)); +} + +static void handle_mousemotion(SDL_Event *ev) +{ + int max_x, max_y; + struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + + 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)) { + sdl_grab_end(scon); + } + if (!gui_grab && + (ev->motion.x > 0 && ev->motion.x < max_x && + ev->motion.y > 0 && ev->motion.y < max_y)) { + sdl_grab_start(scon); + } + } + if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { + sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, + ev->motion.x, ev->motion.y, ev->motion.state); + } +} + +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); + + bev = &ev->button; + if (!gui_grab && !qemu_input_is_absolute()) { + if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { + /* start grabbing all events */ + sdl_grab_start(scon); + } + } else { + if (ev->type == SDL_MOUSEBUTTONDOWN) { + buttonstate |= SDL_BUTTON(bev->button); + } else { + buttonstate &= ~SDL_BUTTON(bev->button); + } + sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate); + } +} + +static void handle_mousewheel(SDL_Event *ev) +{ + struct sdl2_console *scon = get_scon_from_window(ev->key.windowID); + SDL_MouseWheelEvent *wev = &ev->wheel; + InputButton btn; + + if (wev->y > 0) { + btn = INPUT_BUTTON_WHEEL_UP; + } else if (wev->y < 0) { + btn = INPUT_BUTTON_WHEEL_DOWN; + } else { + return; + } + + qemu_input_queue_btn(scon->dcl.con, btn, true); + qemu_input_event_sync(); + qemu_input_queue_btn(scon->dcl.con, btn, false); + qemu_input_event_sync(); +} + +static void handle_windowevent(SDL_Event *ev) +{ + struct sdl2_console *scon = get_scon_from_window(ev->window.windowID); + + if (!scon) { + return; + } + + switch (ev->window.event) { + case SDL_WINDOWEVENT_RESIZED: + { + QemuUIInfo info; + memset(&info, 0, sizeof(info)); + info.width = ev->window.data1; + info.height = ev->window.data2; + dpy_set_ui_info(scon->dcl.con, &info); + } + sdl2_redraw(scon); + break; + case SDL_WINDOWEVENT_EXPOSED: + sdl2_redraw(scon); + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + case SDL_WINDOWEVENT_ENTER: + if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) { + absolute_mouse_grab(scon); + } + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + if (gui_grab && !gui_fullscreen) { + sdl_grab_end(scon); + } + break; + case SDL_WINDOWEVENT_RESTORED: + update_displaychangelistener(&scon->dcl, GUI_REFRESH_INTERVAL_DEFAULT); + break; + case SDL_WINDOWEVENT_MINIMIZED: + update_displaychangelistener(&scon->dcl, 500); + break; + case SDL_WINDOWEVENT_CLOSE: + if (!no_quit) { + no_shutdown = 0; + qemu_system_shutdown_request(); + } + break; + case SDL_WINDOWEVENT_SHOWN: + if (scon->hidden) { + SDL_HideWindow(scon->real_window); + } + break; + case SDL_WINDOWEVENT_HIDDEN: + if (!scon->hidden) { + SDL_ShowWindow(scon->real_window); + } + break; + } +} + +void sdl2_poll_events(struct sdl2_console *scon) +{ + SDL_Event ev1, *ev = &ev1; + + if (scon->last_vm_running != runstate_is_running()) { + scon->last_vm_running = runstate_is_running(); + sdl_update_caption(scon); + } + + while (SDL_PollEvent(ev)) { + switch (ev->type) { + case SDL_KEYDOWN: + handle_keydown(ev); + break; + case SDL_KEYUP: + handle_keyup(ev); + break; + case SDL_TEXTINPUT: + handle_textinput(ev); + break; + case SDL_QUIT: + if (!no_quit) { + no_shutdown = 0; + qemu_system_shutdown_request(); + } + break; + case SDL_MOUSEMOTION: + handle_mousemotion(ev); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + handle_mousebutton(ev); + break; + case SDL_MOUSEWHEEL: + handle_mousewheel(ev); + break; + case SDL_WINDOWEVENT: + handle_windowevent(ev); + break; + default: + break; + } + } +} + +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 (on) { + if (!guest_cursor) { + sdl_show_cursor(); + } + if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { + SDL_SetCursor(guest_sprite); + if (!qemu_input_is_absolute() && !absolute_enabled) { + SDL_WarpMouseInWindow(scon->real_window, x, y); + } + } + } else if (gui_grab) { + sdl_hide_cursor(); + } + guest_cursor = on; + guest_x = x, guest_y = y; +} + +static void sdl_mouse_define(DisplayChangeListener *dcl, + QEMUCursor *c) +{ + + if (guest_sprite) { + SDL_FreeCursor(guest_sprite); + } + + if (guest_sprite_surface) { + SDL_FreeSurface(guest_sprite_surface); + } + + guest_sprite_surface = + SDL_CreateRGBSurfaceFrom(c->data, c->width, c->height, 32, c->width * 4, + 0xff0000, 0x00ff00, 0xff, 0xff000000); + + if (!guest_sprite_surface) { + fprintf(stderr, "Failed to make rgb surface from %p\n", c); + return; + } + guest_sprite = SDL_CreateColorCursor(guest_sprite_surface, + c->hot_x, c->hot_y); + if (!guest_sprite) { + fprintf(stderr, "Failed to make color cursor from %p\n", c); + return; + } + if (guest_cursor && + (gui_grab || qemu_input_is_absolute() || absolute_enabled)) { + SDL_SetCursor(guest_sprite); + } +} + +static void sdl_cleanup(void) +{ + if (guest_sprite) { + SDL_FreeCursor(guest_sprite); + } + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} + +static const DisplayChangeListenerOps dcl_2d_ops = { + .dpy_name = "sdl2-2d", + .dpy_gfx_update = sdl2_2d_update, + .dpy_gfx_switch = sdl2_2d_switch, + .dpy_gfx_check_format = sdl2_2d_check_format, + .dpy_refresh = sdl2_2d_refresh, + .dpy_mouse_set = sdl_mouse_warp, + .dpy_cursor_define = sdl_mouse_define, +}; + +#ifdef CONFIG_OPENGL +static const DisplayChangeListenerOps dcl_gl_ops = { + .dpy_name = "sdl2-gl", + .dpy_gfx_update = sdl2_gl_update, + .dpy_gfx_switch = sdl2_gl_switch, + .dpy_gfx_check_format = console_gl_check_format, + .dpy_refresh = sdl2_gl_refresh, + .dpy_mouse_set = sdl_mouse_warp, + .dpy_cursor_define = sdl_mouse_define, +}; +#endif + +void sdl_display_early_init(int opengl) +{ + switch (opengl) { + case -1: /* default */ + case 0: /* off */ + break; + case 1: /* on */ +#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) +{ + int flags; + uint8_t data = 0; + char *filename; + int i; + + if (no_frame) { + gui_noframe = 1; + } + +#ifdef __linux__ + /* on Linux, SDL may use fbcon|directfb|svgalib when run without + * accessible $DISPLAY to open X11 window. This is often the case + * when qemu is run using sudo. But in this case, and when actually + * run in X11 environment, SDL fights with X11 for the video card, + * making current display unavailable, often until reboot. + * So make x11 the default SDL video driver if this variable is unset. + * This is a bit hackish but saves us from bigger problem. + * Maybe it's a good idea to fix this in SDL instead. + */ + setenv("SDL_VIDEODRIVER", "x11", 0); +#endif + + flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; + if (SDL_Init(flags)) { + fprintf(stderr, "Could not initialize SDL(%s) - exiting\n", + SDL_GetError()); + exit(1); + } + SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); + + for (i = 0;; i++) { + QemuConsole *con = qemu_console_lookup_by_index(i); + if (!con) { + break; + } + } + sdl2_num_outputs = i; + 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)) { + sdl2_console[i].hidden = true; + } + sdl2_console[i].idx = i; +#ifdef CONFIG_OPENGL + sdl2_console[i].opengl = display_opengl; + sdl2_console[i].dcl.ops = display_opengl ? &dcl_gl_ops : &dcl_2d_ops; +#else + sdl2_console[i].opengl = 0; + sdl2_console[i].dcl.ops = &dcl_2d_ops; +#endif + sdl2_console[i].dcl.con = con; + register_displaychangelistener(&sdl2_console[i].dcl); + } + + /* Load a 32x32x4 image. White pixels are transparent. */ + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp"); + if (filename) { + SDL_Surface *image = SDL_LoadBMP(filename); + if (image) { + uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255); + SDL_SetColorKey(image, SDL_TRUE, colorkey); + SDL_SetWindowIcon(sdl2_console[0].real_window, image); + } + g_free(filename); + } + + if (full_screen) { + gui_fullscreen = 1; + 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); +} |