19#include "sdl_context.hpp"
20#include "sdl_config.hpp"
21#include "sdl_channels.hpp"
22#include "sdl_monitor.hpp"
23#include "sdl_pointer.hpp"
24#include "sdl_touch.hpp"
26#include <sdl_common_utils.hpp>
27#include <scoped_guard.hpp>
29#include "dialogs/sdl_dialogs.hpp"
31#if defined(WITH_WEBVIEW)
32#include <aad/sdl_webview.hpp>
36 : _context(context), _log(WLog_Get(CLIENT_TAG(
"SDL"))), _rdpThreadRunning(false),
37 _primary(nullptr, SDL_DestroySurface), _disp(this), _input(this), _clip(this), _dialog(_log)
39 WINPR_ASSERT(context);
42 auto instance = _context->instance;
43 WINPR_ASSERT(instance);
45 instance->PreConnect = preConnect;
46 instance->PostConnect = postConnect;
47 instance->PostDisconnect = postDisconnect;
48 instance->PostFinalDisconnect = postFinalDisconnect;
49 instance->AuthenticateEx = sdl_authenticate_ex;
50 instance->VerifyCertificateEx = sdl_verify_certificate_ex;
51 instance->VerifyChangedCertificateEx = sdl_verify_changed_certificate_ex;
52 instance->LogonErrorInfo = sdl_logon_error_info;
53 instance->PresentGatewayMessage = sdl_present_gateway_message;
54 instance->ChooseSmartcard = sdl_choose_smartcard;
55 instance->RetryDialog = sdl_retry_dialog;
58 instance->GetAccessToken = sdl_webview_get_access_token;
60 instance->GetAccessToken = client_cli_get_access_token;
65void SdlContext::setHasCursor(
bool val)
67 this->_cursor_visible = val;
70bool SdlContext::hasCursor()
const
72 return _cursor_visible;
75void SdlContext::setMetadata()
78 if (!wmclass || (strlen(wmclass) == 0))
79 wmclass = SDL_CLIENT_UUID;
81 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING, wmclass);
82 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING, SDL_CLIENT_NAME);
83 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_VERSION_STRING, SDL_CLIENT_VERSION);
84 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_CREATOR_STRING, SDL_CLIENT_VENDOR);
85 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_COPYRIGHT_STRING, SDL_CLIENT_COPYRIGHT);
86 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_URL_STRING, SDL_CLIENT_URL);
87 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_TYPE_STRING, SDL_CLIENT_TYPE);
90int SdlContext::start()
92 _thread = std::thread(rdpThreadRun,
this);
100 HANDLE
event = freerdp_abort_event(context());
101 if (!SetEvent(event))
108void SdlContext::cleanup()
110 std::unique_lock lock(_critical);
116bool SdlContext::shallAbort(
bool ignoreDialogs)
118 std::unique_lock lock(_critical);
119 if (freerdp_shall_disconnect_context(context()))
123 if (_rdpThreadRunning)
125 return !getDialog().isRunning();
132BOOL SdlContext::preConnect(freerdp* instance)
134 WINPR_ASSERT(instance);
135 WINPR_ASSERT(instance->context);
137 auto sdl = get_context(instance->context);
139 auto settings = instance->context->settings;
140 WINPR_ASSERT(settings);
155 PubSub_SubscribeChannelConnected(instance->context->pubSub, sdl_OnChannelConnectedEventHandler);
156 PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
157 sdl_OnChannelDisconnectedEventHandler);
162 UINT32 maxHeight = 0;
164 if (!sdl_detect_monitors(sdl, &maxWidth, &maxHeight))
167 if ((maxWidth != 0) && (maxHeight != 0) &&
170 WLog_Print(sdl->getWLog(), WLOG_INFO,
"Update size to %ux%u", maxWidth, maxHeight);
182 WLog_Print(sdl->getWLog(), WLOG_INFO,
183 "auth-only, but no password set. Please provide one.");
190 WLog_Print(sdl->getWLog(), WLOG_INFO,
"Authentication only. Don't connect SDL.");
193 if (!sdl->getInputChannelContext().initialize())
208BOOL SdlContext::postConnect(freerdp* instance)
210 WINPR_ASSERT(instance);
212 auto context = instance->context;
213 WINPR_ASSERT(context);
215 auto sdl = get_context(context);
219 const auto driver = SDL_GetCurrentVideoDriver();
223 if (strcmp(driver,
"wayland") == 0)
225 else if (strcmp(driver,
"x11") == 0)
227 auto env = SDL_GetEnvironment();
228 auto xdg = SDL_GetEnvironmentVariable(env,
"XDG_SESSION_TYPE");
229 auto qpa = SDL_GetEnvironmentVariable(env,
"QT_QPA_PLATFORM");
230 if (xdg && (strcmp(xdg,
"wayland") == 0))
232 else if (qpa && (strcmp(qpa,
"wayland") == 0))
239 const auto name = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING);
241 WLog_Print(sdl->getWLog(), WLOG_WARN,
242 "%s is affected by wayland bug "
243 "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/179",
246 sdl->getWLog(), WLOG_WARN,
247 "you will not be able to properly use all monitors for FreeRDP unless this is "
248 "resolved and the SDL library you are using supports this.");
249 WLog_Print(sdl->getWLog(), WLOG_WARN,
250 "For the time being run %s from an X11 session or only use single monitor "
257 sdl->getDialog().show(
false);
264 WLog_Print(sdl->getWLog(), WLOG_INFO,
265 "auth-only, but no password set. Please provide one.");
269 WLog_Print(sdl->getWLog(), WLOG_INFO,
"Authentication only. Don't connect to X.");
273 if (!sdl->waitForWindowsCreated())
276 sdl->_sdlPixelFormat = SDL_PIXELFORMAT_BGRA32;
277 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
280 if (!sdl->createPrimary())
283 if (!sdl_register_pointer(instance->context->graphics))
286 WINPR_ASSERT(context->update);
288 context->update->BeginPaint = beginPaint;
289 context->update->EndPaint = endPaint;
290 context->update->PlaySound = playSound;
291 context->update->DesktopResize = desktopResize;
292 context->update->SetKeyboardIndicators = sdlInput::keyboard_set_indicators;
293 context->update->SetKeyboardImeStatus = sdlInput::keyboard_set_ime_status;
295 if (!sdl->setResizeable(
false))
300 sdl->setConnected(
true);
307void SdlContext::postDisconnect(freerdp* instance)
312 if (!instance->context)
315 auto sdl = get_context(instance->context);
316 sdl->setConnected(
false);
321void SdlContext::postFinalDisconnect(freerdp* instance)
326 if (!instance->context)
329 PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
330 sdl_OnChannelConnectedEventHandler);
331 PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
332 sdl_OnChannelDisconnectedEventHandler);
336bool SdlContext::createPrimary()
338 auto gdi = context()->gdi;
341 _primary = SDLSurfacePtr(
342 SDL_CreateSurfaceFrom(
static_cast<int>(gdi->width),
static_cast<int>(gdi->height),
343 pixelFormat(), gdi->primary_buffer,
static_cast<int>(gdi->stride)),
348 SDL_SetSurfaceBlendMode(_primary.get(), SDL_BLENDMODE_NONE);
349 SDL_Rect surfaceRect = { 0, 0, gdi->width, gdi->height };
350 SDL_FillSurfaceRect(_primary.get(), &surfaceRect,
351 SDL_MapSurfaceRGBA(_primary.get(), 0, 0, 0, 0xff));
356bool SdlContext::createWindows()
358 auto settings = context()->settings;
359 const auto& title = windowTitle();
361 ScopeGuard guard1([&]() { _windowsCreatedEvent.set(); });
367 for (UINT32 x = 0; x < windowCount; x++)
369 auto id = monitorId(x);
374 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x));
376 originX = std::min<Sint32>(monitor->x, originX);
377 originY = std::min<Sint32>(monitor->y, originY);
380 for (UINT32 x = 0; x < windowCount; x++)
382 auto id = monitorId(x);
387 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x));
389 auto w = WINPR_ASSERTING_INT_CAST(Uint32, monitor->width);
390 auto h = WINPR_ASSERTING_INT_CAST(Uint32, monitor->height);
398 Uint32 flags = SDL_WINDOW_HIGH_PIXEL_DENSITY;
403 flags |= SDL_WINDOW_FULLSCREEN;
408 flags |= SDL_WINDOW_BORDERLESS;
412 flags |= SDL_WINDOW_BORDERLESS;
414 auto did = WINPR_ASSERTING_INT_CAST(SDL_DisplayID,
id);
415 auto window = SdlWindow::create(did, title, flags, w, h);
419 window.setOffsetX(originX - monitor->x);
420 window.setOffsetY(originY - monitor->y);
423 _windows.insert({ window.id(), std::move(window) });
429bool SdlContext::updateWindowList()
431 std::vector<rdpMonitor> list;
432 list.reserve(_windows.size());
433 for (
const auto& win : _windows)
434 list.push_back(win.second.monitor(_windows.size() == 1));
440std::string SdlContext::windowTitle()
const
442 const char* prefix =
"FreeRDP:";
450 const auto addPort = (port != 3389);
452 std::stringstream ss;
453 ss << prefix <<
" " << name;
461bool SdlContext::waitForWindowsCreated()
464 std::unique_lock<CriticalSection> lock(_critical);
465 _windowsCreatedEvent.clear();
466 if (!sdl_push_user_event(SDL_EVENT_USER_CREATE_WINDOWS,
this))
470 HANDLE handles[] = { _windowsCreatedEvent.handle(), freerdp_abort_event(context()) };
472 const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
486BOOL SdlContext::endPaint(rdpContext* context)
488 auto sdl = get_context(context);
491 auto gdi = context->gdi;
493 WINPR_ASSERT(gdi->primary);
495 HGDI_DC hdc = gdi->primary->hdc;
501 WINPR_ASSERT(hwnd->invalid || (hwnd->ninvalid == 0));
503 if (hwnd->invalid->null)
506 WINPR_ASSERT(hwnd->invalid);
507 if (gdi->suppressOutput || hwnd->invalid->null)
510 const INT32 ninvalid = hwnd->ninvalid;
511 const GDI_RGN* cinvalid = hwnd->cinvalid;
516 std::vector<SDL_Rect> rects;
517 for (INT32 x = 0; x < ninvalid; x++)
519 auto& rgn = cinvalid[x];
520 rects.push_back({ rgn.x, rgn.y, rgn.w, rgn.h });
523 sdl->push(std::move(rects));
524 return sdl_push_user_event(SDL_EVENT_USER_UPDATE);
527void SdlContext::sdl_client_cleanup(
int exit_code,
const std::string& error_msg)
529 rdpSettings* settings = context()->settings;
530 WINPR_ASSERT(settings);
532 _rdpThreadRunning =
false;
533 bool showError =
false;
535 WLog_Print(getWLog(), WLOG_INFO,
"Authentication only, exit status %s [%" PRId32
"]",
536 sdl::error::exitCodeToTag(exit_code), exit_code);
541 case sdl::error::SUCCESS:
542 case sdl::error::DISCONNECT:
543 case sdl::error::LOGOFF:
544 case sdl::error::DISCONNECT_BY_USER:
545 case sdl::error::CONNECT_CANCELLED:
549 getDialog().showError(error_msg);
556 getDialog().show(
false);
558 _exitCode = exit_code;
559 std::ignore = sdl_push_user_event(SDL_EVENT_USER_QUIT);
563int SdlContext::sdl_client_thread_connect(std::string& error_msg)
565 auto instance = context()->instance;
566 WINPR_ASSERT(instance);
568 _rdpThreadRunning =
true;
569 BOOL rc = freerdp_connect(instance);
571 rdpSettings* settings = context()->settings;
572 WINPR_ASSERT(settings);
574 int exit_code = sdl::error::SUCCESS;
577 UINT32 error = freerdp_get_last_error(context());
578 exit_code = sdl::error::errorToExitCode(error);
583 DWORD code = freerdp_get_last_error(context());
584 freerdp_abort_connect_context(context());
585 WLog_Print(getWLog(), WLOG_ERROR,
"Authentication only, %s [0x%08" PRIx32
"] %s",
586 freerdp_get_last_error_name(code), code, freerdp_get_last_error_string(code));
592 DWORD code = freerdp_error_info(instance);
593 if (exit_code == sdl::error::SUCCESS)
597 exit_code = error_info_to_error(&code, &msg, &len);
603 auto last = freerdp_get_last_error(context());
604 if (error_msg.empty())
608 winpr_asprintf(&msg, &len,
"%s [0x%08" PRIx32
"]\n%s",
609 freerdp_get_last_error_name(last), last,
610 freerdp_get_last_error_string(last));
616 if (exit_code == sdl::error::SUCCESS)
618 if (last == FREERDP_ERROR_AUTHENTICATION_FAILED)
619 exit_code = sdl::error::AUTH_FAILURE;
620 else if (code == ERRINFO_SUCCESS)
621 exit_code = sdl::error::CONN_FAILED;
624 getDialog().show(
false);
630int SdlContext::sdl_client_thread_run(std::string& error_msg)
632 auto instance = context()->instance;
633 WINPR_ASSERT(instance);
635 int exit_code = sdl::error::SUCCESS;
636 while (!freerdp_shall_disconnect_context(context()))
638 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {};
644 if (freerdp_focus_required(instance))
646 auto ctx = get_context(context());
649 auto& input = ctx->getInputChannelContext();
650 if (!input.keyboard_focus_in())
652 if (!input.keyboard_focus_in())
656 const DWORD nCount = freerdp_get_event_handles(context(), handles, ARRAYSIZE(handles));
660 WLog_Print(getWLog(), WLOG_ERROR,
"freerdp_get_event_handles failed");
664 const DWORD status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
666 if (status == WAIT_FAILED)
668 WLog_Print(getWLog(), WLOG_ERROR,
"WaitForMultipleObjects WAIT_FAILED");
672 if (!freerdp_check_event_handles(context()))
674 if (client_auto_reconnect(instance))
677 getDialog().show(
false);
686 if (freerdp_error_info(instance) == 0)
687 exit_code = sdl::error::CONN_FAILED;
690 if (freerdp_get_last_error(context()) == FREERDP_ERROR_SUCCESS)
691 WLog_Print(getWLog(), WLOG_ERROR,
"WaitForMultipleObjects failed with %" PRIu32
"",
693 if (freerdp_get_last_error(context()) == FREERDP_ERROR_SUCCESS)
694 WLog_Print(getWLog(), WLOG_ERROR,
"Failed to check FreeRDP event handles");
699 if (exit_code == sdl::error::SUCCESS)
703 char* emsg =
nullptr;
705 exit_code = error_info_to_error(&code, &emsg, &elen);
711 if ((code == ERRINFO_LOGOFF_BY_USER) &&
712 (freerdp_get_disconnect_ultimatum(context()) == Disconnect_Ultimatum_user_requested))
714 const char* msg =
"Error info says user did not initiate but disconnect ultimatum says "
715 "they did; treat this as a user logoff";
717 char* emsg =
nullptr;
719 winpr_asprintf(&emsg, &elen,
"%s", msg);
725 WLog_Print(getWLog(), WLOG_INFO,
"%s", msg);
726 exit_code = sdl::error::LOGOFF;
730 freerdp_disconnect(instance);
738DWORD SdlContext::rdpThreadRun(
SdlContext* sdl)
742 std::string error_msg;
743 int exit_code = sdl->sdl_client_thread_connect(error_msg);
744 if (exit_code == sdl::error::SUCCESS)
745 exit_code = sdl->sdl_client_thread_run(error_msg);
746 sdl->sdl_client_cleanup(exit_code, error_msg);
748 return static_cast<DWORD
>(exit_code);
751int SdlContext::error_info_to_error(DWORD* pcode,
char** msg,
size_t* len)
const
753 const DWORD code = freerdp_error_info(context()->instance);
754 const char* name = freerdp_get_error_info_name(code);
755 const char* str = freerdp_get_error_info_string(code);
756 const int exit_code = sdl::error::errorToExitCode(code);
758 winpr_asprintf(msg, len,
"Terminate with %s due to ERROR_INFO %s [0x%08" PRIx32
"]: %s",
759 sdl::error::errorToExitCodeTag(code), name, code, str);
760 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"%s", *msg);
766void SdlContext::applyMonitorOffset(SDL_WindowID window,
float& x,
float& y)
const
771 auto w = getWindowForId(window);
772 x -=
static_cast<float>(w->offsetX());
773 y -=
static_cast<float>(w->offsetY());
776bool SdlContext::drawToWindow(
SdlWindow& window,
const std::vector<SDL_Rect>& rects)
781 auto gdi = context()->gdi;
784 auto size = window.rect();
786 std::unique_lock lock(_critical);
787 auto surface = _primary.get();
790 window.setOffsetX(0);
791 window.setOffsetY(0);
792 if (gdi->width < size.w)
794 window.setOffsetX((size.w - gdi->width) / 2);
796 if (gdi->height < size.h)
798 window.setOffsetY((size.h - gdi->height) / 2);
801 _localScale = {
static_cast<float>(size.w) /
static_cast<float>(gdi->width),
802 static_cast<float>(size.h) /
static_cast<float>(gdi->height) };
803 if (!window.drawScaledRects(surface, _localScale, rects))
808 SDL_Point offset{ 0, 0 };
810 offset = { window.offsetX(), window.offsetY() };
811 if (!window.drawRects(surface, offset, rects))
815 window.updateSurface();
819bool SdlContext::minimizeAllWindows()
821 for (
auto& w : _windows)
826int SdlContext::exitCode()
const
831SDL_PixelFormat SdlContext::pixelFormat()
const
833 return _sdlPixelFormat;
836bool SdlContext::addDisplayWindow(SDL_DisplayID
id)
839 SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS;
840 auto title = sdl::utils::windowTitle(context()->settings);
841 auto w = SdlWindow::create(
id, title, flags);
842 _windows.emplace(w.id(), std::move(w));
846bool SdlContext::removeDisplay(SDL_DisplayID
id)
848 for (
auto& w : _windows)
850 if (w.second.displayIndex() ==
id)
851 _windows.erase(w.first);
856const SdlWindow* SdlContext::getWindowForId(SDL_WindowID
id)
const
858 auto it = _windows.find(
id);
859 if (it == _windows.end())
864SdlWindow* SdlContext::getWindowForId(SDL_WindowID
id)
866 auto it = _windows.find(
id);
867 if (it == _windows.end())
874 if (_windows.empty())
876 return &_windows.begin()->second;
884sdlInput& SdlContext::getInputChannelContext()
889sdlClip& SdlContext::getClipboardChannelContext()
899wLog* SdlContext::getWLog()
904bool SdlContext::moveMouseTo(
const SDL_FPoint& pos)
906 auto window = SDL_GetMouseFocus();
910 const auto id = SDL_GetWindowID(window);
911 const auto spos = pixelToScreen(
id, pos);
912 SDL_WarpMouseInWindow(window, spos.x, spos.y);
916bool SdlContext::handleEvent(
const SDL_MouseMotionEvent& ev)
920 if (!eventToPixelCoordinates(ev.windowID, copy))
922 removeLocalScaling(copy.motion.x, copy.motion.y);
923 removeLocalScaling(copy.motion.xrel, copy.motion.yrel);
924 applyMonitorOffset(copy.motion.windowID, copy.motion.x, copy.motion.y);
926 return SdlTouch::handleEvent(
this, copy.motion);
929bool SdlContext::handleEvent(
const SDL_MouseWheelEvent& ev)
933 if (!eventToPixelCoordinates(ev.windowID, copy))
935 removeLocalScaling(copy.wheel.mouse_x, copy.wheel.mouse_y);
936 return SdlTouch::handleEvent(
this, copy.wheel);
939bool SdlContext::handleEvent(
const SDL_WindowEvent& ev)
941 if (!getDisplayChannelContext().handleEvent(ev))
944 auto window = getWindowForId(ev.windowID);
949 const auto& r = window->rect();
950 const auto& b = window->bounds();
951 const auto& scale = window->scale();
952 const auto& orientation = window->orientation();
953 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
954 "%s: [%u] %dx%d-%dx%d {%dx%d-%dx%d}{scale=%f,orientation=%s}",
955 sdl::utils::toString(ev.type).c_str(), ev.windowID, r.x, r.y, r.w, r.h, b.x,
956 b.y, b.w, b.h,
static_cast<double>(scale),
957 sdl::utils::toString(orientation).c_str());
962 case SDL_EVENT_WINDOW_MOUSE_ENTER:
963 return restoreCursor();
964 case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
969 if (!drawToWindow(*window))
971 if (!restoreCursor())
975 case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
978 if (!drawToWindow(*window))
980 if (!restoreCursor())
983 case SDL_EVENT_WINDOW_MOVED:
985 auto r = window->rect();
986 auto id = window->id();
987 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"%u: %dx%d-%dx%d",
id, r.x, r.y, r.w, r.h);
990 case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
992 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"Window closed, terminating RDP session...");
993 freerdp_abort_connect_context(context());
1002bool SdlContext::handleEvent(
const SDL_DisplayEvent& ev)
1004 if (!getDisplayChannelContext().handleEvent(ev))
1009 case SDL_EVENT_DISPLAY_REMOVED:
1014 if (!SDL_GetDisplayBounds(ev.displayID, &r))
1016 const auto name = SDL_GetDisplayName(ev.displayID);
1019 const auto orientation = SDL_GetCurrentDisplayOrientation(ev.displayID);
1020 const auto scale = SDL_GetDisplayContentScale(ev.displayID);
1021 const auto mode = SDL_GetCurrentDisplayMode(ev.displayID);
1025 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
1026 "%s: [%u, %s] %dx%d-%dx%d {orientation=%s, scale=%f}%s",
1027 sdl::utils::toString(ev.type).c_str(), ev.displayID, name, r.x, r.y, r.w,
1028 r.h, sdl::utils::toString(orientation).c_str(),
static_cast<double>(scale),
1029 sdl::utils::toString(mode).c_str());
1036bool SdlContext::handleEvent(
const SDL_MouseButtonEvent& ev)
1038 SDL_Event copy = {};
1040 if (!eventToPixelCoordinates(ev.windowID, copy))
1042 removeLocalScaling(copy.button.x, copy.button.y);
1043 applyMonitorOffset(copy.button.windowID, copy.button.x, copy.button.y);
1044 return SdlTouch::handleEvent(
this, copy.button);
1047bool SdlContext::handleEvent(
const SDL_TouchFingerEvent& ev)
1051 if (!eventToPixelCoordinates(ev.windowID, copy))
1053 removeLocalScaling(copy.tfinger.dx, copy.tfinger.dy);
1054 removeLocalScaling(copy.tfinger.x, copy.tfinger.y);
1055 applyMonitorOffset(copy.tfinger.windowID, copy.tfinger.x, copy.tfinger.y);
1056 return SdlTouch::handleEvent(
this, copy.tfinger);
1059bool SdlContext::eventToPixelCoordinates(SDL_WindowID
id, SDL_Event& ev)
1061 auto w = getWindowForId(
id);
1066 auto renderer = SDL_GetRenderer(w->window());
1069 return SDL_ConvertEventToRenderCoordinates(renderer, &ev);
1072SDL_FPoint SdlContext::applyLocalScaling(
const SDL_FPoint& val)
const
1078 rval.x *= _localScale.x;
1079 rval.y *= _localScale.y;
1083void SdlContext::removeLocalScaling(
float& x,
float& y)
const
1091SDL_FPoint SdlContext::screenToPixel(SDL_WindowID
id,
const SDL_FPoint& pos)
1093 auto w = getWindowForId(
id);
1098 auto renderer = SDL_GetRenderer(w->window());
1103 if (!SDL_RenderCoordinatesFromWindow(renderer, pos.x, pos.y, &rpos.x, &rpos.y))
1105 removeLocalScaling(rpos.x, rpos.y);
1109SDL_FPoint SdlContext::pixelToScreen(SDL_WindowID
id,
const SDL_FPoint& pos)
1111 auto w = getWindowForId(
id);
1116 auto renderer = SDL_GetRenderer(w->window());
1121 if (!SDL_RenderCoordinatesToWindow(renderer, pos.x, pos.y, &rpos.x, &rpos.y))
1123 return applyLocalScaling(rpos);
1126SDL_FRect SdlContext::pixelToScreen(SDL_WindowID
id,
const SDL_FRect& pos)
1128 const auto fpos = pixelToScreen(
id, SDL_FPoint{ pos.x, pos.y });
1129 const auto size = pixelToScreen(
id, SDL_FPoint{ pos.w, pos.h });
1130 return { fpos.x, fpos.y, size.x, size.y };
1133bool SdlContext::handleEvent(
const SDL_Event& ev)
1135 if ((ev.type >= SDL_EVENT_DISPLAY_FIRST) && (ev.type <= SDL_EVENT_DISPLAY_LAST))
1137 const auto& dev = ev.display;
1138 return handleEvent(dev);
1140 if ((ev.type >= SDL_EVENT_WINDOW_FIRST) && (ev.type <= SDL_EVENT_WINDOW_LAST))
1142 const auto& wev = ev.window;
1143 return handleEvent(wev);
1147 case SDL_EVENT_FINGER_DOWN:
1148 case SDL_EVENT_FINGER_UP:
1149 case SDL_EVENT_FINGER_MOTION:
1151 const auto& cev = ev.tfinger;
1152 return handleEvent(cev);
1154 case SDL_EVENT_MOUSE_MOTION:
1156 const auto& cev = ev.motion;
1157 return handleEvent(cev);
1159 case SDL_EVENT_MOUSE_BUTTON_DOWN:
1160 case SDL_EVENT_MOUSE_BUTTON_UP:
1162 const auto& cev = ev.button;
1163 return handleEvent(cev);
1165 case SDL_EVENT_MOUSE_WHEEL:
1167 const auto& cev = ev.wheel;
1168 return handleEvent(cev);
1170 case SDL_EVENT_CLIPBOARD_UPDATE:
1172 const auto& cev = ev.clipboard;
1173 return getClipboardChannelContext().handleEvent(cev);
1175 case SDL_EVENT_KEY_DOWN:
1176 case SDL_EVENT_KEY_UP:
1178 const auto& cev = ev.key;
1179 return getInputChannelContext().handleEvent(cev);
1181 case SDL_EVENT_RENDER_TARGETS_RESET:
1182 case SDL_EVENT_RENDER_DEVICE_RESET:
1183 case SDL_EVENT_WILL_ENTER_FOREGROUND:
1190bool SdlContext::drawToWindows(
const std::vector<SDL_Rect>& rects)
1192 for (
auto& window : _windows)
1194 if (!drawToWindow(window.second, rects))
1201BOOL SdlContext::desktopResize(rdpContext* context)
1203 rdpGdi* gdi =
nullptr;
1204 rdpSettings* settings =
nullptr;
1205 auto sdl = get_context(context);
1208 WINPR_ASSERT(context);
1210 settings = context->settings;
1211 WINPR_ASSERT(settings);
1213 std::unique_lock lock(sdl->_critical);
1218 return sdl->createPrimary();
1222BOOL SdlContext::playSound(rdpContext* context,
const PLAY_SOUND_UPDATE* play_sound)
1225 WINPR_UNUSED(context);
1226 WINPR_UNUSED(play_sound);
1232BOOL SdlContext::beginPaint(rdpContext* context)
1234 auto gdi = context->gdi;
1236 WINPR_ASSERT(gdi->primary);
1238 HGDI_DC hdc = gdi->primary->hdc;
1244 WINPR_ASSERT(hwnd->invalid);
1245 hwnd->invalid->null = TRUE;
1251bool SdlContext::redraw(
bool suppress)
const
1256 auto gdi = context()->gdi;
1258 return gdi_send_suppress_output(gdi, suppress);
1261void SdlContext::setConnected(
bool val)
1266bool SdlContext::isConnected()
const
1271rdpContext* SdlContext::context()
const
1273 WINPR_ASSERT(_context);
1277rdpClientContext* SdlContext::common()
const
1279 return reinterpret_cast<rdpClientContext*
>(context());
1282bool SdlContext::setCursor(CursorType type)
1285 return restoreCursor();
1288bool SdlContext::setCursor(rdpPointer* cursor)
1291 return setCursor(CURSOR_IMAGE);
1294rdpPointer* SdlContext::cursor()
const
1299bool SdlContext::restoreCursor()
1301 WLog_Print(getWLog(), WLOG_DEBUG,
"restore cursor: %d", _cursorType);
1302 switch (_cursorType)
1305 if (!SDL_HideCursor())
1307 WLog_Print(getWLog(), WLOG_ERROR,
"SDL_HideCursor failed");
1311 setHasCursor(
false);
1314 case CURSOR_DEFAULT:
1316 auto def = SDL_GetDefaultCursor();
1317 if (!SDL_SetCursor(def))
1319 WLog_Print(getWLog(), WLOG_ERROR,
"SDL_SetCursor(default=%p) failed",
1320 static_cast<void*
>(def));
1323 if (!SDL_ShowCursor())
1325 WLog_Print(getWLog(), WLOG_ERROR,
"SDL_ShowCursor failed");
1333 return sdl_Pointer_Set_Process(
this);
1335 WLog_Print(getWLog(), WLOG_ERROR,
"Unknown cursorType %s",
1336 sdl::utils::toString(_cursorType).c_str());
1341void SdlContext::setMonitorIds(
const std::vector<SDL_DisplayID>& ids)
1343 _monitorIds.clear();
1346 _monitorIds.push_back(
id);
1350const std::vector<SDL_DisplayID>& SdlContext::monitorIds()
const
1355int64_t SdlContext::monitorId(uint32_t index)
const
1357 if (index >= _monitorIds.size())
1361 return _monitorIds[index];
1364void SdlContext::push(std::vector<SDL_Rect>&& rects)
1366 std::unique_lock lock(_queue_mux);
1367 _queue.emplace(std::move(rects));
1370std::vector<SDL_Rect> SdlContext::pop()
1372 std::unique_lock lock(_queue_mux);
1377 auto val = std::move(_queue.front());
1382bool SdlContext::setFullscreen(
bool enter)
1384 for (
const auto& window : _windows)
1386 if (!sdl_push_user_event(SDL_EVENT_USER_WINDOW_FULLSCREEN, &window.second, enter))
1389 _fullscreen = enter;
1393bool SdlContext::setMinimized()
1395 return sdl_push_user_event(SDL_EVENT_USER_WINDOW_MINIMIZE);
1398bool SdlContext::grabMouse()
const
1403bool SdlContext::toggleGrabMouse()
1405 return setGrabMouse(!grabMouse());
1408bool SdlContext::setGrabMouse(
bool enter)
1414bool SdlContext::grabKeyboard()
const
1416 return _grabKeyboard;
1419bool SdlContext::toggleGrabKeyboard()
1421 return setGrabKeyboard(!grabKeyboard());
1424bool SdlContext::setGrabKeyboard(
bool enter)
1426 _grabKeyboard = enter;
1430bool SdlContext::setResizeable(
bool enable)
1432 const auto settings = context()->settings;
1435 bool use = (dyn && enable) || smart;
1437 for (
const auto& window : _windows)
1439 if (!sdl_push_user_event(SDL_EVENT_USER_WINDOW_RESIZEABLE, &window.second, use))
1447bool SdlContext::resizeable()
const
1452bool SdlContext::toggleResizeable()
1454 return setResizeable(!resizeable());
1457bool SdlContext::fullscreen()
const
1462bool SdlContext::toggleFullscreen()
1464 return setFullscreen(!fullscreen());
SdlContext(rdpContext *context)
object that handles clipboard context for the SDL3 client
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_server_name(const rdpSettings *settings)
A helper function to return the correct server name.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_monitor_def_array_sorted(rdpSettings *settings, const rdpMonitor *monitors, size_t count)
Sort monitor array according to:
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.