From 0b6329bdd639f55888ad713d54d082da5e46baf0 Mon Sep 17 00:00:00 2001 From: jpy794 Date: Wed, 18 Dec 2024 20:45:03 +0800 Subject: [PATCH] enable sdl3 hidpi fix wait create windows enable sdl hidpi map mouse event fix smart sizing dynamic resolution in hidpi reset drawing offset when resize is done tirgger a full redraw to sdl window after resizing format & fix warning sdl hidpi cursor workaround clean up format --- client/SDL/SDL3/sdl_disp.cpp | 26 ++++++++++------ client/SDL/SDL3/sdl_disp.hpp | 6 ++++ client/SDL/SDL3/sdl_freerdp.cpp | 55 ++++++++++++++++++++++++++++----- client/SDL/SDL3/sdl_pointer.cpp | 15 ++++++++- client/SDL/SDL3/sdl_window.cpp | 3 +- 5 files changed, 85 insertions(+), 20 deletions(-) diff --git a/client/SDL/SDL3/sdl_disp.cpp b/client/SDL/SDL3/sdl_disp.cpp index f194abb1b..8298c3757 100644 --- a/client/SDL/SDL3/sdl_disp.cpp +++ b/client/SDL/SDL3/sdl_disp.cpp @@ -51,8 +51,7 @@ BOOL sdlDispContext::settings_changed() freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation)) return TRUE; - if (_lastSentDesktopScaleFactor != - freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor)) + if (_lastSentDesktopScaleFactor != _targetDesktopScaleFactor) return TRUE; if (_lastSentDeviceScaleFactor != @@ -75,7 +74,7 @@ BOOL sdlDispContext::update_last_sent() _lastSentWidth = _targetWidth; _lastSentHeight = _targetHeight; _lastSentDesktopOrientation = freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation); - _lastSentDesktopScaleFactor = freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor); + _lastSentDesktopScaleFactor = _targetDesktopScaleFactor; _lastSentDeviceScaleFactor = freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor); // TODO _fullscreen = _sdl->fullscreen; return TRUE; @@ -116,8 +115,7 @@ BOOL sdlDispContext::sendResize() layout.Width = WINPR_ASSERTING_INT_CAST(uint32_t, _targetWidth); layout.Height = WINPR_ASSERTING_INT_CAST(uint32_t, _targetHeight); layout.Orientation = freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation); - layout.DesktopScaleFactor = - freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor); + layout.DesktopScaleFactor = _targetDesktopScaleFactor; layout.DeviceScaleFactor = freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor); layout.PhysicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, _targetWidth); layout.PhysicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, _targetHeight); @@ -356,13 +354,19 @@ BOOL sdlDispContext::handle_window_event(const SDL_WindowEvent* ev) case SDL_EVENT_WINDOW_RESTORED: gdi_send_suppress_output(_sdl->context()->gdi, FALSE); return TRUE; - - case SDL_EVENT_WINDOW_RESIZED: + case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: - _targetWidth = ev->data1; - _targetHeight = ev->data2; + { + if (freerdp_settings_get_bool(_sdl->context()->settings, + FreeRDP_DynamicResolutionUpdate)) + { + const auto& window = _sdl->windows.at(ev->windowID); + const auto factor = SDL_GetWindowDisplayScale(window.window()); + _targetDesktopScaleFactor = static_cast(100 * factor); + } + assert(SDL_GetWindowSizeInPixels(it->second.window(), &_targetWidth, &_targetHeight)); return addTimer(); - + } case SDL_EVENT_WINDOW_MOUSE_LEAVE: WINPR_ASSERT(_sdl); _sdl->input.keyboard_grab(ev->windowID, false); @@ -456,6 +460,8 @@ sdlDispContext::sdlDispContext(SdlContext* sdl) : _sdl(sdl) int32_t, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth)); _lastSentHeight = _targetHeight = WINPR_ASSERTING_INT_CAST( int32_t, freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)); + _lastSentDesktopScaleFactor = _targetDesktopScaleFactor = + freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor); PubSub_SubscribeActivated(pubSub, sdlDispContext::OnActivated); PubSub_SubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset); addTimer(); diff --git a/client/SDL/SDL3/sdl_disp.hpp b/client/SDL/SDL3/sdl_disp.hpp index a8288a368..5a0f7c321 100644 --- a/client/SDL/SDL3/sdl_disp.hpp +++ b/client/SDL/SDL3/sdl_disp.hpp @@ -45,6 +45,11 @@ class sdlDispContext BOOL handle_window_event(const SDL_WindowEvent* ev); + [[nodiscard]] UINT32 scale_factor() const + { + return _lastSentDesktopScaleFactor; + } + private: UINT DisplayControlCaps(UINT32 maxNumMonitors, UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB); @@ -75,6 +80,7 @@ class sdlDispContext UINT16 _lastSentDesktopOrientation = 0; UINT32 _lastSentDesktopScaleFactor = 0; UINT32 _lastSentDeviceScaleFactor = 0; + UINT32 _targetDesktopScaleFactor = 0; SDL_TimerID _timer = 0; unsigned _timer_retries = 0; }; diff --git a/client/SDL/SDL3/sdl_freerdp.cpp b/client/SDL/SDL3/sdl_freerdp.cpp index 73d2818fa..f34863975 100644 --- a/client/SDL/SDL3/sdl_freerdp.cpp +++ b/client/SDL/SDL3/sdl_freerdp.cpp @@ -403,6 +403,8 @@ static BOOL sdl_draw_to_window(SdlContext* sdl, SdlWindow& window, if (!freerdp_settings_get_bool(context->settings, FreeRDP_SmartSizing)) { + window.setOffsetX(0); + window.setOffsetY(0); if (gdi->width < size.w) { window.setOffsetX((size.w - gdi->width) / 2); @@ -775,12 +777,13 @@ static BOOL sdl_create_windows(SdlContext* sdl) static BOOL sdl_wait_create_windows(SdlContext* sdl) { - std::lock_guard lock(sdl->critical); + std::unique_lock lock(sdl->critical); sdl->windows_created.clear(); if (!sdl_push_user_event(SDL_EVENT_USER_CREATE_WINDOWS, sdl)) return FALSE; + lock.unlock(); - HANDLE handles[] = { sdl->initialized.handle(), freerdp_abort_event(sdl->context()) }; + HANDLE handles[] = { sdl->windows_created.handle(), freerdp_abort_event(sdl->context()) }; const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE); switch (rc) @@ -864,6 +867,16 @@ static int sdl_run(SdlContext* sdl) } } + auto point2pix = [](Uint32 win_id, float& x, float& y) + { + auto win = SDL_GetWindowFromID(win_id); + assert(win); + auto scale = SDL_GetWindowDisplayScale(win); + assert(scale); + x *= scale; + y *= scale; + }; + switch (windowEvent.type) { case SDL_EVENT_QUIT: @@ -882,15 +895,18 @@ static int sdl_run(SdlContext* sdl) break; // TODO: Switch keyboard layout case SDL_EVENT_MOUSE_MOTION: { - const SDL_MouseMotionEvent* ev = &windowEvent.motion; - sdl_handle_mouse_motion(sdl, ev); + SDL_MouseMotionEvent& ev = windowEvent.motion; + point2pix(ev.windowID, ev.x, ev.y); + point2pix(ev.windowID, ev.xrel, ev.yrel); + sdl_handle_mouse_motion(sdl, &ev); } break; case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { - const SDL_MouseButtonEvent* ev = &windowEvent.button; - sdl_handle_mouse_button(sdl, ev); + SDL_MouseButtonEvent& ev = windowEvent.button; + point2pix(ev.windowID, ev.x, ev.y); + sdl_handle_mouse_button(sdl, &ev); } break; case SDL_EVENT_MOUSE_WHEEL: @@ -1017,6 +1033,7 @@ static int sdl_run(SdlContext* sdl) } break; case SDL_EVENT_USER_POINTER_SET: + windowEvent.user.code = static_cast(sdl->disp.scale_factor()); sdl_Pointer_Set_Process(&windowEvent.user); break; case SDL_EVENT_CLIPBOARD_UPDATE: @@ -1041,10 +1058,32 @@ static int sdl_run(SdlContext* sdl) switch (ev->type) { - case SDL_EVENT_WINDOW_RESIZED: + case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: + { + if (freerdp_settings_get_bool(sdl->context()->settings, + FreeRDP_DynamicResolutionUpdate)) + { + break; + } + auto win = window->second.window(); + int w_pix{}; + int h_pix{}; + assert(SDL_GetWindowSizeInPixels(win, &w_pix, &h_pix)); + auto scale = SDL_GetWindowDisplayScale(win); + assert(scale != 0); + auto w_gdi = sdl->context()->gdi->width; + auto h_gdi = sdl->context()->gdi->height; + auto pix2point = [=](int pix) + { return static_cast(static_cast(pix) / scale); }; + if (w_pix != w_gdi || h_pix != h_gdi) + { + SDL_SetWindowSize(win, pix2point(w_gdi), pix2point(h_gdi)); + } + } + break; case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: window->second.fill(); - window->second.updateSurface(); + sdl_draw_to_window(sdl, window->second); break; case SDL_EVENT_WINDOW_MOVED: { diff --git a/client/SDL/SDL3/sdl_pointer.cpp b/client/SDL/SDL3/sdl_pointer.cpp index 5c3aca1e0..695ebbaaf 100644 --- a/client/SDL/SDL3/sdl_pointer.cpp +++ b/client/SDL/SDL3/sdl_pointer.cpp @@ -158,10 +158,23 @@ BOOL sdl_Pointer_Set_Process(SDL_UserEvent* uptr) if (!rc) return FALSE; - ptr->cursor = SDL_CreateColorCursor(ptr->image, x, y); + // create a cursor image in 100% display scale to trick SDL into creating the cursor with the + // correct size + const auto hidpi_scale = static_cast(uptr->code) / 100; + auto normal = SDL_CreateSurface( + static_cast(static_cast(ptr->image->w) / hidpi_scale), + static_cast(static_cast(ptr->image->h) / hidpi_scale), ptr->image->format); + assert(normal); + SDL_BlitSurfaceScaled(ptr->image, nullptr, normal, nullptr, + SDL_ScaleMode::SDL_SCALEMODE_NEAREST); + SDL_AddSurfaceAlternateImage(normal, ptr->image); + + ptr->cursor = SDL_CreateColorCursor(normal, x, y); if (!ptr->cursor) return FALSE; + SDL_DestroySurface(normal); + SDL_SetCursor(ptr->cursor); SDL_ShowCursor(); return TRUE; diff --git a/client/SDL/SDL3/sdl_window.cpp b/client/SDL/SDL3/sdl_window.cpp index 64b12fa02..eefc7e558 100644 --- a/client/SDL/SDL3/sdl_window.cpp +++ b/client/SDL/SDL3/sdl_window.cpp @@ -29,6 +29,7 @@ SdlWindow::SdlWindow(const std::string& title, Sint32 startupX, Sint32 startupY, SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, startupY); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, height); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true); // SDL_SetProperty(props, SDL_PROP_WINDOW_CREATE_FL); _window = SDL_CreateWindowWithProperties(props); SDL_DestroyProperties(props); @@ -65,7 +66,7 @@ SDL_Rect SdlWindow::rect() const if (_window) { SDL_GetWindowPosition(_window, &rect.x, &rect.y); - SDL_GetWindowSize(_window, &rect.w, &rect.h); + SDL_GetWindowSizeInPixels(_window, &rect.w, &rect.h); } return rect; }