[client,sdl] simplify mouse cursor update and restore

This commit is contained in:
akallabeth
2026-01-28 20:35:06 +01:00
parent 7e220eee98
commit a9e3954076
5 changed files with 87 additions and 41 deletions

View File

@@ -956,6 +956,8 @@ bool SdlContext::handleEvent(const SDL_WindowEvent& ev)
switch (ev.type)
{
case SDL_EVENT_WINDOW_MOUSE_ENTER:
return restoreCursor();
case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
if (isConnected())
{
@@ -963,7 +965,7 @@ bool SdlContext::handleEvent(const SDL_WindowEvent& ev)
return false;
if (!drawToWindow(*window))
return false;
if (!sdl_Pointer_Set_Process(this))
if (!restoreCursor())
return false;
}
break;
@@ -972,7 +974,7 @@ bool SdlContext::handleEvent(const SDL_WindowEvent& ev)
return false;
if (!drawToWindow(*window))
return false;
if (!sdl_Pointer_Set_Process(this))
if (!restoreCursor())
return false;
break;
case SDL_EVENT_WINDOW_MOVED:
@@ -1177,8 +1179,6 @@ bool SdlContext::handleEvent(const SDL_Event& ev)
case SDL_EVENT_RENDER_DEVICE_RESET:
case SDL_EVENT_WILL_ENTER_FOREGROUND:
return redraw();
case SDL_EVENT_WINDOW_MOUSE_ENTER:
return sdl_Pointer_Set_Process(this);
default:
return true;
}
@@ -1276,9 +1276,16 @@ rdpClientContext* SdlContext::common() const
return reinterpret_cast<rdpClientContext*>(context());
}
void SdlContext::setCursor(rdpPointer* cursor)
bool SdlContext::setCursor(CursorType type)
{
_cursorType = type;
return restoreCursor();
}
bool SdlContext::setCursor(rdpPointer* cursor)
{
_cursor = cursor;
return setCursor(CURSOR_IMAGE);
}
rdpPointer* SdlContext::cursor() const
@@ -1286,6 +1293,36 @@ rdpPointer* SdlContext::cursor() const
return _cursor;
}
bool SdlContext::restoreCursor()
{
WLog_Print(getWLog(), WLOG_DEBUG, "restore cursor: %d", _cursorType);
switch (_cursorType)
{
case CURSOR_NULL:
if (!SDL_HideCursor())
return false;
setHasCursor(false);
return true;
case CURSOR_DEFAULT:
{
auto def = SDL_GetDefaultCursor();
if (!SDL_SetCursor(def))
return false;
if (!SDL_ShowCursor())
return false;
setHasCursor(true);
return true;
}
case CURSOR_IMAGE:
setHasCursor(true);
return sdl_Pointer_Set_Process(this);
default:
return false;
}
}
void SdlContext::setMonitorIds(const std::vector<SDL_DisplayID>& ids)
{
_monitorIds.clear();

View File

@@ -43,6 +43,13 @@
class SdlContext
{
public:
enum CursorType
{
CURSOR_NULL,
CURSOR_DEFAULT,
CURSOR_IMAGE
};
explicit SdlContext(rdpContext* context);
SdlContext(const SdlContext& other) = delete;
SdlContext(SdlContext&& other) = delete;
@@ -78,15 +85,17 @@ class SdlContext
[[nodiscard]] rdpContext* context() const;
[[nodiscard]] rdpClientContext* common() const;
void setCursor(rdpPointer* cursor);
[[nodiscard]] bool setCursor(CursorType type);
[[nodiscard]] bool setCursor(rdpPointer* cursor);
[[nodiscard]] rdpPointer* cursor() const;
[[nodiscard]] bool restoreCursor();
void setMonitorIds(const std::vector<SDL_DisplayID>& ids);
const std::vector<SDL_DisplayID>& monitorIds() const;
int64_t monitorId(uint32_t index) const;
[[nodiscard]] const std::vector<SDL_DisplayID>& monitorIds() const;
[[nodiscard]] int64_t monitorId(uint32_t index) const;
void push(std::vector<SDL_Rect>&& rects);
std::vector<SDL_Rect> pop();
[[nodiscard]] std::vector<SDL_Rect> pop();
void setHasCursor(bool val);
[[nodiscard]] bool hasCursor() const;
@@ -171,6 +180,7 @@ class SdlContext
std::atomic<bool> _connected = false;
bool _cursor_visible = true;
rdpPointer* _cursor = nullptr;
CursorType _cursorType = CURSOR_NULL;
std::vector<SDL_DisplayID> _monitorIds;
std::mutex _queue_mux;
std::queue<std::vector<SDL_Rect>> _queue;

View File

@@ -198,19 +198,13 @@ static void sdl_term_handler([[maybe_unused]] int signum, [[maybe_unused]] const
throw ErrorMsg{ -1, windowEvent.type, "sdl->minimizeAllWindows" };
break;
case SDL_EVENT_USER_POINTER_NULL:
SDL_HideCursor();
sdl->setCursor(nullptr);
sdl->setHasCursor(false);
if (!sdl->setCursor(SdlContext::CURSOR_NULL))
throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" };
break;
case SDL_EVENT_USER_POINTER_DEFAULT:
{
SDL_Cursor* def = SDL_GetDefaultCursor();
SDL_SetCursor(def);
SDL_ShowCursor();
sdl->setCursor(nullptr);
sdl->setHasCursor(true);
}
break;
if (!sdl->setCursor(SdlContext::CURSOR_DEFAULT))
throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" };
break;
case SDL_EVENT_USER_POINTER_POSITION:
{
const auto x =
@@ -223,9 +217,8 @@ static void sdl_term_handler([[maybe_unused]] int signum, [[maybe_unused]] const
}
break;
case SDL_EVENT_USER_POINTER_SET:
sdl->setCursor(static_cast<rdpPointer*>(windowEvent.user.data1));
if (!sdl_Pointer_Set_Process(sdl))
throw ErrorMsg{ -1, windowEvent.type, "sdl_Pointer_Set_Process" };
if (!sdl->setCursor(static_cast<rdpPointer*>(windowEvent.user.data1)))
throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" };
break;
case SDL_EVENT_USER_QUIT:
default:

View File

@@ -103,7 +103,7 @@ static void sdl_Pointer_Free(rdpContext* context, rdpPointer* pointer)
return sdl_push_user_event(SDL_EVENT_USER_POINTER_SET, pointer);
}
BOOL sdl_Pointer_Set_Process(SdlContext* sdl)
bool sdl_Pointer_Set_Process(SdlContext* sdl)
{
WINPR_ASSERT(sdl);
@@ -111,7 +111,7 @@ BOOL sdl_Pointer_Set_Process(SdlContext* sdl)
auto pointer = sdl->cursor();
auto ptr = reinterpret_cast<sdlPointer*>(pointer);
if (!ptr)
return TRUE;
return true;
rdpGdi* gdi = context->gdi;
WINPR_ASSERT(gdi);
@@ -121,7 +121,7 @@ BOOL sdl_Pointer_Set_Process(SdlContext* sdl)
auto isw = static_cast<float>(pointer->width);
auto ish = static_cast<float>(pointer->height);
SDL_Window* window = SDL_GetMouseFocus();
auto window = SDL_GetMouseFocus();
if (!window)
return sdl_Pointer_SetDefault(context);
@@ -134,9 +134,11 @@ BOOL sdl_Pointer_Set_Process(SdlContext* sdl)
ptr->image =
SDL_CreateSurface(static_cast<int>(pos.w), static_cast<int>(pos.h), sdl->pixelFormat());
if (!ptr->image)
return FALSE;
return false;
if (!SDL_LockSurface(ptr->image))
return false;
SDL_LockSurface(ptr->image);
auto pixels = static_cast<BYTE*>(ptr->image->pixels);
auto data = static_cast<const BYTE*>(ptr->data);
const BOOL rc = freerdp_image_scale(
@@ -145,13 +147,13 @@ BOOL sdl_Pointer_Set_Process(SdlContext* sdl)
gdi->dstFormat, 0, 0, 0, static_cast<UINT32>(isw), static_cast<UINT32>(ish));
SDL_UnlockSurface(ptr->image);
if (!rc)
return FALSE;
return false;
// create a cursor image in 100% display scale to trick SDL into creating the cursor with the
// correct size
auto fw = sdl->getFirstWindow();
if (!fw)
return FALSE;
return false;
const auto hidpi_scale =
sdl->pixelToScreen(fw->id(), SDL_FPoint{ static_cast<float>(ptr->image->w),
@@ -159,20 +161,24 @@ BOOL sdl_Pointer_Set_Process(SdlContext* sdl)
auto normal = SDL_CreateSurface(static_cast<int>(hidpi_scale.x),
static_cast<int>(hidpi_scale.y), ptr->image->format);
assert(normal);
SDL_BlitSurfaceScaled(ptr->image, nullptr, normal, nullptr,
SDL_ScaleMode::SDL_SCALEMODE_LINEAR);
SDL_AddSurfaceAlternateImage(normal, ptr->image);
if (!SDL_BlitSurfaceScaled(ptr->image, nullptr, normal, nullptr,
SDL_ScaleMode::SDL_SCALEMODE_LINEAR))
return false;
if (!SDL_AddSurfaceAlternateImage(normal, ptr->image))
return false;
ptr->cursor = SDL_CreateColorCursor(normal, static_cast<int>(pos.x), static_cast<int>(pos.y));
if (!ptr->cursor)
return FALSE;
return false;
SDL_DestroySurface(normal);
SDL_SetCursor(ptr->cursor);
SDL_ShowCursor();
if (!SDL_SetCursor(ptr->cursor))
return false;
if (!SDL_ShowCursor())
return false;
sdl->setHasCursor(true);
return TRUE;
return true;
}
[[nodiscard]] static BOOL sdl_Pointer_SetNull(rdpContext* context)
@@ -190,7 +196,7 @@ BOOL sdl_Pointer_Set_Process(SdlContext* sdl)
return sdl_push_user_event(SDL_EVENT_USER_POINTER_POSITION, x, y);
}
BOOL sdl_register_pointer(rdpGraphics* graphics)
bool sdl_register_pointer(rdpGraphics* graphics)
{
const rdpPointer pointer = { sizeof(sdlPointer),
sdl_Pointer_New,
@@ -211,5 +217,5 @@ BOOL sdl_register_pointer(rdpGraphics* graphics)
nullptr,
{} };
graphics_register_pointer(graphics, &pointer);
return TRUE;
return true;
}

View File

@@ -25,6 +25,6 @@
#include <freerdp/graphics.h>
[[nodiscard]] BOOL sdl_register_pointer(rdpGraphics* graphics);
[[nodiscard]] bool sdl_register_pointer(rdpGraphics* graphics);
[[nodiscard]] BOOL sdl_Pointer_Set_Process(SdlContext* sdl);
[[nodiscard]] bool sdl_Pointer_Set_Process(SdlContext* sdl);