Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 56 additions & 1 deletion devices/video/display_sdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ class Display::Impl {
SDL_Texture* disp_texture = 0;
SDL_Texture* cursor_texture = 0;
SDL_Rect cursor_rect; // destination rectangle for cursor drawing
bool show_host_cursor = true; // desired SDL host pointer visibility
bool guest_cursor_drawn = false; // guest is drawing its own cursor
bool was_grabbed = false; // last reported grab state
bool manual_grab = false; // grab toggled on with Ctrl+G
int display_w;
int display_h;
double drawable_w;
Expand Down Expand Up @@ -312,6 +316,14 @@ void Display::handle_events(const WindowEvent& wnd_event) {
if (wnd_event.window_id == impl->disp_wnd_id) {
SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, "0");
SDL_SetWindowKeyboardGrab(impl->display_wnd, SDL_TRUE);
// When the window (re)gains focus (e.g. the user clicks it), SDL
// may have dropped the relative mouse grab on focus loss. Re-grab
// it so the guest cursor keeps working; this is the reliable
// re-grab trigger instead of polling every frame.
if (impl->guest_cursor_drawn && !impl->manual_grab && !SDL_GetRelativeMouseMode()) {
SDL_SetRelativeMouseMode(SDL_TRUE);
this->update_window_title();
}
}
break;

Expand Down Expand Up @@ -394,9 +406,11 @@ void Display::toggle_mouse_grab()
{
if (SDL_GetRelativeMouseMode()) {
SDL_SetRelativeMouseMode(SDL_FALSE);
impl->manual_grab = false;
} else {
this->update_mouse_grab(true);
SDL_SetRelativeMouseMode(SDL_TRUE);
impl->manual_grab = true;
}
}

Expand Down Expand Up @@ -434,7 +448,9 @@ void Display::update_window_title()
std::to_string(impl->display_w) + "x" + std::to_string(impl->display_h)
+ " " + std::to_string(int(std::round(impl->renderer_scale_x * 100))) + "%";
if (is_grabbed)
new_window_title += " (🖱 Grabbed)";
new_window_title += " (Grabbed, Ctrl+G to release)";
else if (impl->guest_cursor_drawn)
new_window_title += " (Press Ctrl+G to grab)";

if (new_window_title != old_window_title)
SDL_SetWindowTitle(impl->display_wnd, new_window_title.c_str());
Expand Down Expand Up @@ -466,6 +482,45 @@ void Display::update(std::function<void(uint8_t *dst_buf, int dst_pitch)> conver
SDL_RenderClear(impl->renderer);
SDL_RenderCopy(impl->renderer, impl->disp_texture, NULL, &impl->dest_rect);

bool is_grabbed = SDL_GetRelativeMouseMode();

// The guest draws its own cursor into the framebuffer (hardware cursor).
// When such a cursor session starts, auto-grab the host mouse so the
// pointer cannot leave the window and the guest cursor can reach every
// screen area. When the session ends, release an automatic grab again so
// the user can move the pointer to other windows. A manual grab (Ctrl+G)
// is sticky and is neither grabbed nor released automatically.
if (draw_hw_cursor) {
if (!impl->guest_cursor_drawn && !impl->manual_grab && !is_grabbed) {
this->update_mouse_grab(true);
SDL_SetRelativeMouseMode(SDL_TRUE);
is_grabbed = true;
}
} else {
if (!impl->manual_grab && is_grabbed) {
SDL_SetRelativeMouseMode(SDL_FALSE);
is_grabbed = false;
}
}

// The guest draws its own cursor into the framebuffer. Even without a
// grab, keep the SDL host pointer hidden so the user never sees a second
// cursor that does not track the guest one. When the guest cursor is not
// drawn (e.g. firmware), show the host pointer so the user can aim and
// click.
bool want_host_cursor = !draw_hw_cursor;
if (impl->show_host_cursor != want_host_cursor) {
impl->show_host_cursor = want_host_cursor;
SDL_ShowCursor(want_host_cursor ? SDL_ENABLE : SDL_DISABLE);
}

// Let the window title reflect the current grab/cursor state.
if (is_grabbed != impl->was_grabbed || draw_hw_cursor != impl->guest_cursor_drawn) {
impl->was_grabbed = is_grabbed;
impl->guest_cursor_drawn = draw_hw_cursor;
this->update_window_title();
}

// draw HW cursor if enabled
if (draw_hw_cursor) {
impl->cursor_rect.x = cursor_x * impl->renderer_scale_x + impl->dest_rect.x;
Expand Down
Loading