24#include <freerdp/config.h>
30#include <freerdp/constants.h>
31#include <freerdp/freerdp.h>
32#include <freerdp/gdi/gdi.h>
33#include <freerdp/streamdump.h>
34#include <freerdp/utils/signal.h>
36#include <freerdp/channels/channels.h>
37#include <freerdp/client/channels.h>
38#include <freerdp/client/cliprdr.h>
39#include <freerdp/client/cmdline.h>
40#include <freerdp/client/file.h>
42#include <freerdp/log.h>
43#include <winpr/assert.h>
44#include <winpr/config.h>
46#include <winpr/synch.h>
49#if !defined(__MINGW32__)
50#include <SDL3/SDL_main.h>
52#include <SDL3/SDL_hints.h>
53#include <SDL3/SDL_oldnames.h>
54#include <SDL3/SDL_video.h>
56#include <sdl_config.hpp>
58#include "dialogs/sdl_connection_dialog_hider.hpp"
59#include "dialogs/sdl_dialogs.hpp"
60#include "scoped_guard.hpp"
61#include "sdl_channels.hpp"
62#include "sdl_disp.hpp"
63#include "sdl_freerdp.hpp"
65#include "sdl_monitor.hpp"
66#include "sdl_pointer.hpp"
67#include "sdl_prefs.hpp"
68#include "sdl_touch.hpp"
69#include "sdl_utils.hpp"
71#if defined(WITH_WEBVIEW)
72#include <aad/sdl_webview.hpp>
75#define SDL_TAG CLIENT_TAG("SDL")
81 SDL_EXIT_DISCONNECT = 1,
83 SDL_EXIT_IDLE_TIMEOUT = 3,
84 SDL_EXIT_LOGON_TIMEOUT = 4,
85 SDL_EXIT_CONN_REPLACED = 5,
86 SDL_EXIT_OUT_OF_MEMORY = 6,
87 SDL_EXIT_CONN_DENIED = 7,
88 SDL_EXIT_CONN_DENIED_FIPS = 8,
89 SDL_EXIT_USER_PRIVILEGES = 9,
90 SDL_EXIT_FRESH_CREDENTIALS_REQUIRED = 10,
91 SDL_EXIT_DISCONNECT_BY_USER = 11,
94 SDL_EXIT_LICENSE_INTERNAL = 16,
95 SDL_EXIT_LICENSE_NO_LICENSE_SERVER = 17,
96 SDL_EXIT_LICENSE_NO_LICENSE = 18,
97 SDL_EXIT_LICENSE_BAD_CLIENT_MSG = 19,
98 SDL_EXIT_LICENSE_HWID_DOESNT_MATCH = 20,
99 SDL_EXIT_LICENSE_BAD_CLIENT = 21,
100 SDL_EXIT_LICENSE_CANT_FINISH_PROTOCOL = 22,
101 SDL_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL = 23,
102 SDL_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION = 24,
103 SDL_EXIT_LICENSE_CANT_UPGRADE = 25,
104 SDL_EXIT_LICENSE_NO_REMOTE_CONNECTIONS = 26,
110 SDL_EXIT_PARSE_ARGUMENTS = 128,
111 SDL_EXIT_MEMORY = 129,
112 SDL_EXIT_PROTOCOL = 130,
113 SDL_EXIT_CONN_FAILED = 131,
114 SDL_EXIT_AUTH_FAILURE = 132,
115 SDL_EXIT_NEGO_FAILURE = 133,
116 SDL_EXIT_LOGON_FAILURE = 134,
117 SDL_EXIT_ACCOUNT_LOCKED_OUT = 135,
118 SDL_EXIT_PRE_CONNECT_FAILED = 136,
119 SDL_EXIT_CONNECT_UNDEFINED = 137,
120 SDL_EXIT_POST_CONNECT_FAILED = 138,
121 SDL_EXIT_DNS_ERROR = 139,
122 SDL_EXIT_DNS_NAME_NOT_FOUND = 140,
123 SDL_EXIT_CONNECT_FAILED = 141,
124 SDL_EXIT_MCS_CONNECT_INITIAL_ERROR = 142,
125 SDL_EXIT_TLS_CONNECT_FAILED = 143,
126 SDL_EXIT_INSUFFICIENT_PRIVILEGES = 144,
127 SDL_EXIT_CONNECT_CANCELLED = 145,
129 SDL_EXIT_CONNECT_TRANSPORT_FAILED = 147,
130 SDL_EXIT_CONNECT_PASSWORD_EXPIRED = 148,
131 SDL_EXIT_CONNECT_PASSWORD_MUST_CHANGE = 149,
132 SDL_EXIT_CONNECT_KDC_UNREACHABLE = 150,
133 SDL_EXIT_CONNECT_ACCOUNT_DISABLED = 151,
134 SDL_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED = 152,
135 SDL_EXIT_CONNECT_CLIENT_REVOKED = 153,
136 SDL_EXIT_CONNECT_WRONG_PASSWORD = 154,
137 SDL_EXIT_CONNECT_ACCESS_DENIED = 155,
138 SDL_EXIT_CONNECT_ACCOUNT_RESTRICTION = 156,
139 SDL_EXIT_CONNECT_ACCOUNT_EXPIRED = 157,
140 SDL_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED = 158,
141 SDL_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS = 159,
142 SDL_EXIT_CONNECT_TARGET_BOOTING = 160,
144 SDL_EXIT_UNKNOWN = 255,
147struct sdl_exit_code_map_t
151 const char* code_tag;
154#define ENTRY(x, y) { x, y, #y }
155static const struct sdl_exit_code_map_t sdl_exit_code_map[] = {
156 ENTRY(FREERDP_ERROR_SUCCESS, SDL_EXIT_SUCCESS), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_DISCONNECT),
157 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LOGOFF), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_IDLE_TIMEOUT),
158 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LOGON_TIMEOUT),
159 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_REPLACED),
160 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_OUT_OF_MEMORY),
161 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_DENIED),
162 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_DENIED_FIPS),
163 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_USER_PRIVILEGES),
164 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_FRESH_CREDENTIALS_REQUIRED),
165 ENTRY(ERRINFO_LOGOFF_BY_USER, SDL_EXIT_DISCONNECT_BY_USER),
166 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_UNKNOWN),
169 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_INTERNAL),
170 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_LICENSE_SERVER),
171 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_LICENSE),
172 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT_MSG),
173 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_HWID_DOESNT_MATCH),
174 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT),
175 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_FINISH_PROTOCOL),
176 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL),
177 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION),
178 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_UPGRADE),
179 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_REMOTE_CONNECTIONS),
180 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_UPGRADE),
183 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_RDP),
186 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_PARSE_ARGUMENTS), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_MEMORY),
187 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_PROTOCOL), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_FAILED),
189 ENTRY(FREERDP_ERROR_AUTHENTICATION_FAILED, SDL_EXIT_AUTH_FAILURE),
190 ENTRY(FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED, SDL_EXIT_NEGO_FAILURE),
191 ENTRY(FREERDP_ERROR_CONNECT_LOGON_FAILURE, SDL_EXIT_LOGON_FAILURE),
192 ENTRY(FREERDP_ERROR_CONNECT_TARGET_BOOTING, SDL_EXIT_CONNECT_TARGET_BOOTING),
193 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT, SDL_EXIT_ACCOUNT_LOCKED_OUT),
194 ENTRY(FREERDP_ERROR_PRE_CONNECT_FAILED, SDL_EXIT_PRE_CONNECT_FAILED),
195 ENTRY(FREERDP_ERROR_CONNECT_UNDEFINED, SDL_EXIT_CONNECT_UNDEFINED),
196 ENTRY(FREERDP_ERROR_POST_CONNECT_FAILED, SDL_EXIT_POST_CONNECT_FAILED),
197 ENTRY(FREERDP_ERROR_DNS_ERROR, SDL_EXIT_DNS_ERROR),
198 ENTRY(FREERDP_ERROR_DNS_NAME_NOT_FOUND, SDL_EXIT_DNS_NAME_NOT_FOUND),
199 ENTRY(FREERDP_ERROR_CONNECT_FAILED, SDL_EXIT_CONNECT_FAILED),
200 ENTRY(FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR, SDL_EXIT_MCS_CONNECT_INITIAL_ERROR),
201 ENTRY(FREERDP_ERROR_TLS_CONNECT_FAILED, SDL_EXIT_TLS_CONNECT_FAILED),
202 ENTRY(FREERDP_ERROR_INSUFFICIENT_PRIVILEGES, SDL_EXIT_INSUFFICIENT_PRIVILEGES),
203 ENTRY(FREERDP_ERROR_CONNECT_CANCELLED, SDL_EXIT_CONNECT_CANCELLED),
204 ENTRY(FREERDP_ERROR_CONNECT_TRANSPORT_FAILED, SDL_EXIT_CONNECT_TRANSPORT_FAILED),
205 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED, SDL_EXIT_CONNECT_PASSWORD_EXPIRED),
206 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE, SDL_EXIT_CONNECT_PASSWORD_MUST_CHANGE),
207 ENTRY(FREERDP_ERROR_CONNECT_KDC_UNREACHABLE, SDL_EXIT_CONNECT_KDC_UNREACHABLE),
208 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED, SDL_EXIT_CONNECT_ACCOUNT_DISABLED),
209 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED,
210 SDL_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED),
211 ENTRY(FREERDP_ERROR_CONNECT_CLIENT_REVOKED, SDL_EXIT_CONNECT_CLIENT_REVOKED),
212 ENTRY(FREERDP_ERROR_CONNECT_WRONG_PASSWORD, SDL_EXIT_CONNECT_WRONG_PASSWORD),
213 ENTRY(FREERDP_ERROR_CONNECT_ACCESS_DENIED, SDL_EXIT_CONNECT_ACCESS_DENIED),
214 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION, SDL_EXIT_CONNECT_ACCOUNT_RESTRICTION),
215 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED, SDL_EXIT_CONNECT_ACCOUNT_EXPIRED),
216 ENTRY(FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED, SDL_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED),
217 ENTRY(FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS,
218 SDL_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS)
221static const struct sdl_exit_code_map_t* sdl_map_entry_by_code(
int exit_code)
223 for (
const auto& x : sdl_exit_code_map)
225 const struct sdl_exit_code_map_t* cur = &x;
226 if (cur->code == exit_code)
232static const struct sdl_exit_code_map_t* sdl_map_entry_by_error(UINT32 error)
234 for (
const auto& x : sdl_exit_code_map)
236 const struct sdl_exit_code_map_t* cur = &x;
237 if (cur->error == error)
243static int sdl_map_error_to_exit_code(DWORD error)
245 const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_error(error);
249 return SDL_EXIT_CONN_FAILED;
252static const char* sdl_map_error_to_code_tag(UINT32 error)
254 const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_error(error);
256 return entry->code_tag;
260static const char* sdl_map_to_code_tag(
int code)
262 const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_code(code);
264 return entry->code_tag;
268static int error_info_to_error(freerdp* instance, DWORD* pcode,
char** msg,
size_t* len)
270 const DWORD code = freerdp_error_info(instance);
271 const char* name = freerdp_get_error_info_name(code);
272 const char* str = freerdp_get_error_info_string(code);
273 const int exit_code = sdl_map_error_to_exit_code(code);
275 winpr_asprintf(msg, len,
"Terminate with %s due to ERROR_INFO %s [0x%08" PRIx32
"]: %s",
276 sdl_map_error_to_code_tag(code), name, code, str);
277 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"%s", *msg);
285static BOOL sdl_begin_paint(rdpContext* context)
287 auto gdi = context->gdi;
289 WINPR_ASSERT(gdi->primary);
291 HGDI_DC hdc = gdi->primary->hdc;
297 WINPR_ASSERT(hwnd->invalid);
298 hwnd->invalid->null = TRUE;
305 SDL_Surface* surface, SDL_Point offset,
const SDL_Rect& srcRect)
307 WINPR_ASSERT(surface);
308 SDL_Rect dstRect = { offset.x + srcRect.x, offset.y + srcRect.y, srcRect.w, srcRect.h };
309 return window.blit(surface, srcRect, dstRect);
312static bool sdl_draw_to_window_rect(
SdlContext* sdl,
SdlWindow& window, SDL_Surface* surface,
313 SDL_Point offset,
const std::vector<SDL_Rect>& rects = {})
317 return sdl_draw_to_window_rect(sdl, window, surface, offset,
318 { 0, 0, surface->w, surface->h });
320 for (
auto& srcRect : rects)
322 if (!sdl_draw_to_window_rect(sdl, window, surface, offset, srcRect))
328static bool sdl_draw_to_window_scaled_rect(
SdlContext* sdl,
SdlWindow& window, SDL_Surface* surface,
329 const SDL_Rect& srcRect)
331 SDL_Rect dstRect = srcRect;
332 sdl_scale_coordinates(sdl, window.id(), &dstRect.x, &dstRect.y, FALSE, TRUE);
333 sdl_scale_coordinates(sdl, window.id(), &dstRect.w, &dstRect.h, FALSE, TRUE);
334 return window.blit(surface, srcRect, dstRect);
337static BOOL sdl_draw_to_window_scaled_rect(
SdlContext* sdl,
SdlWindow& window, SDL_Surface* surface,
338 const std::vector<SDL_Rect>& rects = {})
342 return sdl_draw_to_window_scaled_rect(sdl, window, surface,
343 { 0, 0, surface->w, surface->h });
345 for (
const auto& srcRect : rects)
347 if (!sdl_draw_to_window_scaled_rect(sdl, window, surface, srcRect))
354 const std::vector<SDL_Rect>& rects = {})
358 if (!sdl->isConnected())
361 auto context = sdl->context();
362 auto gdi = context->gdi;
365 auto size = window.rect();
367 auto surface = sdl->primary.get();
370 window.setOffsetX(0);
371 window.setOffsetY(0);
372 if (gdi->width < size.w)
374 window.setOffsetX((size.w - gdi->width) / 2);
376 if (gdi->height < size.h)
378 window.setOffsetY((size.h - gdi->height) / 2);
380 if (!sdl_draw_to_window_scaled_rect(sdl, window, surface, rects))
386 if (!sdl_draw_to_window_rect(sdl, window, surface, { window.offsetX(), window.offsetY() },
391 window.updateSurface();
395static BOOL sdl_draw_to_window(
SdlContext* sdl, std::map<Uint32, SdlWindow>& windows,
396 const std::vector<SDL_Rect>& rects = {})
398 for (
auto& window : windows)
400 if (!sdl_draw_to_window(sdl, window.second, rects))
411static BOOL sdl_end_paint(rdpContext* context)
413 auto sdl = get_context(context);
416 auto gdi = context->gdi;
418 WINPR_ASSERT(gdi->primary);
420 HGDI_DC hdc = gdi->primary->hdc;
426 WINPR_ASSERT(hwnd->invalid || (hwnd->ninvalid == 0));
428 if (hwnd->invalid->null)
431 WINPR_ASSERT(hwnd->invalid);
432 if (gdi->suppressOutput || hwnd->invalid->null)
435 const INT32 ninvalid = hwnd->ninvalid;
436 const GDI_RGN* cinvalid = hwnd->cinvalid;
441 std::vector<SDL_Rect> rects;
442 for (INT32 x = 0; x < ninvalid; x++)
444 auto& rgn = cinvalid[x];
445 rects.push_back({ rgn.x, rgn.y, rgn.w, rgn.h });
448 sdl->push(std::move(rects));
449 return sdl_push_user_event(SDL_EVENT_USER_UPDATE);
452static void sdl_destroy_primary(
SdlContext* sdl)
456 sdl->primary.reset();
460static BOOL sdl_create_primary(
SdlContext* sdl)
462 rdpGdi* gdi =
nullptr;
466 gdi = sdl->context()->gdi;
469 sdl_destroy_primary(sdl);
471 SDLSurfacePtr(SDL_CreateSurfaceFrom(
static_cast<int>(gdi->width),
472 static_cast<int>(gdi->height), sdl->sdl_pixel_format,
473 gdi->primary_buffer,
static_cast<int>(gdi->stride)),
478 SDL_SetSurfaceBlendMode(sdl->primary.get(), SDL_BLENDMODE_NONE);
479 SDL_Rect surfaceRect = { 0, 0, gdi->width, gdi->height };
480 SDL_FillSurfaceRect(sdl->primary.get(), &surfaceRect,
481 SDL_MapSurfaceRGBA(sdl->primary.get(), 0, 0, 0, 0xff));
486static BOOL sdl_desktop_resize(rdpContext* context)
488 rdpGdi* gdi =
nullptr;
489 rdpSettings* settings =
nullptr;
490 auto sdl = get_context(context);
493 WINPR_ASSERT(context);
495 settings = context->settings;
496 WINPR_ASSERT(settings);
498 std::lock_guard<CriticalSection> lock(sdl->critical);
503 return sdl_create_primary(sdl);
507static BOOL sdl_play_sound(rdpContext* context,
const PLAY_SOUND_UPDATE* play_sound)
510 WINPR_UNUSED(context);
511 WINPR_UNUSED(play_sound);
518 sdl->initialize.set();
520 HANDLE handles[] = { sdl->initialized.handle(), freerdp_abort_event(sdl->context()) };
522 const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
534static BOOL sdl_pre_connect(freerdp* instance)
536 WINPR_ASSERT(instance);
537 WINPR_ASSERT(instance->context);
539 auto sdl = get_context(instance->context);
541 auto settings = instance->context->settings;
542 WINPR_ASSERT(settings);
557 PubSub_SubscribeChannelConnected(instance->context->pubSub, sdl_OnChannelConnectedEventHandler);
558 PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
559 sdl_OnChannelDisconnectedEventHandler);
564 UINT32 maxHeight = 0;
566 if (!sdl_wait_for_init(sdl))
569 if (!sdl_detect_monitors(sdl, &maxWidth, &maxHeight))
572 if ((maxWidth != 0) && (maxHeight != 0) &&
575 WLog_Print(sdl->log, WLOG_INFO,
"Update size to %ux%u", maxWidth, maxHeight);
587 WLog_Print(sdl->log, WLOG_INFO,
"auth-only, but no password set. Please provide one.");
594 WLog_Print(sdl->log, WLOG_INFO,
"Authentication only. Don't connect SDL.");
597 if (!sdl->input.initialize())
604static const char* sdl_window_get_title(rdpSettings* settings)
606 const char* windowTitle =
nullptr;
609 const char* name =
nullptr;
610 const char* prefix =
"FreeRDP:";
622 addPort = (port != 3389);
624 char buffer[MAX_PATH + 64] = {};
627 (void)sprintf_s(buffer,
sizeof(buffer),
"%s %s", prefix, name);
629 (
void)sprintf_s(buffer,
sizeof(buffer),
"%s %s:%" PRIu32, prefix, name, port);
636static void sdl_term_handler([[maybe_unused]]
int signum, [[maybe_unused]]
const char* signame,
637 [[maybe_unused]]
void* context)
647 std::lock_guard<CriticalSection> lock(sdl->critical);
648 sdl->windows.clear();
649 sdl->dialog.destroy();
651 sdl_destroy_primary(sdl);
653 freerdp_del_signal_cleanup_handler(sdl->context(), sdl_term_handler);
654 sdl_dialogs_uninit();
658static BOOL sdl_create_windows(
SdlContext* sdl)
662 auto settings = sdl->context()->settings;
663 auto title = sdl_window_get_title(settings);
665 ScopeGuard guard1([&]() { sdl->windows_created.set(); });
671 for (UINT32 x = 0; x < windowCount; x++)
673 auto id = sdl->monitorId(x);
678 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x));
680 originX = std::min<Sint32>(monitor->x, originX);
681 originY = std::min<Sint32>(monitor->y, originY);
684 for (UINT32 x = 0; x < windowCount; x++)
686 auto id = sdl->monitorId(x);
691 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x));
693 auto w = WINPR_ASSERTING_INT_CAST(Uint32, monitor->width);
694 auto h = WINPR_ASSERTING_INT_CAST(Uint32, monitor->height);
702 Uint32 flags = SDL_WINDOW_HIGH_PIXEL_DENSITY;
703 auto startupX = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
704 auto startupY = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
709 flags |= SDL_WINDOW_FULLSCREEN;
714 flags |= SDL_WINDOW_BORDERLESS;
718 flags |= SDL_WINDOW_BORDERLESS;
720 char buffer[MAX_PATH + 64] = {};
721 (void)sprintf_s(buffer,
sizeof(buffer),
"%s:%" PRIu32, title, x);
723 static_cast<int>(startupX),
724 static_cast<int>(startupY),
728 if (!window.window())
733 window.setOffsetX(originX - monitor->x);
734 window.setOffsetY(originY - monitor->y);
737 sdl->windows.insert({ window.id(), std::move(window) });
743static BOOL sdl_wait_create_windows(
SdlContext* sdl)
746 std::unique_lock<CriticalSection> lock(sdl->critical);
747 sdl->windows_created.clear();
748 if (!sdl_push_user_event(SDL_EVENT_USER_CREATE_WINDOWS, sdl))
752 HANDLE handles[] = { sdl->windows_created.handle(), freerdp_abort_event(sdl->context()) };
754 const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
766 std::lock_guard<CriticalSection> lock(sdl->critical);
767 if (freerdp_shall_disconnect_context(sdl->context()))
769 if (sdl->rdp_thread_running)
771 return !sdl->dialog.isRunning();
781 HANDLE handles[] = { sdl->initialize.handle(), freerdp_abort_event(sdl->context()) };
782 const DWORD status = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
791 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
792 auto backend = SDL_GetCurrentVideoDriver();
793 WLog_Print(sdl->log, WLOG_DEBUG,
"client is using backend '%s'", backend);
796 SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED,
"0");
797 SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,
"0");
799 freerdp_add_signal_cleanup_handler(sdl->context(), sdl_term_handler);
800 sdl->dialog.create(sdl->context());
801 sdl->dialog.setTitle(
"Connecting to '%s'",
803 sdl->dialog.showInfo(
"The connection is being established\n\nPlease wait...");
806 sdl->dialog.show(
true);
809 sdl->initialized.set();
811 while (!shall_abort(sdl))
813 SDL_Event windowEvent = {};
814 while (!shall_abort(sdl) && SDL_WaitEventTimeout(
nullptr, 1000))
819 const int prc = SDL_PeepEvents(&windowEvent, 1, SDL_GETEVENT, SDL_EVENT_FIRST,
820 SDL_EVENT_USER_RETRY_DIALOG);
823 if (sdl_log_error(prc, sdl->log,
"SDL_PeepEvents"))
827#if defined(WITH_DEBUG_SDL_EVENTS)
828 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"got event %s [0x%08" PRIx32
"]",
829 sdl_event_type_str(windowEvent.type), windowEvent.type);
832 std::lock_guard<CriticalSection> lock(sdl->critical);
835 if (freerdp_shall_disconnect_context(sdl->context()))
839 if (sdl->dialog.handleEvent(windowEvent))
844 auto point2pix = [](Uint32 win_id,
float& x,
float& y)
846 auto win = SDL_GetWindowFromID(win_id);
849 auto scale = SDL_GetWindowDisplayScale(win);
856 switch (windowEvent.type)
859 freerdp_abort_connect_context(sdl->context());
861 case SDL_EVENT_KEY_DOWN:
862 case SDL_EVENT_KEY_UP:
864 const SDL_KeyboardEvent* ev = &windowEvent.key;
865 sdl->input.keyboard_handle_event(ev);
868 case SDL_EVENT_KEYMAP_CHANGED:
872 case SDL_EVENT_MOUSE_MOTION:
874 SDL_MouseMotionEvent& ev = windowEvent.motion;
875 point2pix(ev.windowID, ev.x, ev.y);
876 point2pix(ev.windowID, ev.xrel, ev.yrel);
877 sdl_handle_mouse_motion(sdl, &ev);
880 case SDL_EVENT_MOUSE_BUTTON_DOWN:
881 case SDL_EVENT_MOUSE_BUTTON_UP:
883 SDL_MouseButtonEvent& ev = windowEvent.button;
884 point2pix(ev.windowID, ev.x, ev.y);
885 sdl_handle_mouse_button(sdl, &ev);
888 case SDL_EVENT_MOUSE_WHEEL:
890 const SDL_MouseWheelEvent* ev = &windowEvent.wheel;
891 sdl_handle_mouse_wheel(sdl, ev);
894 case SDL_EVENT_FINGER_DOWN:
896 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
897 sdl_handle_touch_down(sdl, ev);
900 case SDL_EVENT_FINGER_UP:
902 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
903 sdl_handle_touch_up(sdl, ev);
906 case SDL_EVENT_FINGER_MOTION:
908 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
909 sdl_handle_touch_motion(sdl, ev);
913 case SDL_EVENT_RENDER_TARGETS_RESET:
916 case SDL_EVENT_RENDER_DEVICE_RESET:
919 case SDL_EVENT_WILL_ENTER_FOREGROUND:
922 case SDL_EVENT_USER_CERT_DIALOG:
925 auto title =
static_cast<const char*
>(windowEvent.user.data1);
926 auto msg =
static_cast<const char*
>(windowEvent.user.data2);
927 sdl_cert_dialog_show(title, msg);
930 case SDL_EVENT_USER_SHOW_DIALOG:
933 auto title =
static_cast<const char*
>(windowEvent.user.data1);
934 auto msg =
static_cast<const char*
>(windowEvent.user.data2);
935 sdl_message_dialog_show(title, msg, windowEvent.user.code);
938 case SDL_EVENT_USER_SCARD_DIALOG:
941 auto title =
static_cast<const char*
>(windowEvent.user.data1);
942 auto msg =
static_cast<const char**
>(windowEvent.user.data2);
943 sdl_scard_dialog_show(title, windowEvent.user.code, msg);
946 case SDL_EVENT_USER_AUTH_DIALOG:
949 sdl_auth_dialog_show(
953 case SDL_EVENT_USER_UPDATE:
955 std::vector<SDL_Rect> rectangles;
958 rectangles = sdl->pop();
959 sdl_draw_to_window(sdl, sdl->windows, rectangles);
960 }
while (!rectangles.empty());
963 case SDL_EVENT_USER_CREATE_WINDOWS:
965 auto ctx =
static_cast<SdlContext*
>(windowEvent.user.data1);
966 sdl_create_windows(ctx);
969 case SDL_EVENT_USER_WINDOW_RESIZEABLE:
971 auto window =
static_cast<SdlWindow*
>(windowEvent.user.data1);
972 const bool use = windowEvent.user.code != 0;
974 window->resizeable(use);
977 case SDL_EVENT_USER_WINDOW_FULLSCREEN:
979 auto window =
static_cast<SdlWindow*
>(windowEvent.user.data1);
980 const bool enter = windowEvent.user.code != 0;
982 window->fullscreen(enter);
985 case SDL_EVENT_USER_WINDOW_MINIMIZE:
986 for (
auto& window : sdl->windows)
988 window.second.minimize();
991 case SDL_EVENT_USER_POINTER_NULL:
993 sdl->setCursor(
nullptr);
994 sdl->setHasCursor(
false);
996 case SDL_EVENT_USER_POINTER_DEFAULT:
998 SDL_Cursor* def = SDL_GetDefaultCursor();
1001 sdl->setCursor(
nullptr);
1002 sdl->setHasCursor(
true);
1005 case SDL_EVENT_USER_POINTER_POSITION:
1008 static_cast<INT32
>(
reinterpret_cast<uintptr_t
>(windowEvent.user.data1));
1010 static_cast<INT32
>(
reinterpret_cast<uintptr_t
>(windowEvent.user.data2));
1012 SDL_Window* window = SDL_GetMouseFocus();
1015 const Uint32
id = SDL_GetWindowID(window);
1019 if (sdl_scale_coordinates(sdl,
id, &sx, &sy, FALSE, FALSE))
1020 SDL_WarpMouseInWindow(window,
static_cast<float>(sx),
1021 static_cast<float>(sy));
1025 case SDL_EVENT_USER_POINTER_SET:
1026 sdl->setCursor(
static_cast<rdpPointer*
>(windowEvent.user.data1));
1027 sdl_Pointer_Set_Process(sdl);
1029 case SDL_EVENT_CLIPBOARD_UPDATE:
1030 sdl->clip.handle_update(windowEvent.clipboard);
1032 case SDL_EVENT_USER_QUIT:
1034 if ((windowEvent.type >= SDL_EVENT_DISPLAY_FIRST) &&
1035 (windowEvent.type <= SDL_EVENT_DISPLAY_LAST))
1037 const SDL_DisplayEvent* ev = &windowEvent.display;
1038 (void)sdl->disp.handle_display_event(ev);
1040 else if ((windowEvent.type >= SDL_EVENT_WINDOW_FIRST) &&
1041 (windowEvent.type <= SDL_EVENT_WINDOW_LAST))
1043 const SDL_WindowEvent* ev = &windowEvent.window;
1044 auto window = sdl->windows.find(ev->windowID);
1045 if (window != sdl->windows.end())
1047 (void)sdl->disp.handle_window_event(ev);
1051 case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
1052 if (sdl->isConnected())
1054 sdl_Pointer_Set_Process(sdl);
1056 sdl->context()->settings,
1057 FreeRDP_DynamicResolutionUpdate))
1061 auto win = window->second.window();
1064 [[maybe_unused]]
auto rcpix =
1065 SDL_GetWindowSizeInPixels(win, &w_pix, &h_pix);
1067 auto scale = SDL_GetWindowDisplayScale(win);
1068 if (scale <= SDL_FLT_EPSILON)
1070 auto err = SDL_GetError();
1072 SDL_LOG_CATEGORY_APPLICATION,
1073 "SDL_GetWindowDisplayScale() failed with %s", err);
1077 assert(SDL_isnanf(scale) == 0);
1078 assert(SDL_isinff(scale) == 0);
1079 assert(scale > SDL_FLT_EPSILON);
1080 auto w_gdi = sdl->context()->gdi->width;
1081 auto h_gdi = sdl->context()->gdi->height;
1082 auto pix2point = [=](
int pix)
1084 return static_cast<int>(
static_cast<float>(pix) /
1087 if (w_pix != w_gdi || h_pix != h_gdi)
1089 const auto ssws = SDL_SetWindowSize(
1090 win, pix2point(w_gdi), pix2point(h_gdi));
1093 auto err = SDL_GetError();
1095 SDL_LOG_CATEGORY_APPLICATION,
1096 "SDL_SetWindowSize() failed with %s", err);
1102 case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
1103 window->second.fill();
1104 sdl_draw_to_window(sdl, window->second);
1105 sdl_Pointer_Set_Process(sdl);
1107 case SDL_EVENT_WINDOW_MOVED:
1109 auto r = window->second.rect();
1110 auto id = window->second.id();
1111 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
"%u: %dx%d-%dx%d",
1112 id, r.x, r.y, r.w, r.h);
1115 case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
1117 SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION,
1118 "Window closed, terminating RDP session...");
1119 freerdp_abort_connect_context(sdl->context());
1134 sdl_cleanup_sdl(sdl);
1146static BOOL sdl_post_connect(freerdp* instance)
1148 WINPR_ASSERT(instance);
1150 auto context = instance->context;
1151 WINPR_ASSERT(context);
1153 auto sdl = get_context(context);
1156 sdl->dialog.show(
false);
1163 WLog_Print(sdl->log, WLOG_INFO,
"auth-only, but no password set. Please provide one.");
1167 WLog_Print(sdl->log, WLOG_INFO,
"Authentication only. Don't connect to X.");
1171 if (!sdl_wait_create_windows(sdl))
1174 sdl->sdl_pixel_format = SDL_PIXELFORMAT_BGRA32;
1175 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
1178 if (!sdl_create_primary(sdl))
1181 if (!sdl_register_pointer(instance->context->graphics))
1184 WINPR_ASSERT(context->update);
1186 context->update->BeginPaint = sdl_begin_paint;
1187 context->update->EndPaint = sdl_end_paint;
1188 context->update->PlaySound = sdl_play_sound;
1189 context->update->DesktopResize = sdl_desktop_resize;
1190 context->update->SetKeyboardIndicators = sdlInput::keyboard_set_indicators;
1191 context->update->SetKeyboardImeStatus = sdlInput::keyboard_set_ime_status;
1193 if (!sdl->update_resizeable(
false))
1198 sdl->setConnected(
true);
1205static void sdl_post_disconnect(freerdp* instance)
1210 if (!instance->context)
1213 auto sdl = get_context(instance->context);
1214 sdl->setConnected(
false);
1219static void sdl_post_final_disconnect(freerdp* instance)
1224 if (!instance->context)
1227 PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
1228 sdl_OnChannelConnectedEventHandler);
1229 PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
1230 sdl_OnChannelDisconnectedEventHandler);
1233static void sdl_client_cleanup(
SdlContext* sdl,
int exit_code,
const std::string& error_msg)
1237 rdpContext* context = sdl->context();
1238 WINPR_ASSERT(context);
1239 rdpSettings* settings = context->settings;
1240 WINPR_ASSERT(settings);
1242 sdl->rdp_thread_running =
false;
1243 bool showError =
false;
1245 WLog_Print(sdl->log, WLOG_INFO,
"Authentication only, exit status %s [%" PRId32
"]",
1246 sdl_map_to_code_tag(exit_code), exit_code);
1251 case SDL_EXIT_SUCCESS:
1252 case SDL_EXIT_DISCONNECT:
1253 case SDL_EXIT_LOGOFF:
1254 case SDL_EXIT_DISCONNECT_BY_USER:
1255 case SDL_EXIT_CONNECT_CANCELLED:
1259 sdl->dialog.showError(error_msg);
1266 sdl->dialog.show(
false);
1268 sdl->exit_code = exit_code;
1269 sdl_push_user_event(SDL_EVENT_USER_QUIT);
1273static int sdl_client_thread_connect(
SdlContext* sdl, std::string& error_msg)
1277 auto instance = sdl->context()->instance;
1278 WINPR_ASSERT(instance);
1280 sdl->rdp_thread_running =
true;
1281 BOOL rc = freerdp_connect(instance);
1283 rdpContext* context = sdl->context();
1284 rdpSettings* settings = context->settings;
1285 WINPR_ASSERT(settings);
1287 int exit_code = SDL_EXIT_SUCCESS;
1290 UINT32 error = freerdp_get_last_error(context);
1291 exit_code = sdl_map_error_to_exit_code(error);
1296 DWORD code = freerdp_get_last_error(context);
1297 freerdp_abort_connect_context(context);
1298 WLog_Print(sdl->log, WLOG_ERROR,
"Authentication only, %s [0x%08" PRIx32
"] %s",
1299 freerdp_get_last_error_name(code), code, freerdp_get_last_error_string(code));
1305 DWORD code = freerdp_error_info(instance);
1306 if (exit_code == SDL_EXIT_SUCCESS)
1308 char* msg =
nullptr;
1310 exit_code = error_info_to_error(instance, &code, &msg, &len);
1316 auto last = freerdp_get_last_error(context);
1317 if (error_msg.empty())
1319 char* msg =
nullptr;
1321 winpr_asprintf(&msg, &len,
"%s [0x%08" PRIx32
"]\n%s",
1322 freerdp_get_last_error_name(last), last,
1323 freerdp_get_last_error_string(last));
1329 if (exit_code == SDL_EXIT_SUCCESS)
1331 if (last == FREERDP_ERROR_AUTHENTICATION_FAILED)
1332 exit_code = SDL_EXIT_AUTH_FAILURE;
1333 else if (code == ERRINFO_SUCCESS)
1334 exit_code = SDL_EXIT_CONN_FAILED;
1337 sdl->dialog.show(
false);
1343static int sdl_client_thread_run(
SdlContext* sdl, std::string& error_msg)
1347 auto context = sdl->context();
1348 WINPR_ASSERT(context);
1350 auto instance = context->instance;
1351 WINPR_ASSERT(instance);
1353 int exit_code = SDL_EXIT_SUCCESS;
1354 while (!freerdp_shall_disconnect_context(context))
1356 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {};
1362 if (freerdp_focus_required(instance))
1364 auto ctx = get_context(context);
1366 if (!ctx->input.keyboard_focus_in())
1368 if (!ctx->input.keyboard_focus_in())
1372 const DWORD nCount = freerdp_get_event_handles(context, handles, ARRAYSIZE(handles));
1376 WLog_Print(sdl->log, WLOG_ERROR,
"freerdp_get_event_handles failed");
1380 const DWORD status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
1382 if (status == WAIT_FAILED)
1385 if (!freerdp_check_event_handles(context))
1387 if (client_auto_reconnect(instance))
1390 sdl->dialog.show(
false);
1399 if (freerdp_error_info(instance) == 0)
1400 exit_code = SDL_EXIT_CONN_FAILED;
1403 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
1404 WLog_Print(sdl->log, WLOG_ERROR,
"WaitForMultipleObjects failed with %" PRIu32
"",
1406 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
1407 WLog_Print(sdl->log, WLOG_ERROR,
"Failed to check FreeRDP event handles");
1412 if (exit_code == SDL_EXIT_SUCCESS)
1416 char* emsg =
nullptr;
1418 exit_code = error_info_to_error(instance, &code, &emsg, &elen);
1424 if ((code == ERRINFO_LOGOFF_BY_USER) &&
1425 (freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested))
1427 const char* msg =
"Error info says user did not initiate but disconnect ultimatum says "
1428 "they did; treat this as a user logoff";
1430 char* emsg =
nullptr;
1432 winpr_asprintf(&emsg, &elen,
"%s", msg);
1438 WLog_Print(sdl->log, WLOG_INFO,
"%s", msg);
1439 exit_code = SDL_EXIT_LOGOFF;
1443 freerdp_disconnect(instance);
1451static DWORD WINAPI sdl_client_thread_proc(
SdlContext* sdl)
1455 std::string error_msg;
1456 int exit_code = sdl_client_thread_connect(sdl, error_msg);
1457 if (exit_code == SDL_EXIT_SUCCESS)
1458 exit_code = sdl_client_thread_run(sdl, error_msg);
1459 sdl_client_cleanup(sdl, exit_code, error_msg);
1461 return static_cast<DWORD
>(exit_code);
1467static BOOL sdl_client_global_init()
1471 const DWORD wVersionRequested = MAKEWORD(1, 1);
1472 const int rc = WSAStartup(wVersionRequested, &wsaData);
1475 WLog_ERR(SDL_TAG,
"WSAStartup failed with %s [%d]", gai_strerrorA(rc), rc);
1480 return (freerdp_handle_signals() == 0);
1484static void sdl_client_global_uninit()
1491static BOOL sdl_client_new(freerdp* instance, rdpContext* context)
1495 if (!instance || !context)
1502 instance->PreConnect = sdl_pre_connect;
1503 instance->PostConnect = sdl_post_connect;
1504 instance->PostDisconnect = sdl_post_disconnect;
1505 instance->PostFinalDisconnect = sdl_post_final_disconnect;
1506 instance->AuthenticateEx = sdl_authenticate_ex;
1507 instance->VerifyCertificateEx = sdl_verify_certificate_ex;
1508 instance->VerifyChangedCertificateEx = sdl_verify_changed_certificate_ex;
1509 instance->LogonErrorInfo = sdl_logon_error_info;
1510 instance->PresentGatewayMessage = sdl_present_gateway_message;
1511 instance->ChooseSmartcard = sdl_choose_smartcard;
1512 instance->RetryDialog = sdl_retry_dialog;
1515 instance->GetAccessToken = sdl_webview_get_access_token;
1517 instance->GetAccessToken = client_cli_get_access_token;
1524static void sdl_client_free([[maybe_unused]] freerdp* instance, rdpContext* context)
1534static int sdl_client_start(rdpContext* context)
1536 auto sdl = get_context(context);
1539 sdl->thread = std::thread(sdl_client_thread_proc, sdl);
1543static int sdl_client_stop(rdpContext* context)
1545 auto sdl = get_context(context);
1550 HANDLE
event = freerdp_abort_event(context);
1551 if (!SetEvent(event))
1558static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
1560 WINPR_ASSERT(pEntryPoints);
1562 ZeroMemory(pEntryPoints,
sizeof(RDP_CLIENT_ENTRY_POINTS));
1563 pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
1564 pEntryPoints->Size =
sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
1565 pEntryPoints->GlobalInit = sdl_client_global_init;
1566 pEntryPoints->GlobalUninit = sdl_client_global_uninit;
1568 pEntryPoints->ClientNew = sdl_client_new;
1569 pEntryPoints->ClientFree = sdl_client_free;
1570 pEntryPoints->ClientStart = sdl_client_start;
1571 pEntryPoints->ClientStop = sdl_client_stop;
1578 freerdp_client_context_free(&sdl->common.context);
1581static const char* category2str(
int category)
1585 case SDL_LOG_CATEGORY_APPLICATION:
1586 return "SDL_LOG_CATEGORY_APPLICATION";
1587 case SDL_LOG_CATEGORY_ERROR:
1588 return "SDL_LOG_CATEGORY_ERROR";
1589 case SDL_LOG_CATEGORY_ASSERT:
1590 return "SDL_LOG_CATEGORY_ASSERT";
1591 case SDL_LOG_CATEGORY_SYSTEM:
1592 return "SDL_LOG_CATEGORY_SYSTEM";
1593 case SDL_LOG_CATEGORY_AUDIO:
1594 return "SDL_LOG_CATEGORY_AUDIO";
1595 case SDL_LOG_CATEGORY_VIDEO:
1596 return "SDL_LOG_CATEGORY_VIDEO";
1597 case SDL_LOG_CATEGORY_RENDER:
1598 return "SDL_LOG_CATEGORY_RENDER";
1599 case SDL_LOG_CATEGORY_INPUT:
1600 return "SDL_LOG_CATEGORY_INPUT";
1601 case SDL_LOG_CATEGORY_TEST:
1602 return "SDL_LOG_CATEGORY_TEST";
1603 case SDL_LOG_CATEGORY_GPU:
1604 return "SDL_LOG_CATEGORY_GPU";
1605 case SDL_LOG_CATEGORY_RESERVED2:
1606 return "SDL_LOG_CATEGORY_RESERVED2";
1607 case SDL_LOG_CATEGORY_RESERVED3:
1608 return "SDL_LOG_CATEGORY_RESERVED3";
1609 case SDL_LOG_CATEGORY_RESERVED4:
1610 return "SDL_LOG_CATEGORY_RESERVED4";
1611 case SDL_LOG_CATEGORY_RESERVED5:
1612 return "SDL_LOG_CATEGORY_RESERVED5";
1613 case SDL_LOG_CATEGORY_RESERVED6:
1614 return "SDL_LOG_CATEGORY_RESERVED6";
1615 case SDL_LOG_CATEGORY_RESERVED7:
1616 return "SDL_LOG_CATEGORY_RESERVED7";
1617 case SDL_LOG_CATEGORY_RESERVED8:
1618 return "SDL_LOG_CATEGORY_RESERVED8";
1619 case SDL_LOG_CATEGORY_RESERVED9:
1620 return "SDL_LOG_CATEGORY_RESERVED9";
1621 case SDL_LOG_CATEGORY_RESERVED10:
1622 return "SDL_LOG_CATEGORY_RESERVED10";
1623 case SDL_LOG_CATEGORY_CUSTOM:
1625 return "SDL_LOG_CATEGORY_CUSTOM";
1629static SDL_LogPriority wloglevel2dl(DWORD level)
1634 return SDL_LOG_PRIORITY_VERBOSE;
1636 return SDL_LOG_PRIORITY_DEBUG;
1638 return SDL_LOG_PRIORITY_INFO;
1640 return SDL_LOG_PRIORITY_WARN;
1642 return SDL_LOG_PRIORITY_ERROR;
1644 return SDL_LOG_PRIORITY_CRITICAL;
1647 return SDL_LOG_PRIORITY_VERBOSE;
1651static DWORD sdlpriority2wlog(SDL_LogPriority priority)
1653 DWORD level = WLOG_OFF;
1656 case SDL_LOG_PRIORITY_VERBOSE:
1659 case SDL_LOG_PRIORITY_DEBUG:
1662 case SDL_LOG_PRIORITY_INFO:
1665 case SDL_LOG_PRIORITY_WARN:
1668 case SDL_LOG_PRIORITY_ERROR:
1671 case SDL_LOG_PRIORITY_CRITICAL:
1681static void SDLCALL winpr_LogOutputFunction(
void* userdata,
int category, SDL_LogPriority priority,
1682 const char* message)
1684 auto sdl =
static_cast<SdlContext*
>(userdata);
1687 const DWORD level = sdlpriority2wlog(priority);
1688 auto log = sdl->log;
1689 if (!WLog_IsLevelActive(log, level))
1692 WLog_PrintTextMessage(log, level, __LINE__, __FILE__, __func__,
"[%s] %s",
1693 category2str(category), message);
1696int main(
int argc,
char* argv[])
1700 RDP_CLIENT_ENTRY_POINTS clientEntryPoints = {};
1702 RdpClientEntry(&clientEntryPoints);
1704 reinterpret_cast<sdl_rdp_context*
>(freerdp_client_context_new(&clientEntryPoints)),
1709 auto sdl = sdl_rdp->sdl;
1711 auto settings = sdl->context()->settings;
1712 WINPR_ASSERT(settings);
1714 status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE);
1715 sdl_rdp->sdl->setMetadata();
1718 rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
1720 sdl_list_monitors(sdl);
1725 case COMMAND_LINE_STATUS_PRINT:
1726 case COMMAND_LINE_STATUS_PRINT_VERSION:
1727 case COMMAND_LINE_STATUS_PRINT_BUILDCONFIG:
1729 case COMMAND_LINE_STATUS_PRINT_HELP:
1731 SdlPref::print_config_file_help(3);
1738 SDL_SetLogOutputFunction(winpr_LogOutputFunction, sdl);
1739 auto level = WLog_GetLogLevel(sdl->log);
1740 SDL_SetLogPriorities(wloglevel2dl(level));
1742 auto context = sdl->context();
1743 WINPR_ASSERT(context);
1745 if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CREATE_REQUEST, FALSE))
1748 if (freerdp_client_start(context) != 0)
1753 if (freerdp_client_stop(context) != 0)
1756 if (sdl->exit_code != 0)
1757 rc = sdl->exit_code;
1762bool SdlContext::update_fullscreen(
bool enter)
1764 for (
const auto& window : windows)
1766 if (!sdl_push_user_event(SDL_EVENT_USER_WINDOW_FULLSCREEN, &window.second, enter))
1773bool SdlContext::update_minimize()
1775 return sdl_push_user_event(SDL_EVENT_USER_WINDOW_MINIMIZE);
1778bool SdlContext::update_resizeable(
bool enable)
1780 const auto settings = context()->settings;
1783 bool use = (dyn && enable) || smart;
1785 for (
const auto& window : windows)
1787 if (!sdl_push_user_event(SDL_EVENT_USER_WINDOW_RESIZEABLE, &window.second, use))
1795SdlContext::SdlContext(rdpContext* context)
1796 : _context(context), log(WLog_Get(SDL_TAG)), disp(this), input(this), clip(this),
1797 primary(nullptr, SDL_DestroySurface), rdp_thread_running(false), dialog(log)
1799 WINPR_ASSERT(context);
1803void SdlContext::setHasCursor(
bool val)
1805 this->_cursor_visible = val;
1808bool SdlContext::hasCursor()
const
1810 return _cursor_visible;
1813void SdlContext::setMetadata()
1816 if (!wmclass || (strlen(wmclass) == 0))
1817 wmclass = SDL_CLIENT_UUID;
1819 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING, wmclass);
1820 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING, SDL_CLIENT_NAME);
1821 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_VERSION_STRING, SDL_CLIENT_VERSION);
1822 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_CREATOR_STRING, SDL_CLIENT_VENDOR);
1823 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_COPYRIGHT_STRING, SDL_CLIENT_COPYRIGHT);
1824 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_URL_STRING, SDL_CLIENT_URL);
1825 SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_TYPE_STRING, SDL_CLIENT_TYPE);
1828bool SdlContext::redraw(
bool suppress)
const
1833 auto gdi = context()->gdi;
1835 return gdi_send_suppress_output(gdi, suppress);
1838void SdlContext::setConnected(
bool val)
1843bool SdlContext::isConnected()
const
1848rdpContext* SdlContext::context()
const
1850 WINPR_ASSERT(_context);
1854rdpClientContext* SdlContext::common()
const
1856 return reinterpret_cast<rdpClientContext*
>(context());
1859void SdlContext::setCursor(rdpPointer* cursor)
1864rdpPointer* SdlContext::cursor()
const
1869void SdlContext::setMonitorIds(
const std::vector<SDL_DisplayID>& ids)
1871 _monitorIds.clear();
1874 _monitorIds.push_back(
id);
1878const std::vector<SDL_DisplayID>& SdlContext::monitorIds()
const
1883int64_t SdlContext::monitorId(uint32_t index)
const
1885 if (index >= _monitorIds.size())
1889 return _monitorIds[index];
1892void SdlContext::push(std::vector<SDL_Rect>&& rects)
1894 std::unique_lock lock(_queue_mux);
1895 _queue.emplace(std::move(rects));
1898std::vector<SDL_Rect> SdlContext::pop()
1900 std::unique_lock lock(_queue_mux);
1905 auto val = std::move(_queue.front());
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_server_name(const rdpSettings *settings)
A helper function to return the correct server name.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.