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.