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>
43#include <winpr/config.h>
44#include <winpr/assert.h>
45#include <winpr/synch.h>
46#include <freerdp/log.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"
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 "sdl_win32_console.hpp"
67#include <sdl_config.hpp>
69#if defined(WITH_WEBVIEW)
70#include <aad/sdl_webview.hpp>
73#define SDL_TAG CLIENT_TAG("SDL")
79 SDL_EXIT_DISCONNECT = 1,
81 SDL_EXIT_IDLE_TIMEOUT = 3,
82 SDL_EXIT_LOGON_TIMEOUT = 4,
83 SDL_EXIT_CONN_REPLACED = 5,
84 SDL_EXIT_OUT_OF_MEMORY = 6,
85 SDL_EXIT_CONN_DENIED = 7,
86 SDL_EXIT_CONN_DENIED_FIPS = 8,
87 SDL_EXIT_USER_PRIVILEGES = 9,
88 SDL_EXIT_FRESH_CREDENTIALS_REQUIRED = 10,
89 SDL_EXIT_DISCONNECT_BY_USER = 11,
92 SDL_EXIT_LICENSE_INTERNAL = 16,
93 SDL_EXIT_LICENSE_NO_LICENSE_SERVER = 17,
94 SDL_EXIT_LICENSE_NO_LICENSE = 18,
95 SDL_EXIT_LICENSE_BAD_CLIENT_MSG = 19,
96 SDL_EXIT_LICENSE_HWID_DOESNT_MATCH = 20,
97 SDL_EXIT_LICENSE_BAD_CLIENT = 21,
98 SDL_EXIT_LICENSE_CANT_FINISH_PROTOCOL = 22,
99 SDL_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL = 23,
100 SDL_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION = 24,
101 SDL_EXIT_LICENSE_CANT_UPGRADE = 25,
102 SDL_EXIT_LICENSE_NO_REMOTE_CONNECTIONS = 26,
108 SDL_EXIT_PARSE_ARGUMENTS = 128,
109 SDL_EXIT_MEMORY = 129,
110 SDL_EXIT_PROTOCOL = 130,
111 SDL_EXIT_CONN_FAILED = 131,
112 SDL_EXIT_AUTH_FAILURE = 132,
113 SDL_EXIT_NEGO_FAILURE = 133,
114 SDL_EXIT_LOGON_FAILURE = 134,
115 SDL_EXIT_ACCOUNT_LOCKED_OUT = 135,
116 SDL_EXIT_PRE_CONNECT_FAILED = 136,
117 SDL_EXIT_CONNECT_UNDEFINED = 137,
118 SDL_EXIT_POST_CONNECT_FAILED = 138,
119 SDL_EXIT_DNS_ERROR = 139,
120 SDL_EXIT_DNS_NAME_NOT_FOUND = 140,
121 SDL_EXIT_CONNECT_FAILED = 141,
122 SDL_EXIT_MCS_CONNECT_INITIAL_ERROR = 142,
123 SDL_EXIT_TLS_CONNECT_FAILED = 143,
124 SDL_EXIT_INSUFFICIENT_PRIVILEGES = 144,
125 SDL_EXIT_CONNECT_CANCELLED = 145,
127 SDL_EXIT_CONNECT_TRANSPORT_FAILED = 147,
128 SDL_EXIT_CONNECT_PASSWORD_EXPIRED = 148,
129 SDL_EXIT_CONNECT_PASSWORD_MUST_CHANGE = 149,
130 SDL_EXIT_CONNECT_KDC_UNREACHABLE = 150,
131 SDL_EXIT_CONNECT_ACCOUNT_DISABLED = 151,
132 SDL_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED = 152,
133 SDL_EXIT_CONNECT_CLIENT_REVOKED = 153,
134 SDL_EXIT_CONNECT_WRONG_PASSWORD = 154,
135 SDL_EXIT_CONNECT_ACCESS_DENIED = 155,
136 SDL_EXIT_CONNECT_ACCOUNT_RESTRICTION = 156,
137 SDL_EXIT_CONNECT_ACCOUNT_EXPIRED = 157,
138 SDL_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED = 158,
139 SDL_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS = 159,
141 SDL_EXIT_UNKNOWN = 255,
144struct sdl_exit_code_map_t
148 const char* code_tag;
151#define ENTRY(x, y) { x, y, #y }
152static const struct sdl_exit_code_map_t sdl_exit_code_map[] = {
153 ENTRY(FREERDP_ERROR_SUCCESS, SDL_EXIT_SUCCESS), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_DISCONNECT),
154 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LOGOFF), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_IDLE_TIMEOUT),
155 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LOGON_TIMEOUT),
156 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_REPLACED),
157 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_OUT_OF_MEMORY),
158 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_DENIED),
159 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_DENIED_FIPS),
160 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_USER_PRIVILEGES),
161 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_FRESH_CREDENTIALS_REQUIRED),
162 ENTRY(ERRINFO_LOGOFF_BY_USER, SDL_EXIT_DISCONNECT_BY_USER),
163 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_UNKNOWN),
166 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_INTERNAL),
167 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_LICENSE_SERVER),
168 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_LICENSE),
169 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT_MSG),
170 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_HWID_DOESNT_MATCH),
171 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT),
172 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_FINISH_PROTOCOL),
173 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL),
174 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION),
175 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_UPGRADE),
176 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_REMOTE_CONNECTIONS),
177 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_UPGRADE),
180 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_RDP),
183 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_PARSE_ARGUMENTS), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_MEMORY),
184 ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_PROTOCOL), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_FAILED),
186 ENTRY(FREERDP_ERROR_AUTHENTICATION_FAILED, SDL_EXIT_AUTH_FAILURE),
187 ENTRY(FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED, SDL_EXIT_NEGO_FAILURE),
188 ENTRY(FREERDP_ERROR_CONNECT_LOGON_FAILURE, SDL_EXIT_LOGON_FAILURE),
189 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT, SDL_EXIT_ACCOUNT_LOCKED_OUT),
190 ENTRY(FREERDP_ERROR_PRE_CONNECT_FAILED, SDL_EXIT_PRE_CONNECT_FAILED),
191 ENTRY(FREERDP_ERROR_CONNECT_UNDEFINED, SDL_EXIT_CONNECT_UNDEFINED),
192 ENTRY(FREERDP_ERROR_POST_CONNECT_FAILED, SDL_EXIT_POST_CONNECT_FAILED),
193 ENTRY(FREERDP_ERROR_DNS_ERROR, SDL_EXIT_DNS_ERROR),
194 ENTRY(FREERDP_ERROR_DNS_NAME_NOT_FOUND, SDL_EXIT_DNS_NAME_NOT_FOUND),
195 ENTRY(FREERDP_ERROR_CONNECT_FAILED, SDL_EXIT_CONNECT_FAILED),
196 ENTRY(FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR, SDL_EXIT_MCS_CONNECT_INITIAL_ERROR),
197 ENTRY(FREERDP_ERROR_TLS_CONNECT_FAILED, SDL_EXIT_TLS_CONNECT_FAILED),
198 ENTRY(FREERDP_ERROR_INSUFFICIENT_PRIVILEGES, SDL_EXIT_INSUFFICIENT_PRIVILEGES),
199 ENTRY(FREERDP_ERROR_CONNECT_CANCELLED, SDL_EXIT_CONNECT_CANCELLED),
200 ENTRY(FREERDP_ERROR_CONNECT_TRANSPORT_FAILED, SDL_EXIT_CONNECT_TRANSPORT_FAILED),
201 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED, SDL_EXIT_CONNECT_PASSWORD_EXPIRED),
202 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE, SDL_EXIT_CONNECT_PASSWORD_MUST_CHANGE),
203 ENTRY(FREERDP_ERROR_CONNECT_KDC_UNREACHABLE, SDL_EXIT_CONNECT_KDC_UNREACHABLE),
204 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED, SDL_EXIT_CONNECT_ACCOUNT_DISABLED),
205 ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED,
206 SDL_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED),
207 ENTRY(FREERDP_ERROR_CONNECT_CLIENT_REVOKED, SDL_EXIT_CONNECT_CLIENT_REVOKED),
208 ENTRY(FREERDP_ERROR_CONNECT_WRONG_PASSWORD, SDL_EXIT_CONNECT_WRONG_PASSWORD),
209 ENTRY(FREERDP_ERROR_CONNECT_ACCESS_DENIED, SDL_EXIT_CONNECT_ACCESS_DENIED),
210 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION, SDL_EXIT_CONNECT_ACCOUNT_RESTRICTION),
211 ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED, SDL_EXIT_CONNECT_ACCOUNT_EXPIRED),
212 ENTRY(FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED, SDL_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED),
213 ENTRY(FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS,
214 SDL_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS)
217static const struct sdl_exit_code_map_t* sdl_map_entry_by_code(
int exit_code)
219 for (
const auto& x : sdl_exit_code_map)
221 const struct sdl_exit_code_map_t* cur = &x;
222 if (cur->code == exit_code)
231 std::scoped_lock lock(
sdl->critical);
232 if (
sdl->connection_dialog)
233 sdl->connection_dialog->hide();
236static const struct sdl_exit_code_map_t* sdl_map_entry_by_error(UINT32 error)
238 for (
const auto& x : sdl_exit_code_map)
240 const struct sdl_exit_code_map_t* cur = &x;
241 if (cur->error ==
static_cast<uint32_t
>(error))
247static int sdl_map_error_to_exit_code(UINT32 error)
249 const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_error(error);
253 return SDL_EXIT_CONN_FAILED;
256static const char* sdl_map_error_to_code_tag(UINT32 error)
258 const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_error(error);
260 return entry->code_tag;
264static const char* sdl_map_to_code_tag(
int code)
266 const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_code(code);
268 return entry->code_tag;
272static int error_info_to_error(freerdp* instance, DWORD* pcode,
char** msg,
size_t* len)
274 const DWORD code = freerdp_error_info(instance);
275 const char* name = freerdp_get_error_info_name(code);
276 const char* str = freerdp_get_error_info_string(code);
277 const int exit_code = sdl_map_error_to_exit_code(code);
279 winpr_asprintf(msg, len,
"Terminate with %s due to ERROR_INFO %s [0x%08" PRIx32
"]: %s",
280 sdl_map_error_to_code_tag(code), name, code, str);
281 WLog_DBG(SDL_TAG,
"%s", *msg);
289static BOOL sdl_begin_paint(rdpContext* context)
291 auto sdl = get_context(context);
295 HANDLE handles[] = {
sdl->update_complete.handle(), freerdp_abort_event(context) };
296 const DWORD status = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
304 sdl->update_complete.clear();
306 auto gdi = context->gdi;
308 WINPR_ASSERT(gdi->primary);
310 HGDI_DC hdc = gdi->primary->hdc;
316 WINPR_ASSERT(hwnd->invalid);
317 hwnd->invalid->null = TRUE;
327 auto gdi =
sdl->context()->gdi;
328 return gdi_send_suppress_output(gdi, FALSE);
331class SdlEventUpdateTriggerGuard
340 ~SdlEventUpdateTriggerGuard()
342 _sdl->update_complete.set();
344 SdlEventUpdateTriggerGuard(
const SdlEventUpdateTriggerGuard&) =
delete;
345 SdlEventUpdateTriggerGuard(SdlEventUpdateTriggerGuard&&) =
delete;
346 SdlEventUpdateTriggerGuard& operator=(
const SdlEventUpdateTriggerGuard&) =
delete;
347 SdlEventUpdateTriggerGuard& operator=(SdlEventUpdateTriggerGuard&&) =
delete;
351 SDL_Surface* surface, SDL_Point offset, SDL_Rect srcRect)
353 SDL_Rect dstRect = { offset.x + srcRect.x, offset.y + srcRect.y, srcRect.w, srcRect.h };
354 return window.blit(surface, srcRect, dstRect);
358 SDL_Point offset,
const std::vector<SDL_Rect>& rects = {})
362 return sdl_draw_to_window_rect(
sdl, window, surface, offset,
363 { 0, 0, surface->w, surface->h });
365 for (
auto& srcRect : rects)
367 if (!sdl_draw_to_window_rect(
sdl, window, surface, offset, srcRect))
376 SDL_Rect dstRect = srcRect;
377 sdl_scale_coordinates(
sdl, window.id(), &dstRect.x, &dstRect.y, FALSE, TRUE);
378 sdl_scale_coordinates(
sdl, window.id(), &dstRect.w, &dstRect.h, FALSE, TRUE);
379 return window.blit(surface, srcRect, dstRect);
383 const std::vector<SDL_Rect>& rects = {})
387 return sdl_draw_to_window_scaled_rect(
sdl, window, surface,
388 { 0, 0, surface->w, surface->h });
390 for (
const auto& srcRect : rects)
392 if (!sdl_draw_to_window_scaled_rect(
sdl, window, surface, srcRect))
399 const std::vector<SDL_Rect>& rects = {})
403 auto context =
sdl->context();
404 auto gdi = context->gdi;
406 auto size = window.rect();
410 if (gdi->width < size.w)
412 window.setOffsetX((size.w - gdi->width) / 2);
414 if (gdi->height < size.h)
416 window.setOffsetY((size.h - gdi->height) / 2);
419 auto surface =
sdl->primary.get();
420 if (!sdl_draw_to_window_rect(
sdl, window, surface, { window.offsetX(), window.offsetY() },
426 if (!sdl_draw_to_window_scaled_rect(
sdl, window,
sdl->primary.get(), rects))
429 window.updateSurface();
433static BOOL sdl_draw_to_window(
SdlContext*
sdl, std::map<Uint32, SdlWindow>& windows,
434 const std::vector<SDL_Rect>& rects = {})
436 for (
auto& window : windows)
438 if (!sdl_draw_to_window(
sdl, window.second, rects))
445static BOOL sdl_end_paint_process(rdpContext* context)
447 auto sdl = get_context(context);
449 WINPR_ASSERT(context);
451 SdlEventUpdateTriggerGuard guard(
sdl);
453 auto gdi = context->gdi;
455 WINPR_ASSERT(gdi->primary);
457 HGDI_DC hdc = gdi->primary->hdc;
463 WINPR_ASSERT(hwnd->invalid || (hwnd->ninvalid == 0));
465 if (hwnd->invalid->null)
468 WINPR_ASSERT(hwnd->invalid);
469 if (gdi->suppressOutput || hwnd->invalid->null)
472 const INT32 ninvalid = hwnd->ninvalid;
473 const GDI_RGN* cinvalid = hwnd->cinvalid;
478 std::vector<SDL_Rect> rects;
479 for (INT32 x = 0; x < ninvalid; x++)
481 auto& rgn = cinvalid[x];
482 rects.push_back({ rgn.x, rgn.y, rgn.w, rgn.h });
485 return sdl_draw_to_window(
sdl,
sdl->windows, rects);
492static BOOL sdl_end_paint(rdpContext* context)
494 auto sdl = get_context(context);
497 std::scoped_lock lock(
sdl->critical);
498 const BOOL rc = sdl_push_user_event(SDL_USEREVENT_UPDATE, context);
507 sdl->primary.reset();
508 sdl->primary_format.reset();
514 rdpGdi* gdi =
nullptr;
518 gdi =
sdl->context()->gdi;
521 sdl_destroy_primary(
sdl);
522 sdl->primary = SDLSurfacePtr(
523 SDL_CreateRGBSurfaceWithFormatFrom(gdi->primary_buffer,
static_cast<int>(gdi->width),
524 static_cast<int>(gdi->height),
525 static_cast<int>(FreeRDPGetBitsPerPixel(gdi->dstFormat)),
526 static_cast<int>(gdi->stride),
sdl->sdl_pixel_format),
528 sdl->primary_format = SDLPixelFormatPtr(SDL_AllocFormat(
sdl->sdl_pixel_format), SDL_FreeFormat);
530 if (!
sdl->primary || !
sdl->primary_format)
533 SDL_SetSurfaceBlendMode(
sdl->primary.get(), SDL_BLENDMODE_NONE);
534 SDL_FillRect(
sdl->primary.get(),
nullptr,
535 SDL_MapRGBA(
sdl->primary_format.get(), 0, 0, 0, 0xff));
540static BOOL sdl_desktop_resize(rdpContext* context)
542 rdpGdi* gdi =
nullptr;
543 rdpSettings* settings =
nullptr;
544 auto sdl = get_context(context);
547 WINPR_ASSERT(context);
549 settings = context->settings;
550 WINPR_ASSERT(settings);
552 std::scoped_lock lock(
sdl->critical);
557 return sdl_create_primary(
sdl);
561static BOOL sdl_play_sound(rdpContext* context,
const PLAY_SOUND_UPDATE* play_sound)
564 WINPR_UNUSED(context);
565 WINPR_UNUSED(play_sound);
572 sdl->initialize.set();
574 HANDLE handles[] = {
sdl->initialized.handle(), freerdp_abort_event(
sdl->context()) };
576 const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
588static BOOL sdl_pre_connect(freerdp* instance)
590 WINPR_ASSERT(instance);
591 WINPR_ASSERT(instance->context);
593 auto sdl = get_context(instance->context);
595 auto settings = instance->context->settings;
596 WINPR_ASSERT(settings);
611 if (PubSub_SubscribeChannelConnected(instance->context->pubSub,
612 sdl_OnChannelConnectedEventHandler) < 0)
614 if (PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
615 sdl_OnChannelDisconnectedEventHandler) < 0)
617 if (PubSub_SubscribeUserNotification(instance->context->pubSub,
618 sdl_OnUserNotificationEventHandler) < 0)
624 UINT32 maxHeight = 0;
626 if (!sdl_wait_for_init(
sdl))
629 std::scoped_lock lock(
sdl->critical);
631 sdl->connection_dialog = std::make_unique<SDLConnectionDialog>(instance->context);
632 if (
sdl->connection_dialog)
634 sdl->connection_dialog->setTitle(
"Connecting to '%s'",
636 sdl->connection_dialog->showInfo(
637 "The connection is being established\n\nPlease wait...");
639 if (!sdl_detect_monitors(
sdl, &maxWidth, &maxHeight))
642 if ((maxWidth != 0) && (maxHeight != 0) &&
645 WLog_Print(
sdl->log, WLOG_INFO,
"Update size to %ux%u", maxWidth, maxHeight);
657 WLog_Print(
sdl->log, WLOG_INFO,
"auth-only, but no password set. Please provide one.");
664 WLog_Print(
sdl->log, WLOG_INFO,
"Authentication only. Don't connect SDL.");
671static const char* sdl_window_get_title(rdpSettings* settings)
673 const char* windowTitle =
nullptr;
676 const char* name =
nullptr;
677 const char* prefix =
"FreeRDP:";
689 addPort = (port != 3389);
691 char buffer[MAX_PATH + 64] = {};
694 (void)sprintf_s(buffer,
sizeof(buffer),
"%s %s", prefix, name);
696 (
void)sprintf_s(buffer,
sizeof(buffer),
"%s %s:%" PRIu32, prefix, name, port);
703static void sdl_term_handler([[maybe_unused]]
int signum, [[maybe_unused]]
const char* signame,
704 [[maybe_unused]]
void* context)
714 std::scoped_lock lock(
sdl->critical);
715 sdl->windows.clear();
716 sdl->connection_dialog.reset();
718 sdl_destroy_primary(
sdl);
720 freerdp_del_signal_cleanup_handler(
sdl->context(), sdl_term_handler);
729 auto settings =
sdl->context()->settings;
730 auto title = sdl_window_get_title(settings);
736 for (UINT32 x = 0; x < windowCount; x++)
738 auto id = sdl_monitor_id_for_index(
sdl, x);
742 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x));
744 Uint32 w = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
745 Uint32 h = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
753 Uint32 flags = SDL_WINDOW_SHOWN;
754 auto startupX = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
755 auto startupY = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
757 if (monitor->attributes.desktopScaleFactor > 100)
759#if SDL_VERSION_ATLEAST(2, 0, 1)
760 flags |= SDL_WINDOW_ALLOW_HIGHDPI;
767 flags |= SDL_WINDOW_FULLSCREEN;
772 flags |= SDL_WINDOW_BORDERLESS;
776 flags |= SDL_WINDOW_BORDERLESS;
779 static_cast<int>(startupX),
780 static_cast<int>(startupY),
785 if (!window.window())
790 auto r = window.rect();
791 window.setOffsetX(0 - r.x);
792 window.setOffsetY(0 - r.y);
795 sdl->windows.insert({ window.id(), std::move(window) });
803 std::scoped_lock lock(
sdl->critical);
804 sdl->windows_created.clear();
805 if (!sdl_push_user_event(SDL_USEREVENT_CREATE_WINDOWS,
sdl))
808 HANDLE handles[] = {
sdl->initialized.handle(), freerdp_abort_event(
sdl->context()) };
810 const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
822 std::scoped_lock lock(
sdl->critical);
823 if (freerdp_shall_disconnect_context(
sdl->context()))
825 if (
sdl->rdp_thread_running)
827 if (!
sdl->connection_dialog)
829 return !
sdl->connection_dialog->running();
839 HANDLE handles[] = {
sdl->initialize.handle(), freerdp_abort_event(
sdl->context()) };
840 const DWORD status = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
849 SDL_Init(SDL_INIT_VIDEO);
851#if SDL_VERSION_ATLEAST(2, 0, 16)
852 SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED,
"0");
854#if SDL_VERSION_ATLEAST(2, 0, 8)
855 SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,
"0");
858 if (!freerdp_add_signal_cleanup_handler(
sdl->context(), sdl_term_handler))
861 sdl->initialized.set();
863 while (!shall_abort(
sdl))
865 SDL_Event windowEvent = {};
866 while (!shall_abort(
sdl) && SDL_WaitEventTimeout(
nullptr, 1000))
871 const int prc = SDL_PeepEvents(&windowEvent, 1, SDL_GETEVENT, SDL_FIRSTEVENT,
872 SDL_USEREVENT_RETRY_DIALOG);
875 if (sdl_log_error(prc,
sdl->log,
"SDL_PeepEvents"))
879 WLog_Print(
sdl->log, WLOG_TRACE,
"got event %s [0x%08" PRIx32
"]",
880 sdl_event_type_str(windowEvent.type), windowEvent.type);
881 std::scoped_lock lock(
sdl->critical);
884 if (freerdp_shall_disconnect_context(
sdl->context()))
887 if (
sdl->connection_dialog)
889 if (
sdl->connection_dialog->handle(windowEvent))
895 switch (windowEvent.type)
898 freerdp_abort_connect_context(
sdl->context());
903 const SDL_KeyboardEvent* ev = &windowEvent.key;
904 sdl->input.keyboard_handle_event(ev);
907 case SDL_KEYMAPCHANGED:
911 case SDL_MOUSEMOTION:
913 const SDL_MouseMotionEvent* ev = &windowEvent.motion;
914 sdl_handle_mouse_motion(
sdl, ev);
917 case SDL_MOUSEBUTTONDOWN:
918 case SDL_MOUSEBUTTONUP:
920 const SDL_MouseButtonEvent* ev = &windowEvent.button;
921 sdl_handle_mouse_button(
sdl, ev);
926 const SDL_MouseWheelEvent* ev = &windowEvent.wheel;
927 sdl_handle_mouse_wheel(
sdl, ev);
932 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
933 sdl_handle_touch_down(
sdl, ev);
938 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
939 sdl_handle_touch_up(
sdl, ev);
942 case SDL_FINGERMOTION:
944 const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
945 sdl_handle_touch_motion(
sdl, ev);
948#if SDL_VERSION_ATLEAST(2, 0, 10)
949 case SDL_DISPLAYEVENT:
951 const SDL_DisplayEvent* ev = &windowEvent.display;
952 sdl->disp.handle_display_event(ev);
956 case SDL_WINDOWEVENT:
958 const SDL_WindowEvent* ev = &windowEvent.window;
959 auto window =
sdl->windows.find(ev->windowID);
960 if (window !=
sdl->windows.end())
961 sdl->disp.handle_window_event(ev);
964 case SDL_WINDOWEVENT_RESIZED:
965 case SDL_WINDOWEVENT_SIZE_CHANGED:
967 if (window !=
sdl->windows.end())
969 window->second.fill();
970 window->second.updateSurface();
974 case SDL_WINDOWEVENT_MOVED:
976 if (window !=
sdl->windows.end())
978 auto r = window->second.rect();
979 auto id = window->second.id();
980 WLog_DBG(SDL_TAG,
"%u: %dx%d-%dx%d",
id, r.x, r.y, r.w, r.h);
990 case SDL_RENDER_TARGETS_RESET:
993 case SDL_RENDER_DEVICE_RESET:
996 case SDL_APP_WILLENTERFOREGROUND:
999 case SDL_USEREVENT_CERT_DIALOG:
1001 auto title =
static_cast<const char*
>(windowEvent.user.data1);
1002 auto msg =
static_cast<const char*
>(windowEvent.user.data2);
1003 sdl_cert_dialog_show(title, msg);
1006 case SDL_USEREVENT_SHOW_DIALOG:
1008 auto title =
static_cast<const char*
>(windowEvent.user.data1);
1009 auto msg =
static_cast<const char*
>(windowEvent.user.data2);
1010 sdl_message_dialog_show(title, msg, windowEvent.user.code);
1013 case SDL_USEREVENT_SCARD_DIALOG:
1015 auto title =
static_cast<const char*
>(windowEvent.user.data1);
1016 auto msg =
static_cast<const char**
>(windowEvent.user.data2);
1017 sdl_scard_dialog_show(title, windowEvent.user.code, msg);
1020 case SDL_USEREVENT_AUTH_DIALOG:
1021 sdl_auth_dialog_show(
1024 case SDL_USEREVENT_UPDATE:
1026 auto context =
static_cast<rdpContext*
>(windowEvent.user.data1);
1027 sdl_end_paint_process(context);
1030 case SDL_USEREVENT_CREATE_WINDOWS:
1032 auto ctx =
static_cast<SdlContext*
>(windowEvent.user.data1);
1033 sdl_create_windows(ctx);
1036 case SDL_USEREVENT_WINDOW_RESIZEABLE:
1038 auto window =
static_cast<SdlWindow*
>(windowEvent.user.data1);
1039 const SDL_bool use = windowEvent.user.code != 0 ? SDL_TRUE : SDL_FALSE;
1041 window->resizeable(use);
1044 case SDL_USEREVENT_WINDOW_FULLSCREEN:
1046 auto window =
static_cast<SdlWindow*
>(windowEvent.user.data1);
1047 const SDL_bool enter = windowEvent.user.code != 0 ? SDL_TRUE : SDL_FALSE;
1049 window->fullscreen(enter);
1052 case SDL_USEREVENT_WINDOW_MINIMIZE:
1054 for (
auto& window :
sdl->windows)
1056 window.second.minimize();
1060 case SDL_USEREVENT_POINTER_NULL:
1061 SDL_ShowCursor(SDL_DISABLE);
1063 case SDL_USEREVENT_POINTER_DEFAULT:
1065 SDL_Cursor* def = SDL_GetDefaultCursor();
1067 SDL_ShowCursor(SDL_ENABLE);
1070 case SDL_USEREVENT_POINTER_POSITION:
1073 static_cast<INT32
>(
reinterpret_cast<uintptr_t
>(windowEvent.user.data1));
1075 static_cast<INT32
>(
reinterpret_cast<uintptr_t
>(windowEvent.user.data2));
1077 SDL_Window* window = SDL_GetMouseFocus();
1080 const Uint32
id = SDL_GetWindowID(window);
1084 if (sdl_scale_coordinates(
sdl,
id, &sx, &sy, FALSE, FALSE))
1085 SDL_WarpMouseInWindow(window, sx, sy);
1089 case SDL_USEREVENT_POINTER_SET:
1090 sdl_Pointer_Set_Process(&windowEvent.user);
1092 case SDL_USEREVENT_QUIT:
1101 sdl_cleanup_sdl(
sdl);
1113static BOOL sdl_post_connect(freerdp* instance)
1115 WINPR_ASSERT(instance);
1117 auto context = instance->context;
1118 WINPR_ASSERT(context);
1120 auto sdl = get_context(context);
1123 sdl_hide_connection_dialog(
sdl);
1130 WLog_Print(
sdl->log, WLOG_INFO,
"auth-only, but no password set. Please provide one.");
1134 WLog_Print(
sdl->log, WLOG_INFO,
"Authentication only. Don't connect to X.");
1138 if (!sdl_wait_create_windows(
sdl))
1141 sdl->sdl_pixel_format = SDL_PIXELFORMAT_BGRA32;
1142 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
1145 if (!sdl_create_primary(
sdl))
1148 if (!sdl_register_pointer(instance->context->graphics))
1151 WINPR_ASSERT(context->update);
1153 context->update->BeginPaint = sdl_begin_paint;
1154 context->update->EndPaint = sdl_end_paint;
1155 context->update->PlaySound = sdl_play_sound;
1156 context->update->DesktopResize = sdl_desktop_resize;
1157 context->update->SetKeyboardIndicators = sdlInput::keyboard_set_indicators;
1158 context->update->SetKeyboardImeStatus = sdlInput::keyboard_set_ime_status;
1160 sdl->update_resizeable(FALSE);
1169static void sdl_post_disconnect(freerdp* instance)
1174 if (!instance->context)
1177 PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
1178 sdl_OnChannelConnectedEventHandler);
1179 PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
1180 sdl_OnChannelDisconnectedEventHandler);
1181 PubSub_UnsubscribeUserNotification(instance->context->pubSub,
1182 sdl_OnUserNotificationEventHandler);
1186static void sdl_post_final_disconnect(freerdp* instance)
1191 if (!instance->context)
1195static void sdl_client_cleanup(
SdlContext*
sdl,
int exit_code,
const std::string& error_msg)
1199 rdpContext* context =
sdl->context();
1200 WINPR_ASSERT(context);
1202 rdpSettings* settings = context->settings;
1203 WINPR_ASSERT(settings);
1205 sdl->rdp_thread_running =
false;
1206 bool showError =
false;
1208 WLog_Print(
sdl->log, WLOG_INFO,
"Authentication only, exit status %s [%" PRId32
"]",
1209 sdl_map_to_code_tag(exit_code), exit_code);
1214 case SDL_EXIT_SUCCESS:
1215 case SDL_EXIT_DISCONNECT:
1216 case SDL_EXIT_LOGOFF:
1217 case SDL_EXIT_DISCONNECT_BY_USER:
1218 case SDL_EXIT_CONNECT_CANCELLED:
1222 std::scoped_lock lock(
sdl->critical);
1223 if (
sdl->connection_dialog && !error_msg.empty())
1225 sdl->connection_dialog->showError(error_msg.c_str());
1234 sdl_hide_connection_dialog(
sdl);
1236 sdl->exit_code = exit_code;
1237 sdl_push_user_event(SDL_USEREVENT_QUIT);
1238#if SDL_VERSION_ATLEAST(2, 0, 16)
1243static int sdl_client_thread_connect(
SdlContext*
sdl, std::string& error_msg)
1247 auto instance =
sdl->context()->instance;
1248 WINPR_ASSERT(instance);
1250 sdl->rdp_thread_running =
true;
1251 BOOL rc = freerdp_connect(instance);
1253 rdpContext* context =
sdl->context();
1254 WINPR_ASSERT(context);
1256 rdpSettings* settings = context->settings;
1257 WINPR_ASSERT(settings);
1259 int exit_code = SDL_EXIT_SUCCESS;
1262 UINT32 error = freerdp_get_last_error(context);
1263 exit_code = sdl_map_error_to_exit_code(error);
1268 DWORD code = freerdp_get_last_error(context);
1269 freerdp_abort_connect_context(context);
1270 WLog_Print(
sdl->log, WLOG_ERROR,
"Authentication only, %s [0x%08" PRIx32
"] %s",
1271 freerdp_get_last_error_name(code), code, freerdp_get_last_error_string(code));
1277 DWORD code = freerdp_error_info(instance);
1278 if (exit_code == SDL_EXIT_SUCCESS)
1280 char* msg =
nullptr;
1282 exit_code = error_info_to_error(instance, &code, &msg, &len);
1288 auto last = freerdp_get_last_error(context);
1289 if (error_msg.empty())
1291 char* msg =
nullptr;
1293 winpr_asprintf(&msg, &len,
"%s [0x%08" PRIx32
"]\n%s",
1294 freerdp_get_last_error_name(last), last,
1295 freerdp_get_last_error_string(last));
1301 if (exit_code == SDL_EXIT_SUCCESS)
1303 if (last == FREERDP_ERROR_AUTHENTICATION_FAILED)
1304 exit_code = SDL_EXIT_AUTH_FAILURE;
1305 else if (code == ERRINFO_SUCCESS)
1306 exit_code = SDL_EXIT_CONN_FAILED;
1309 sdl_hide_connection_dialog(
sdl);
1314static int sdl_client_thread_run(
SdlContext*
sdl, std::string& error_msg)
1318 auto context =
sdl->context();
1319 WINPR_ASSERT(context);
1321 auto instance = context->instance;
1322 WINPR_ASSERT(instance);
1324 int exit_code = SDL_EXIT_SUCCESS;
1325 while (!freerdp_shall_disconnect_context(context))
1327 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {};
1333 if (freerdp_focus_required(instance))
1335 auto ctx = get_context(context);
1337 if (!ctx->input.keyboard_focus_in())
1339 if (!ctx->input.keyboard_focus_in())
1343 const DWORD nCount = freerdp_get_event_handles(context, handles, ARRAYSIZE(handles));
1347 WLog_Print(
sdl->log, WLOG_ERROR,
"freerdp_get_event_handles failed");
1351 const DWORD status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
1353 if (status == WAIT_FAILED)
1356 if (!freerdp_check_event_handles(context))
1358 if (client_auto_reconnect(instance))
1361 sdl_hide_connection_dialog(
sdl);
1370 if (freerdp_error_info(instance) == 0)
1371 exit_code = SDL_EXIT_CONN_FAILED;
1374 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
1375 WLog_Print(
sdl->log, WLOG_ERROR,
"WaitForMultipleObjects failed with %" PRIu32
"",
1377 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
1378 WLog_Print(
sdl->log, WLOG_ERROR,
"Failed to check FreeRDP event handles");
1383 if (exit_code == SDL_EXIT_SUCCESS)
1387 char* msg =
nullptr;
1389 exit_code = error_info_to_error(instance, &code, &msg, &len);
1395 if ((code == ERRINFO_LOGOFF_BY_USER) &&
1396 (freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested))
1398 const char* msg =
"Error info says user did not initiate but disconnect ultimatum says "
1399 "they did; treat this as a user logoff";
1400 char* emsg =
nullptr;
1402 winpr_asprintf(&emsg, &len,
"%s", msg);
1407 WLog_Print(
sdl->log, WLOG_INFO,
"%s", msg);
1408 exit_code = SDL_EXIT_LOGOFF;
1412 freerdp_disconnect(instance);
1423 std::string error_msg;
1424 int exit_code = sdl_client_thread_connect(
sdl, error_msg);
1425 if (exit_code == SDL_EXIT_SUCCESS)
1426 exit_code = sdl_client_thread_run(
sdl, error_msg);
1427 sdl_client_cleanup(
sdl, exit_code, error_msg);
1429 return static_cast<DWORD
>(exit_code);
1435static BOOL sdl_client_global_init()
1439 const DWORD wVersionRequested = MAKEWORD(1, 1);
1440 const int rc = WSAStartup(wVersionRequested, &wsaData);
1443 WLog_ERR(SDL_TAG,
"WSAStartup failed with %s [%d]", gai_strerrorA(rc), rc);
1448 return freerdp_handle_signals() == 0;
1452static void sdl_client_global_uninit()
1459static BOOL sdl_client_new(freerdp* instance, rdpContext* context)
1463 if (!instance || !context)
1470 instance->PreConnect = sdl_pre_connect;
1471 instance->PostConnect = sdl_post_connect;
1472 instance->PostDisconnect = sdl_post_disconnect;
1473 instance->PostFinalDisconnect = sdl_post_final_disconnect;
1474 instance->AuthenticateEx = sdl_authenticate_ex;
1475 instance->VerifyCertificateEx = sdl_verify_certificate_ex;
1476 instance->VerifyChangedCertificateEx = sdl_verify_changed_certificate_ex;
1477 instance->LogonErrorInfo = sdl_logon_error_info;
1478 instance->PresentGatewayMessage = sdl_present_gateway_message;
1479 instance->ChooseSmartcard = sdl_choose_smartcard;
1480 instance->RetryDialog = sdl_retry_dialog;
1482#if defined(WITH_WEBVIEW)
1483 instance->GetAccessToken = sdl_webview_get_access_token;
1485 instance->GetAccessToken = client_cli_get_access_token;
1492static void sdl_client_free([[maybe_unused]] freerdp* instance, rdpContext* context)
1502static int sdl_client_start(rdpContext* context)
1504 auto sdl = get_context(context);
1507 sdl->thread = std::thread(sdl_client_thread_proc,
sdl);
1511static int sdl_client_stop(rdpContext* context)
1513 auto sdl = get_context(context);
1518 HANDLE
event = freerdp_abort_event(context);
1519 if (!SetEvent(event))
1526static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
1528 WINPR_ASSERT(pEntryPoints);
1530 ZeroMemory(pEntryPoints,
sizeof(RDP_CLIENT_ENTRY_POINTS));
1531 pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
1532 pEntryPoints->Size =
sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
1533 pEntryPoints->GlobalInit = sdl_client_global_init;
1534 pEntryPoints->GlobalUninit = sdl_client_global_uninit;
1536 pEntryPoints->ClientNew = sdl_client_new;
1537 pEntryPoints->ClientFree = sdl_client_free;
1538 pEntryPoints->ClientStart = sdl_client_start;
1539 pEntryPoints->ClientStop = sdl_client_stop;
1546 freerdp_client_context_free(&
sdl->common.context);
1549static const char* category2str(
int category)
1553 case SDL_LOG_CATEGORY_APPLICATION:
1554 return "SDL_LOG_CATEGORY_APPLICATION";
1555 case SDL_LOG_CATEGORY_ERROR:
1556 return "SDL_LOG_CATEGORY_ERROR";
1557 case SDL_LOG_CATEGORY_ASSERT:
1558 return "SDL_LOG_CATEGORY_ASSERT";
1559 case SDL_LOG_CATEGORY_SYSTEM:
1560 return "SDL_LOG_CATEGORY_SYSTEM";
1561 case SDL_LOG_CATEGORY_AUDIO:
1562 return "SDL_LOG_CATEGORY_AUDIO";
1563 case SDL_LOG_CATEGORY_VIDEO:
1564 return "SDL_LOG_CATEGORY_VIDEO";
1565 case SDL_LOG_CATEGORY_RENDER:
1566 return "SDL_LOG_CATEGORY_RENDER";
1567 case SDL_LOG_CATEGORY_INPUT:
1568 return "SDL_LOG_CATEGORY_INPUT";
1569 case SDL_LOG_CATEGORY_TEST:
1570 return "SDL_LOG_CATEGORY_TEST";
1571 case SDL_LOG_CATEGORY_RESERVED1:
1572 return "SDL_LOG_CATEGORY_RESERVED1";
1573 case SDL_LOG_CATEGORY_RESERVED2:
1574 return "SDL_LOG_CATEGORY_RESERVED2";
1575 case SDL_LOG_CATEGORY_RESERVED3:
1576 return "SDL_LOG_CATEGORY_RESERVED3";
1577 case SDL_LOG_CATEGORY_RESERVED4:
1578 return "SDL_LOG_CATEGORY_RESERVED4";
1579 case SDL_LOG_CATEGORY_RESERVED5:
1580 return "SDL_LOG_CATEGORY_RESERVED5";
1581 case SDL_LOG_CATEGORY_RESERVED6:
1582 return "SDL_LOG_CATEGORY_RESERVED6";
1583 case SDL_LOG_CATEGORY_RESERVED7:
1584 return "SDL_LOG_CATEGORY_RESERVED7";
1585 case SDL_LOG_CATEGORY_RESERVED8:
1586 return "SDL_LOG_CATEGORY_RESERVED8";
1587 case SDL_LOG_CATEGORY_RESERVED9:
1588 return "SDL_LOG_CATEGORY_RESERVED9";
1589 case SDL_LOG_CATEGORY_RESERVED10:
1590 return "SDL_LOG_CATEGORY_RESERVED10";
1591 case SDL_LOG_CATEGORY_CUSTOM:
1593 return "SDL_LOG_CATEGORY_CUSTOM";
1597static SDL_LogPriority wloglevel2dl(DWORD level)
1602 return SDL_LOG_PRIORITY_VERBOSE;
1604 return SDL_LOG_PRIORITY_DEBUG;
1606 return SDL_LOG_PRIORITY_INFO;
1608 return SDL_LOG_PRIORITY_WARN;
1610 return SDL_LOG_PRIORITY_ERROR;
1612 return SDL_LOG_PRIORITY_CRITICAL;
1615 return SDL_LOG_PRIORITY_VERBOSE;
1619static DWORD sdlpriority2wlog(SDL_LogPriority priority)
1621 DWORD level = WLOG_OFF;
1624 case SDL_LOG_PRIORITY_VERBOSE:
1627 case SDL_LOG_PRIORITY_DEBUG:
1630 case SDL_LOG_PRIORITY_INFO:
1633 case SDL_LOG_PRIORITY_WARN:
1636 case SDL_LOG_PRIORITY_ERROR:
1639 case SDL_LOG_PRIORITY_CRITICAL:
1649static void SDLCALL winpr_LogOutputFunction(
void* userdata,
int category, SDL_LogPriority priority,
1650 const char* message)
1655 const DWORD level = sdlpriority2wlog(priority);
1656 auto log =
sdl->log;
1657 if (!WLog_IsLevelActive(log, level))
1660 WLog_PrintTextMessage(log, level, __LINE__, __FILE__, __func__,
"[%s] %s",
1661 category2str(category), message);
1664int main(
int argc,
char* argv[])
1667 sdl::win32::release_transient_console();
1672 RDP_CLIENT_ENTRY_POINTS clientEntryPoints = {};
1674 freerdp_client_warn_experimental(argc, argv);
1675 freerdp_client_warn_deprecated(argc, argv);
1677 "SDL2 client does not support clipboard! Only SDL3 client has (partial) support");
1679 RdpClientEntry(&clientEntryPoints);
1681 reinterpret_cast<sdl_rdp_context*
>(freerdp_client_context_new(&clientEntryPoints)),
1686 auto sdl = sdl_rdp->sdl;
1688 auto settings =
sdl->context()->settings;
1689 WINPR_ASSERT(settings);
1691 status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE);
1694 rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
1696 sdl_list_monitors(
sdl);
1701 case COMMAND_LINE_STATUS_PRINT:
1702 case COMMAND_LINE_STATUS_PRINT_VERSION:
1703 case COMMAND_LINE_STATUS_PRINT_BUILDCONFIG:
1705 case COMMAND_LINE_STATUS_PRINT_HELP:
1707 SdlPref::print_config_file_help(2);
1714 SDL_LogSetOutputFunction(winpr_LogOutputFunction,
sdl);
1715 auto level = WLog_GetLogLevel(
sdl->log);
1716 SDL_LogSetAllPriority(wloglevel2dl(level));
1718 auto context =
sdl->context();
1719 WINPR_ASSERT(context);
1721 if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CREATE_REQUEST, FALSE))
1724 if (freerdp_client_start(context) != 0)
1729 if (freerdp_client_stop(context) != 0)
1732 if (
sdl->exit_code != 0)
1733 rc =
sdl->exit_code;
1738BOOL SdlContext::update_fullscreen(BOOL enter)
1740 std::scoped_lock lock(critical);
1741 for (
const auto& window : windows)
1743 if (!sdl_push_user_event(SDL_USEREVENT_WINDOW_FULLSCREEN, &window.second, enter))
1750BOOL SdlContext::update_minimize()
1752 std::scoped_lock lock(critical);
1753 return sdl_push_user_event(SDL_USEREVENT_WINDOW_MINIMIZE);
1756BOOL SdlContext::update_resizeable(BOOL enable)
1758 std::scoped_lock lock(critical);
1760 const auto settings = context()->settings;
1763 BOOL use = (dyn && enable) || smart;
1765 for (
const auto& window : windows)
1767 if (!sdl_push_user_event(SDL_USEREVENT_WINDOW_RESIZEABLE, &window.second, use))
1775SdlContext::SdlContext(rdpContext* context)
1776 : _context(context), log(WLog_Get(SDL_TAG)), update_complete(true), disp(this), input(this),
1777 primary(nullptr, SDL_FreeSurface), primary_format(nullptr, SDL_FreeFormat),
1778 rdp_thread_running(false)
1780 WINPR_ASSERT(context);
1784rdpContext* SdlContext::context()
const
1789rdpClientContext* SdlContext::common()
const
1791 return reinterpret_cast<rdpClientContext*
>(_context);
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 BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 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_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.