24 #include <freerdp/config.h>
30 #include <freerdp/freerdp.h>
31 #include <freerdp/constants.h>
32 #include <freerdp/gdi/gdi.h>
33 #include <freerdp/streamdump.h>
34 #include <freerdp/utils/signal.h>
36 #include <freerdp/client/file.h>
37 #include <freerdp/client/cmdline.h>
38 #include <freerdp/client/cliprdr.h>
39 #include <freerdp/client/channels.h>
40 #include <freerdp/channels/channels.h>
42 #include <winpr/crt.h>
43 #include <winpr/config.h>
44 #include <winpr/assert.h>
45 #include <winpr/synch.h>
46 #include <freerdp/log.h>
49 #include <SDL_hints.h>
50 #include <SDL_video.h>
52 #include "sdl_channels.hpp"
53 #include "sdl_freerdp.hpp"
54 #include "sdl_utils.hpp"
55 #include "sdl_disp.hpp"
56 #include "sdl_monitor.hpp"
57 #include "sdl_kbd.hpp"
58 #include "sdl_touch.hpp"
59 #include "sdl_pointer.hpp"
60 #include "sdl_prefs.hpp"
61 #include "dialogs/sdl_dialogs.hpp"
62 #include "scoped_guard.hpp"
64 #include <aad/sdl_webview.hpp>
66 #define SDL_TAG CLIENT_TAG("SDL")
72 SDL_EXIT_DISCONNECT = 1,
74 SDL_EXIT_IDLE_TIMEOUT = 3,
75 SDL_EXIT_LOGON_TIMEOUT = 4,
76 SDL_EXIT_CONN_REPLACED = 5,
77 SDL_EXIT_OUT_OF_MEMORY = 6,
78 SDL_EXIT_CONN_DENIED = 7,
79 SDL_EXIT_CONN_DENIED_FIPS = 8,
80 SDL_EXIT_USER_PRIVILEGES = 9,
81 SDL_EXIT_FRESH_CREDENTIALS_REQUIRED = 10,
82 SDL_EXIT_DISCONNECT_BY_USER = 11,
85 SDL_EXIT_LICENSE_INTERNAL = 16,
86 SDL_EXIT_LICENSE_NO_LICENSE_SERVER = 17,
87 SDL_EXIT_LICENSE_NO_LICENSE = 18,
88 SDL_EXIT_LICENSE_BAD_CLIENT_MSG = 19,
89 SDL_EXIT_LICENSE_HWID_DOESNT_MATCH = 20,
90 SDL_EXIT_LICENSE_BAD_CLIENT = 21,
91 SDL_EXIT_LICENSE_CANT_FINISH_PROTOCOL = 22,
92 SDL_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL = 23,
93 SDL_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION = 24,
94 SDL_EXIT_LICENSE_CANT_UPGRADE = 25,
95 SDL_EXIT_LICENSE_NO_REMOTE_CONNECTIONS = 26,
101 SDL_EXIT_PARSE_ARGUMENTS = 128,
102 SDL_EXIT_MEMORY = 129,
103 SDL_EXIT_PROTOCOL = 130,
104 SDL_EXIT_CONN_FAILED = 131,
105 SDL_EXIT_AUTH_FAILURE = 132,
106 SDL_EXIT_NEGO_FAILURE = 133,
107 SDL_EXIT_LOGON_FAILURE = 134,
108 SDL_EXIT_ACCOUNT_LOCKED_OUT = 135,
109 SDL_EXIT_PRE_CONNECT_FAILED = 136,
110 SDL_EXIT_CONNECT_UNDEFINED = 137,
111 SDL_EXIT_POST_CONNECT_FAILED = 138,
112 SDL_EXIT_DNS_ERROR = 139,
113 SDL_EXIT_DNS_NAME_NOT_FOUND = 140,
114 SDL_EXIT_CONNECT_FAILED = 141,
115 SDL_EXIT_MCS_CONNECT_INITIAL_ERROR = 142,
116 SDL_EXIT_TLS_CONNECT_FAILED = 143,
117 SDL_EXIT_INSUFFICIENT_PRIVILEGES = 144,
118 SDL_EXIT_CONNECT_CANCELLED = 145,
120 SDL_EXIT_CONNECT_TRANSPORT_FAILED = 147,
121 SDL_EXIT_CONNECT_PASSWORD_EXPIRED = 148,
122 SDL_EXIT_CONNECT_PASSWORD_MUST_CHANGE = 149,
123 SDL_EXIT_CONNECT_KDC_UNREACHABLE = 150,
124 SDL_EXIT_CONNECT_ACCOUNT_DISABLED = 151,
125 SDL_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED = 152,
126 SDL_EXIT_CONNECT_CLIENT_REVOKED = 153,
127 SDL_EXIT_CONNECT_WRONG_PASSWORD = 154,
128 SDL_EXIT_CONNECT_ACCESS_DENIED = 155,
129 SDL_EXIT_CONNECT_ACCOUNT_RESTRICTION = 156,
130 SDL_EXIT_CONNECT_ACCOUNT_EXPIRED = 157,
131 SDL_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED = 158,
132 SDL_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS = 159,
134 SDL_EXIT_UNKNOWN = 255,
137 struct sdl_exit_code_map_t
141 const char* code_tag;
144 #define ENTRY(x, y) \
148 static const struct sdl_exit_code_map_t sdl_exit_code_map[] = {
149 ENTRY(FREERDP_ERROR_SUCCESS, SDL_EXIT_SUCCESS), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_DISCONNECT),
150 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LOGOFF), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_IDLE_TIMEOUT),
151 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LOGON_TIMEOUT),
152 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_REPLACED),
153 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_OUT_OF_MEMORY),
154 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_DENIED),
155 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_DENIED_FIPS),
156 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_USER_PRIVILEGES),
157 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_FRESH_CREDENTIALS_REQUIRED),
158 ENTRY(ERRINFO_LOGOFF_BY_USER, SDL_EXIT_DISCONNECT_BY_USER),
159 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_UNKNOWN),
162 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_INTERNAL),
163 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_LICENSE_SERVER),
164 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_LICENSE),
165 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT_MSG),
166 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_HWID_DOESNT_MATCH),
167 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT),
168 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_FINISH_PROTOCOL),
169 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL),
170 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION),
171 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_UPGRADE),
172 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_REMOTE_CONNECTIONS),
173 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_UPGRADE),
176 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_RDP),
179 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_PARSE_ARGUMENTS), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_MEMORY),
180 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_PROTOCOL), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_FAILED),
182 ENTRY(FREERDP_ERROR_AUTHENTICATION_FAILED, SDL_EXIT_AUTH_FAILURE),
183 ENTRY(FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED, SDL_EXIT_NEGO_FAILURE),
184 ENTRY(FREERDP_ERROR_CONNECT_LOGON_FAILURE, SDL_EXIT_LOGON_FAILURE),
185 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT, SDL_EXIT_ACCOUNT_LOCKED_OUT),
186 ENTRY(FREERDP_ERROR_PRE_CONNECT_FAILED, SDL_EXIT_PRE_CONNECT_FAILED),
187 ENTRY(FREERDP_ERROR_CONNECT_UNDEFINED, SDL_EXIT_CONNECT_UNDEFINED),
188 ENTRY(FREERDP_ERROR_POST_CONNECT_FAILED, SDL_EXIT_POST_CONNECT_FAILED),
189 ENTRY(FREERDP_ERROR_DNS_ERROR, SDL_EXIT_DNS_ERROR),
190 ENTRY(FREERDP_ERROR_DNS_NAME_NOT_FOUND, SDL_EXIT_DNS_NAME_NOT_FOUND),
191 ENTRY(FREERDP_ERROR_CONNECT_FAILED, SDL_EXIT_CONNECT_FAILED),
192 ENTRY(FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR, SDL_EXIT_MCS_CONNECT_INITIAL_ERROR),
193 ENTRY(FREERDP_ERROR_TLS_CONNECT_FAILED, SDL_EXIT_TLS_CONNECT_FAILED),
194 ENTRY(FREERDP_ERROR_INSUFFICIENT_PRIVILEGES, SDL_EXIT_INSUFFICIENT_PRIVILEGES),
195 ENTRY(FREERDP_ERROR_CONNECT_CANCELLED, SDL_EXIT_CONNECT_CANCELLED),
196 ENTRY(FREERDP_ERROR_CONNECT_TRANSPORT_FAILED, SDL_EXIT_CONNECT_TRANSPORT_FAILED),
197 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED, SDL_EXIT_CONNECT_PASSWORD_EXPIRED),
198 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE, SDL_EXIT_CONNECT_PASSWORD_MUST_CHANGE),
199 ENTRY(FREERDP_ERROR_CONNECT_KDC_UNREACHABLE, SDL_EXIT_CONNECT_KDC_UNREACHABLE),
200 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED, SDL_EXIT_CONNECT_ACCOUNT_DISABLED),
201 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED,
202 SDL_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED),
203 ENTRY(FREERDP_ERROR_CONNECT_CLIENT_REVOKED, SDL_EXIT_CONNECT_CLIENT_REVOKED),
204 ENTRY(FREERDP_ERROR_CONNECT_WRONG_PASSWORD, SDL_EXIT_CONNECT_WRONG_PASSWORD),
205 ENTRY(FREERDP_ERROR_CONNECT_ACCESS_DENIED, SDL_EXIT_CONNECT_ACCESS_DENIED),
206 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION, SDL_EXIT_CONNECT_ACCOUNT_RESTRICTION),
207 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED, SDL_EXIT_CONNECT_ACCOUNT_EXPIRED),
208 ENTRY(FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED, SDL_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED),
209 ENTRY(FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS,
210 SDL_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS)
213 static const struct sdl_exit_code_map_t* sdl_map_entry_by_code(
int exit_code)
215 for (
const auto& x : sdl_exit_code_map)
217 const struct sdl_exit_code_map_t* cur = &x;
218 if (cur->code == exit_code)
224 static void sdl_hide_connection_dialog(
SdlContext* sdl)
227 std::lock_guard<CriticalSection> lock(sdl->critical);
228 if (sdl->connection_dialog)
229 sdl->connection_dialog->hide();
232 static const struct sdl_exit_code_map_t* sdl_map_entry_by_error(DWORD 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)
243 static 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;
252 static const char* sdl_map_error_to_code_tag(DWORD error)
254 const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_error(error);
256 return entry->code_tag;
260 static 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;
268 static 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(exit_code), name, code, str);
277 WLog_DBG(SDL_TAG,
"%s", *msg);
285 static BOOL sdl_begin_paint(rdpContext* context)
287 rdpGdi* gdi =
nullptr;
288 auto sdl = get_context(context);
292 HANDLE handles[] = { sdl->update_complete.handle(), freerdp_abort_event(context) };
293 const DWORD status = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
301 sdl->update_complete.clear();
305 WINPR_ASSERT(gdi->primary);
306 WINPR_ASSERT(gdi->primary->hdc);
307 WINPR_ASSERT(gdi->primary->hdc->hwnd);
308 WINPR_ASSERT(gdi->primary->hdc->hwnd->invalid);
309 gdi->primary->hdc->hwnd->invalid->null = TRUE;
310 gdi->primary->hdc->hwnd->ninvalid = 0;
319 auto gdi = sdl->context()->gdi;
320 return gdi_send_suppress_output(gdi, FALSE);
323 class SdlEventUpdateTriggerGuard
329 explicit SdlEventUpdateTriggerGuard(
SdlContext* sdl) : _sdl(sdl)
332 ~SdlEventUpdateTriggerGuard()
334 _sdl->update_complete.set();
336 SdlEventUpdateTriggerGuard(
const SdlEventUpdateTriggerGuard&) =
delete;
337 SdlEventUpdateTriggerGuard(SdlEventUpdateTriggerGuard&&) =
delete;
338 SdlEventUpdateTriggerGuard& operator=(
const SdlEventUpdateTriggerGuard&) =
delete;
339 SdlEventUpdateTriggerGuard& operator=(SdlEventUpdateTriggerGuard&&) =
delete;
342 static bool sdl_draw_to_window_rect(
SdlContext* sdl,
SdlWindow& window, SDL_Surface* surface,
343 SDL_Point offset, SDL_Rect srcRect)
345 SDL_Rect dstRect = { offset.x + srcRect.x, offset.y + srcRect.y, srcRect.w, srcRect.h };
346 return window.blit(surface, srcRect, dstRect);
349 static bool sdl_draw_to_window_rect(
SdlContext* sdl,
SdlWindow& window, SDL_Surface* surface,
350 SDL_Point offset,
const std::vector<SDL_Rect>& rects = {})
354 return sdl_draw_to_window_rect(sdl, window, surface, offset,
355 { 0, 0, surface->w, surface->h });
357 for (
auto& srcRect : rects)
359 if (!sdl_draw_to_window_rect(sdl, window, surface, offset, srcRect))
365 static bool sdl_draw_to_window_scaled_rect(
SdlContext* sdl,
SdlWindow& window, SDL_Surface* surface,
368 SDL_Rect dstRect = srcRect;
369 sdl_scale_coordinates(sdl, window.id(), &dstRect.x, &dstRect.y, FALSE, TRUE);
370 sdl_scale_coordinates(sdl, window.id(), &dstRect.w, &dstRect.h, FALSE, TRUE);
371 return window.blit(surface, srcRect, dstRect);
374 static BOOL sdl_draw_to_window_scaled_rect(
SdlContext* sdl,
SdlWindow& window, SDL_Surface* surface,
375 const std::vector<SDL_Rect>& rects = {})
379 return sdl_draw_to_window_scaled_rect(sdl, window, surface,
380 { 0, 0, surface->w, surface->h });
382 for (
const auto& srcRect : rects)
384 if (!sdl_draw_to_window_scaled_rect(sdl, window, surface, srcRect))
391 const std::vector<SDL_Rect>& rects = {})
395 auto context = sdl->context();
396 auto gdi = context->gdi;
398 auto size = window.rect();
402 if (gdi->width < size.w)
404 window.setOffsetX((size.w - gdi->width) / 2);
406 if (gdi->height < size.h)
408 window.setOffsetY((size.h - gdi->height) / 2);
411 auto surface = sdl->primary.get();
412 if (!sdl_draw_to_window_rect(sdl, window, surface, { window.offsetX(), window.offsetY() },
418 if (!sdl_draw_to_window_scaled_rect(sdl, window, sdl->primary.get(), rects))
421 window.updateSurface();
425 static BOOL sdl_draw_to_window(
SdlContext* sdl, std::map<Uint32, SdlWindow>& windows,
426 const std::vector<SDL_Rect>& rects = {})
428 for (
auto& window : windows)
430 if (!sdl_draw_to_window(sdl, window.second, rects))
437 static BOOL sdl_end_paint_process(rdpContext* context)
439 rdpGdi* gdi =
nullptr;
440 auto sdl = get_context(context);
442 WINPR_ASSERT(context);
444 SdlEventUpdateTriggerGuard guard(sdl);
448 WINPR_ASSERT(gdi->primary);
449 WINPR_ASSERT(gdi->primary->hdc);
450 WINPR_ASSERT(gdi->primary->hdc->hwnd);
451 WINPR_ASSERT(gdi->primary->hdc->hwnd->invalid);
452 if (gdi->suppressOutput || gdi->primary->hdc->hwnd->invalid->null)
455 const INT32 ninvalid = gdi->primary->hdc->hwnd->ninvalid;
456 const GDI_RGN* cinvalid = gdi->primary->hdc->hwnd->cinvalid;
461 std::vector<SDL_Rect> rects;
462 for (INT32 x = 0; x < ninvalid; x++)
464 auto& rgn = cinvalid[x];
465 rects.push_back({ rgn.x, rgn.y, rgn.w, rgn.h });
468 return sdl_draw_to_window(sdl, sdl->windows, rects);
475 static BOOL sdl_end_paint(rdpContext* context)
477 auto sdl = get_context(context);
480 std::lock_guard<CriticalSection> lock(sdl->critical);
481 const BOOL rc = sdl_push_user_event(SDL_USEREVENT_UPDATE, context);
486 static void sdl_destroy_primary(
SdlContext* sdl)
490 sdl->primary.reset();
491 sdl->primary_format.reset();
495 static BOOL sdl_create_primary(
SdlContext* sdl)
497 rdpGdi* gdi =
nullptr;
501 gdi = sdl->context()->gdi;
504 sdl_destroy_primary(sdl);
505 sdl->primary = SDLSurfacePtr(
506 SDL_CreateRGBSurfaceWithFormatFrom(gdi->primary_buffer,
static_cast<int>(gdi->width),
507 static_cast<int>(gdi->height),
508 static_cast<int>(FreeRDPGetBitsPerPixel(gdi->dstFormat)),
509 static_cast<int>(gdi->stride), sdl->sdl_pixel_format),
511 sdl->primary_format = SDLPixelFormatPtr(SDL_AllocFormat(sdl->sdl_pixel_format), SDL_FreeFormat);
513 if (!sdl->primary || !sdl->primary_format)
516 SDL_SetSurfaceBlendMode(sdl->primary.get(), SDL_BLENDMODE_NONE);
517 SDL_FillRect(sdl->primary.get(),
nullptr,
518 SDL_MapRGBA(sdl->primary_format.get(), 0, 0, 0, 0xff));
523 static BOOL sdl_desktop_resize(rdpContext* context)
525 rdpGdi* gdi =
nullptr;
526 rdpSettings* settings =
nullptr;
527 auto sdl = get_context(context);
530 WINPR_ASSERT(context);
532 settings = context->settings;
533 WINPR_ASSERT(settings);
535 std::lock_guard<CriticalSection> lock(sdl->critical);
540 return sdl_create_primary(sdl);
544 static BOOL sdl_play_sound(rdpContext* context,
const PLAY_SOUND_UPDATE* play_sound)
547 WINPR_UNUSED(context);
548 WINPR_UNUSED(play_sound);
552 static BOOL sdl_wait_for_init(
SdlContext* sdl)
555 sdl->initialize.set();
557 HANDLE handles[] = { sdl->initialized.handle(), freerdp_abort_event(sdl->context()) };
559 const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
571 static BOOL sdl_pre_connect(freerdp* instance)
573 WINPR_ASSERT(instance);
574 WINPR_ASSERT(instance->context);
576 auto sdl = get_context(instance->context);
578 auto settings = instance->context->settings;
579 WINPR_ASSERT(settings);
594 PubSub_SubscribeChannelConnected(instance->context->pubSub, sdl_OnChannelConnectedEventHandler);
595 PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
596 sdl_OnChannelDisconnectedEventHandler);
601 UINT32 maxHeight = 0;
603 if (!sdl_wait_for_init(sdl))
606 std::lock_guard<CriticalSection> lock(sdl->critical);
608 sdl->connection_dialog = std::make_unique<SDLConnectionDialog>(instance->context);
609 if (sdl->connection_dialog)
611 sdl->connection_dialog->setTitle(
"Connecting to '%s'",
613 sdl->connection_dialog->showInfo(
614 "The connection is being established\n\nPlease wait...");
616 if (!sdl_detect_monitors(sdl, &maxWidth, &maxHeight))
619 if ((maxWidth != 0) && (maxHeight != 0) &&
622 WLog_Print(sdl->log, WLOG_INFO,
"Update size to %ux%u", maxWidth, maxHeight);
634 WLog_Print(sdl->log, WLOG_INFO,
"auth-only, but no password set. Please provide one.");
641 WLog_Print(sdl->log, WLOG_INFO,
"Authentication only. Don't connect SDL.");
648 static const char* sdl_window_get_title(rdpSettings* settings)
650 const char* windowTitle =
nullptr;
653 const char* name =
nullptr;
654 const char* prefix =
"FreeRDP:";
666 addPort = (port != 3389);
668 char buffer[MAX_PATH + 64] = {};
671 (void)sprintf_s(buffer,
sizeof(buffer),
"%s %s", prefix, name);
673 (
void)sprintf_s(buffer,
sizeof(buffer),
"%s %s:%" PRIu32, prefix, name, port);
680 static void sdl_term_handler(
int signum,
const char* signame,
void* context)
690 std::lock_guard<CriticalSection> lock(sdl->critical);
691 sdl->windows.clear();
692 sdl->connection_dialog.reset();
694 sdl_destroy_primary(sdl);
696 freerdp_del_signal_cleanup_handler(sdl->context(), sdl_term_handler);
701 static BOOL sdl_create_windows(
SdlContext* sdl)
705 auto settings = sdl->context()->settings;
706 auto title = sdl_window_get_title(settings);
710 for (UINT32 x = 0; x < windowCount; x++)
712 auto id = sdl_monitor_id_for_index(sdl, x);
716 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x));
718 Uint32 w = monitor->width;
719 Uint32 h = monitor->height;
727 Uint32 flags = SDL_WINDOW_SHOWN;
728 auto startupX = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
729 auto startupY = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
731 if (monitor->attributes.desktopScaleFactor > 100)
733 #if SDL_VERSION_ATLEAST(2, 0, 1)
734 flags |= SDL_WINDOW_ALLOW_HIGHDPI;
741 flags |= SDL_WINDOW_FULLSCREEN;
746 flags |= SDL_WINDOW_BORDERLESS;
750 flags |= SDL_WINDOW_BORDERLESS;
753 static_cast<int>(startupX),
754 static_cast<int>(startupY),
759 ScopeGuard guard([&]() { sdl->windows_created.set(); });
761 if (!window.window())
766 auto r = window.rect();
767 window.setOffsetX(0 - r.x);
768 window.setOffsetY(0 - r.y);
771 sdl->windows.insert({ window.id(), std::move(window) });
777 static BOOL sdl_wait_create_windows(
SdlContext* sdl)
779 std::lock_guard<CriticalSection> lock(sdl->critical);
780 sdl->windows_created.clear();
781 if (!sdl_push_user_event(SDL_USEREVENT_CREATE_WINDOWS, sdl))
784 HANDLE handles[] = { sdl->initialized.handle(), freerdp_abort_event(sdl->context()) };
786 const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
798 std::lock_guard<CriticalSection> lock(sdl->critical);
799 if (freerdp_shall_disconnect_context(sdl->context()))
801 if (sdl->rdp_thread_running)
803 if (!sdl->connection_dialog)
805 return !sdl->connection_dialog->running();
815 HANDLE handles[] = { sdl->initialize.handle(), freerdp_abort_event(sdl->context()) };
816 const DWORD status = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
825 SDL_Init(SDL_INIT_VIDEO);
827 #if SDL_VERSION_ATLEAST(2, 0, 16)
828 SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED,
"0");
830 #if SDL_VERSION_ATLEAST(2, 0, 8)
831 SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,
"0");
834 freerdp_add_signal_cleanup_handler(sdl->context(), sdl_term_handler);
836 sdl->initialized.set();
838 while (!shall_abort(sdl))
840 SDL_Event windowEvent = {};
841 while (!shall_abort(sdl) && SDL_WaitEventTimeout(
nullptr, 1000))
846 const int prc = SDL_PeepEvents(&windowEvent, 1, SDL_GETEVENT, SDL_FIRSTEVENT,
847 SDL_USEREVENT_RETRY_DIALOG);
850 if (sdl_log_error(prc, sdl->log,
"SDL_PeepEvents"))
854 #if defined(WITH_DEBUG_SDL_EVENTS)
855 SDL_Log(
"got event %s [0x%08" PRIx32
"]", sdl_event_type_str(windowEvent.type),
858 std::lock_guard<CriticalSection> lock(sdl->critical);
861 if (freerdp_shall_disconnect_context(sdl->context()))
864 if (sdl->connection_dialog)
866 if (sdl->connection_dialog->handle(windowEvent))
872 switch (windowEvent.type)
875 freerdp_abort_connect_context(sdl->context());
880 const SDL_KeyboardEvent* ev = &windowEvent.key;
881 sdl->input.keyboard_handle_event(ev);
884 case SDL_KEYMAPCHANGED:
888 case SDL_MOUSEMOTION:
890 const SDL_MouseMotionEvent* ev = &windowEvent.motion;
891 sdl_handle_mouse_motion(sdl, ev);
894 case SDL_MOUSEBUTTONDOWN:
895 case SDL_MOUSEBUTTONUP:
897 const SDL_MouseButtonEvent* ev = &windowEvent.button;
898 sdl_handle_mouse_button(sdl, ev);
903 const SDL_MouseWheelEvent* ev = &windowEvent.wheel;
904 sdl_handle_mouse_wheel(sdl, ev);
909 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
910 sdl_handle_touch_down(sdl, ev);
915 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
916 sdl_handle_touch_up(sdl, ev);
919 case SDL_FINGERMOTION:
921 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
922 sdl_handle_touch_motion(sdl, ev);
925 #if SDL_VERSION_ATLEAST(2, 0, 10)
926 case SDL_DISPLAYEVENT:
928 const SDL_DisplayEvent* ev = &windowEvent.display;
929 sdl->disp.handle_display_event(ev);
933 case SDL_WINDOWEVENT:
935 const SDL_WindowEvent* ev = &windowEvent.window;
936 auto window = sdl->windows.find(ev->windowID);
937 if (window != sdl->windows.end())
938 sdl->disp.handle_window_event(ev);
941 case SDL_WINDOWEVENT_RESIZED:
942 case SDL_WINDOWEVENT_SIZE_CHANGED:
944 if (window != sdl->windows.end())
946 window->second.fill();
947 window->second.updateSurface();
951 case SDL_WINDOWEVENT_MOVED:
953 if (window != sdl->windows.end())
955 auto r = window->second.rect();
956 auto id = window->second.id();
957 WLog_DBG(SDL_TAG,
"%lu: %dx%d-%dx%d",
id, r.x, r.y, r.w, r.h);
967 case SDL_RENDER_TARGETS_RESET:
970 case SDL_RENDER_DEVICE_RESET:
973 case SDL_APP_WILLENTERFOREGROUND:
976 case SDL_USEREVENT_CERT_DIALOG:
978 auto title =
static_cast<const char*
>(windowEvent.user.data1);
979 auto msg =
static_cast<const char*
>(windowEvent.user.data2);
980 sdl_cert_dialog_show(title, msg);
983 case SDL_USEREVENT_SHOW_DIALOG:
985 auto title =
static_cast<const char*
>(windowEvent.user.data1);
986 auto msg =
static_cast<const char*
>(windowEvent.user.data2);
987 sdl_message_dialog_show(title, msg, windowEvent.user.code);
990 case SDL_USEREVENT_SCARD_DIALOG:
992 auto title =
static_cast<const char*
>(windowEvent.user.data1);
993 auto msg =
static_cast<const char**
>(windowEvent.user.data2);
994 sdl_scard_dialog_show(title, windowEvent.user.code, msg);
997 case SDL_USEREVENT_AUTH_DIALOG:
998 sdl_auth_dialog_show(
1001 case SDL_USEREVENT_UPDATE:
1003 auto context =
static_cast<rdpContext*
>(windowEvent.user.data1);
1004 sdl_end_paint_process(context);
1007 case SDL_USEREVENT_CREATE_WINDOWS:
1009 auto ctx =
static_cast<SdlContext*
>(windowEvent.user.data1);
1010 sdl_create_windows(ctx);
1013 case SDL_USEREVENT_WINDOW_RESIZEABLE:
1015 auto window =
static_cast<SdlWindow*
>(windowEvent.user.data1);
1016 const SDL_bool use = windowEvent.user.code != 0 ? SDL_TRUE : SDL_FALSE;
1018 window->resizeable(use);
1021 case SDL_USEREVENT_WINDOW_FULLSCREEN:
1023 auto window =
static_cast<SdlWindow*
>(windowEvent.user.data1);
1024 const SDL_bool enter = windowEvent.user.code != 0 ? SDL_TRUE : SDL_FALSE;
1026 window->fullscreen(enter);
1029 case SDL_USEREVENT_WINDOW_MINIMIZE:
1031 for (
auto& window : sdl->windows)
1033 window.second.minimize();
1037 case SDL_USEREVENT_POINTER_NULL:
1038 SDL_ShowCursor(SDL_DISABLE);
1040 case SDL_USEREVENT_POINTER_DEFAULT:
1042 SDL_Cursor* def = SDL_GetDefaultCursor();
1044 SDL_ShowCursor(SDL_ENABLE);
1047 case SDL_USEREVENT_POINTER_POSITION:
1050 static_cast<INT32
>(
reinterpret_cast<uintptr_t
>(windowEvent.user.data1));
1052 static_cast<INT32
>(
reinterpret_cast<uintptr_t
>(windowEvent.user.data2));
1054 SDL_Window* window = SDL_GetMouseFocus();
1057 const Uint32
id = SDL_GetWindowID(window);
1061 if (sdl_scale_coordinates(sdl,
id, &sx, &sy, FALSE, FALSE))
1062 SDL_WarpMouseInWindow(window, sx, sy);
1066 case SDL_USEREVENT_POINTER_SET:
1067 sdl_Pointer_Set_Process(&windowEvent.user);
1069 case SDL_USEREVENT_QUIT:
1078 sdl_cleanup_sdl(sdl);
1090 static BOOL sdl_post_connect(freerdp* instance)
1092 WINPR_ASSERT(instance);
1094 auto context = instance->context;
1095 WINPR_ASSERT(context);
1097 auto sdl = get_context(context);
1100 sdl_hide_connection_dialog(sdl);
1107 WLog_Print(sdl->log, WLOG_INFO,
"auth-only, but no password set. Please provide one.");
1111 WLog_Print(sdl->log, WLOG_INFO,
"Authentication only. Don't connect to X.");
1115 if (!sdl_wait_create_windows(sdl))
1118 sdl->sdl_pixel_format = SDL_PIXELFORMAT_BGRA32;
1119 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
1122 if (!sdl_create_primary(sdl))
1125 if (!sdl_register_pointer(instance->context->graphics))
1128 WINPR_ASSERT(context->update);
1130 context->update->BeginPaint = sdl_begin_paint;
1131 context->update->EndPaint = sdl_end_paint;
1132 context->update->PlaySound = sdl_play_sound;
1133 context->update->DesktopResize = sdl_desktop_resize;
1134 context->update->SetKeyboardIndicators = sdlInput::keyboard_set_indicators;
1135 context->update->SetKeyboardImeStatus = sdlInput::keyboard_set_ime_status;
1137 sdl->update_resizeable(FALSE);
1146 static void sdl_post_disconnect(freerdp* instance)
1151 if (!instance->context)
1154 PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
1155 sdl_OnChannelConnectedEventHandler);
1156 PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
1157 sdl_OnChannelDisconnectedEventHandler);
1161 static void sdl_post_final_disconnect(freerdp* instance)
1166 if (!instance->context)
1170 static void sdl_client_cleanup(
SdlContext* sdl,
int exit_code,
const std::string& error_msg)
1174 rdpContext* context = sdl->context();
1175 WINPR_ASSERT(context);
1177 rdpSettings* settings = context->settings;
1178 WINPR_ASSERT(settings);
1180 sdl->rdp_thread_running =
false;
1181 bool showError =
false;
1183 WLog_Print(sdl->log, WLOG_INFO,
"Authentication only, exit status %s [%" PRId32
"]",
1184 sdl_map_to_code_tag(exit_code), exit_code);
1189 case SDL_EXIT_SUCCESS:
1190 case SDL_EXIT_DISCONNECT:
1191 case SDL_EXIT_LOGOFF:
1192 case SDL_EXIT_DISCONNECT_BY_USER:
1193 case SDL_EXIT_CONNECT_CANCELLED:
1197 std::lock_guard<CriticalSection> lock(sdl->critical);
1198 if (sdl->connection_dialog && !error_msg.empty())
1200 sdl->connection_dialog->showError(error_msg.c_str());
1209 sdl_hide_connection_dialog(sdl);
1211 sdl->exit_code = exit_code;
1212 sdl_push_user_event(SDL_USEREVENT_QUIT);
1213 #if SDL_VERSION_ATLEAST(2, 0, 16)
1218 static int sdl_client_thread_connect(
SdlContext* sdl, std::string& error_msg)
1222 auto instance = sdl->context()->instance;
1223 WINPR_ASSERT(instance);
1225 sdl->rdp_thread_running =
true;
1226 BOOL rc = freerdp_connect(instance);
1228 rdpContext* context = sdl->context();
1229 WINPR_ASSERT(context);
1231 rdpSettings* settings = context->settings;
1232 WINPR_ASSERT(settings);
1234 int exit_code = SDL_EXIT_SUCCESS;
1237 UINT32 error = freerdp_get_last_error(context);
1238 exit_code = sdl_map_error_to_exit_code(error);
1243 DWORD code = freerdp_get_last_error(context);
1244 freerdp_abort_connect_context(context);
1245 WLog_Print(sdl->log, WLOG_ERROR,
"Authentication only, %s [0x%08" PRIx32
"] %s",
1246 freerdp_get_last_error_name(code), code, freerdp_get_last_error_string(code));
1252 DWORD code = freerdp_error_info(instance);
1253 if (exit_code == SDL_EXIT_SUCCESS)
1255 char* msg =
nullptr;
1257 exit_code = error_info_to_error(instance, &code, &msg, &len);
1263 auto last = freerdp_get_last_error(context);
1264 if (error_msg.empty())
1266 char* msg =
nullptr;
1268 winpr_asprintf(&msg, &len,
"%s [0x%08" PRIx32
"]\n%s",
1269 freerdp_get_last_error_name(last), last,
1270 freerdp_get_last_error_string(last));
1276 if (exit_code == SDL_EXIT_SUCCESS)
1278 if (last == FREERDP_ERROR_AUTHENTICATION_FAILED)
1279 exit_code = SDL_EXIT_AUTH_FAILURE;
1280 else if (code == ERRINFO_SUCCESS)
1281 exit_code = SDL_EXIT_CONN_FAILED;
1284 sdl_hide_connection_dialog(sdl);
1289 static int sdl_client_thread_run(
SdlContext* sdl, std::string& error_msg)
1293 auto context = sdl->context();
1294 WINPR_ASSERT(context);
1296 auto instance = context->instance;
1297 WINPR_ASSERT(instance);
1299 int exit_code = SDL_EXIT_SUCCESS;
1300 while (!freerdp_shall_disconnect_context(context))
1302 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {};
1308 if (freerdp_focus_required(instance))
1310 auto ctx = get_context(context);
1312 if (!ctx->input.keyboard_focus_in())
1314 if (!ctx->input.keyboard_focus_in())
1318 const DWORD nCount = freerdp_get_event_handles(context, handles, ARRAYSIZE(handles));
1322 WLog_Print(sdl->log, WLOG_ERROR,
"freerdp_get_event_handles failed");
1326 const DWORD status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
1328 if (status == WAIT_FAILED)
1331 if (!freerdp_check_event_handles(context))
1333 if (client_auto_reconnect(instance))
1336 sdl_hide_connection_dialog(sdl);
1345 if (freerdp_error_info(instance) == 0)
1346 exit_code = SDL_EXIT_CONN_FAILED;
1349 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
1350 WLog_Print(sdl->log, WLOG_ERROR,
"WaitForMultipleObjects failed with %" PRIu32
"",
1352 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
1353 WLog_Print(sdl->log, WLOG_ERROR,
"Failed to check FreeRDP event handles");
1358 if (exit_code == SDL_EXIT_SUCCESS)
1362 char* msg =
nullptr;
1364 exit_code = error_info_to_error(instance, &code, &msg, &len);
1370 if ((code == ERRINFO_LOGOFF_BY_USER) &&
1371 (freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested))
1373 const char* msg =
"Error info says user did not initiate but disconnect ultimatum says "
1374 "they did; treat this as a user logoff";
1375 char* emsg =
nullptr;
1377 winpr_asprintf(&emsg, &len,
"%s", msg);
1382 WLog_Print(sdl->log, WLOG_INFO,
"%s", msg);
1383 exit_code = SDL_EXIT_LOGOFF;
1387 freerdp_disconnect(instance);
1394 static DWORD WINAPI sdl_client_thread_proc(
SdlContext* sdl)
1398 std::string error_msg;
1399 int exit_code = sdl_client_thread_connect(sdl, error_msg);
1400 if (exit_code == SDL_EXIT_SUCCESS)
1401 exit_code = sdl_client_thread_run(sdl, error_msg);
1402 sdl_client_cleanup(sdl, exit_code, error_msg);
1404 return static_cast<DWORD
>(exit_code);
1410 static BOOL sdl_client_global_init()
1414 const DWORD wVersionRequested = MAKEWORD(1, 1);
1415 const int rc = WSAStartup(wVersionRequested, &wsaData);
1418 WLog_ERR(SDL_TAG,
"WSAStartup failed with %s [%d]", gai_strerrorA(rc), rc);
1423 if (freerdp_handle_signals() != 0)
1430 static void sdl_client_global_uninit()
1437 static BOOL sdl_client_new(freerdp* instance, rdpContext* context)
1441 if (!instance || !context)
1448 instance->PreConnect = sdl_pre_connect;
1449 instance->PostConnect = sdl_post_connect;
1450 instance->PostDisconnect = sdl_post_disconnect;
1451 instance->PostFinalDisconnect = sdl_post_final_disconnect;
1452 instance->AuthenticateEx = sdl_authenticate_ex;
1453 instance->VerifyCertificateEx = sdl_verify_certificate_ex;
1454 instance->VerifyChangedCertificateEx = sdl_verify_changed_certificate_ex;
1455 instance->LogonErrorInfo = sdl_logon_error_info;
1456 instance->PresentGatewayMessage = sdl_present_gateway_message;
1457 instance->ChooseSmartcard = sdl_choose_smartcard;
1458 instance->RetryDialog = sdl_retry_dialog;
1461 instance->GetAccessToken = sdl_webview_get_access_token;
1463 instance->GetAccessToken = client_cli_get_access_token;
1470 static void sdl_client_free(freerdp* instance, rdpContext* context)
1480 static int sdl_client_start(rdpContext* context)
1482 auto sdl = get_context(context);
1485 sdl->thread = std::thread(sdl_client_thread_proc, sdl);
1489 static int sdl_client_stop(rdpContext* context)
1491 auto sdl = get_context(context);
1496 HANDLE
event = freerdp_abort_event(context);
1497 if (!SetEvent(event))
1504 static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
1506 WINPR_ASSERT(pEntryPoints);
1508 ZeroMemory(pEntryPoints,
sizeof(RDP_CLIENT_ENTRY_POINTS));
1509 pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
1510 pEntryPoints->Size =
sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
1511 pEntryPoints->GlobalInit = sdl_client_global_init;
1512 pEntryPoints->GlobalUninit = sdl_client_global_uninit;
1514 pEntryPoints->ClientNew = sdl_client_new;
1515 pEntryPoints->ClientFree = sdl_client_free;
1516 pEntryPoints->ClientStart = sdl_client_start;
1517 pEntryPoints->ClientStop = sdl_client_stop;
1524 freerdp_client_context_free(&sdl->common.context);
1527 static const char* category2str(
int category)
1531 case SDL_LOG_CATEGORY_APPLICATION:
1532 return "SDL_LOG_CATEGORY_APPLICATION";
1533 case SDL_LOG_CATEGORY_ERROR:
1534 return "SDL_LOG_CATEGORY_ERROR";
1535 case SDL_LOG_CATEGORY_ASSERT:
1536 return "SDL_LOG_CATEGORY_ASSERT";
1537 case SDL_LOG_CATEGORY_SYSTEM:
1538 return "SDL_LOG_CATEGORY_SYSTEM";
1539 case SDL_LOG_CATEGORY_AUDIO:
1540 return "SDL_LOG_CATEGORY_AUDIO";
1541 case SDL_LOG_CATEGORY_VIDEO:
1542 return "SDL_LOG_CATEGORY_VIDEO";
1543 case SDL_LOG_CATEGORY_RENDER:
1544 return "SDL_LOG_CATEGORY_RENDER";
1545 case SDL_LOG_CATEGORY_INPUT:
1546 return "SDL_LOG_CATEGORY_INPUT";
1547 case SDL_LOG_CATEGORY_TEST:
1548 return "SDL_LOG_CATEGORY_TEST";
1549 case SDL_LOG_CATEGORY_RESERVED1:
1550 return "SDL_LOG_CATEGORY_RESERVED1";
1551 case SDL_LOG_CATEGORY_RESERVED2:
1552 return "SDL_LOG_CATEGORY_RESERVED2";
1553 case SDL_LOG_CATEGORY_RESERVED3:
1554 return "SDL_LOG_CATEGORY_RESERVED3";
1555 case SDL_LOG_CATEGORY_RESERVED4:
1556 return "SDL_LOG_CATEGORY_RESERVED4";
1557 case SDL_LOG_CATEGORY_RESERVED5:
1558 return "SDL_LOG_CATEGORY_RESERVED5";
1559 case SDL_LOG_CATEGORY_RESERVED6:
1560 return "SDL_LOG_CATEGORY_RESERVED6";
1561 case SDL_LOG_CATEGORY_RESERVED7:
1562 return "SDL_LOG_CATEGORY_RESERVED7";
1563 case SDL_LOG_CATEGORY_RESERVED8:
1564 return "SDL_LOG_CATEGORY_RESERVED8";
1565 case SDL_LOG_CATEGORY_RESERVED9:
1566 return "SDL_LOG_CATEGORY_RESERVED9";
1567 case SDL_LOG_CATEGORY_RESERVED10:
1568 return "SDL_LOG_CATEGORY_RESERVED10";
1569 case SDL_LOG_CATEGORY_CUSTOM:
1571 return "SDL_LOG_CATEGORY_CUSTOM";
1575 static SDL_LogPriority wloglevel2dl(DWORD level)
1580 return SDL_LOG_PRIORITY_VERBOSE;
1582 return SDL_LOG_PRIORITY_DEBUG;
1584 return SDL_LOG_PRIORITY_INFO;
1586 return SDL_LOG_PRIORITY_WARN;
1588 return SDL_LOG_PRIORITY_ERROR;
1590 return SDL_LOG_PRIORITY_CRITICAL;
1593 return SDL_LOG_PRIORITY_VERBOSE;
1597 static DWORD sdlpriority2wlog(SDL_LogPriority priority)
1599 DWORD level = WLOG_OFF;
1602 case SDL_LOG_PRIORITY_VERBOSE:
1605 case SDL_LOG_PRIORITY_DEBUG:
1608 case SDL_LOG_PRIORITY_INFO:
1611 case SDL_LOG_PRIORITY_WARN:
1614 case SDL_LOG_PRIORITY_ERROR:
1617 case SDL_LOG_PRIORITY_CRITICAL:
1627 static void SDLCALL winpr_LogOutputFunction(
void* userdata,
int category, SDL_LogPriority priority,
1628 const char* message)
1630 auto sdl =
static_cast<SdlContext*
>(userdata);
1633 const DWORD level = sdlpriority2wlog(priority);
1634 auto log = sdl->log;
1635 if (!WLog_IsLevelActive(log, level))
1638 WLog_PrintMessage(log, WLOG_MESSAGE_TEXT, level, __LINE__, __FILE__, __func__,
"[%s] %s",
1639 category2str(category), message);
1642 int main(
int argc,
char* argv[])
1646 RDP_CLIENT_ENTRY_POINTS clientEntryPoints = {};
1648 freerdp_client_warn_experimental(argc, argv);
1650 "SDL2 client does not support clipboard! Only SDL3 client has (partial) support");
1652 RdpClientEntry(&clientEntryPoints);
1654 reinterpret_cast<sdl_rdp_context*
>(freerdp_client_context_new(&clientEntryPoints)),
1659 auto sdl = sdl_rdp->sdl;
1661 auto settings = sdl->context()->settings;
1662 WINPR_ASSERT(settings);
1664 status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE);
1667 rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
1669 sdl_list_monitors(sdl);
1674 case COMMAND_LINE_STATUS_PRINT:
1675 case COMMAND_LINE_STATUS_PRINT_VERSION:
1676 case COMMAND_LINE_STATUS_PRINT_BUILDCONFIG:
1678 case COMMAND_LINE_STATUS_PRINT_HELP:
1680 SdlPref::print_config_file_help(2);
1687 SDL_LogSetOutputFunction(winpr_LogOutputFunction, sdl);
1688 auto level = WLog_GetLogLevel(sdl->log);
1689 SDL_LogSetAllPriority(wloglevel2dl(level));
1691 auto context = sdl->context();
1692 WINPR_ASSERT(context);
1694 if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CREATE_REQUEST, FALSE))
1697 if (freerdp_client_start(context) != 0)
1702 if (freerdp_client_stop(context) != 0)
1705 if (sdl->exit_code != 0)
1706 rc = sdl->exit_code;
1711 BOOL SdlContext::update_fullscreen(BOOL enter)
1713 std::lock_guard<CriticalSection> lock(critical);
1714 for (
const auto& window : windows)
1716 if (!sdl_push_user_event(SDL_USEREVENT_WINDOW_FULLSCREEN, &window.second, enter))
1723 BOOL SdlContext::update_minimize()
1725 std::lock_guard<CriticalSection> lock(critical);
1726 if (!sdl_push_user_event(SDL_USEREVENT_WINDOW_MINIMIZE))
1731 BOOL SdlContext::update_resizeable(BOOL enable)
1733 std::lock_guard<CriticalSection> lock(critical);
1735 const auto settings = context()->settings;
1738 BOOL use = (dyn && enable) || smart;
1740 for (
const auto& window : windows)
1742 if (!sdl_push_user_event(SDL_USEREVENT_WINDOW_RESIZEABLE, &window.second, use))
1750 SdlContext::SdlContext(rdpContext* context)
1751 : _context(context), log(WLog_Get(SDL_TAG)), update_complete(true), disp(this), input(this),
1752 primary(nullptr, SDL_FreeSurface), primary_format(nullptr, SDL_FreeFormat),
1753 rdp_thread_running(false)
1755 WINPR_ASSERT(context);
1759 rdpContext* SdlContext::context()
const
1764 rdpClientContext* SdlContext::common()
const
1766 return reinterpret_cast<rdpClientContext*
>(_context);
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_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string 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 BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.