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_config.hpp> 
   66#if defined(WITH_WEBVIEW) 
   67#include <aad/sdl_webview.hpp> 
   70#define SDL_TAG CLIENT_TAG("SDL") 
   76  SDL_EXIT_DISCONNECT = 1,
 
   78  SDL_EXIT_IDLE_TIMEOUT = 3,
 
   79  SDL_EXIT_LOGON_TIMEOUT = 4,
 
   80  SDL_EXIT_CONN_REPLACED = 5,
 
   81  SDL_EXIT_OUT_OF_MEMORY = 6,
 
   82  SDL_EXIT_CONN_DENIED = 7,
 
   83  SDL_EXIT_CONN_DENIED_FIPS = 8,
 
   84  SDL_EXIT_USER_PRIVILEGES = 9,
 
   85  SDL_EXIT_FRESH_CREDENTIALS_REQUIRED = 10,
 
   86  SDL_EXIT_DISCONNECT_BY_USER = 11,
 
   89  SDL_EXIT_LICENSE_INTERNAL = 16,
 
   90  SDL_EXIT_LICENSE_NO_LICENSE_SERVER = 17,
 
   91  SDL_EXIT_LICENSE_NO_LICENSE = 18,
 
   92  SDL_EXIT_LICENSE_BAD_CLIENT_MSG = 19,
 
   93  SDL_EXIT_LICENSE_HWID_DOESNT_MATCH = 20,
 
   94  SDL_EXIT_LICENSE_BAD_CLIENT = 21,
 
   95  SDL_EXIT_LICENSE_CANT_FINISH_PROTOCOL = 22,
 
   96  SDL_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL = 23,
 
   97  SDL_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION = 24,
 
   98  SDL_EXIT_LICENSE_CANT_UPGRADE = 25,
 
   99  SDL_EXIT_LICENSE_NO_REMOTE_CONNECTIONS = 26,
 
  105  SDL_EXIT_PARSE_ARGUMENTS = 128,
 
  106  SDL_EXIT_MEMORY = 129,
 
  107  SDL_EXIT_PROTOCOL = 130,
 
  108  SDL_EXIT_CONN_FAILED = 131,
 
  109  SDL_EXIT_AUTH_FAILURE = 132,
 
  110  SDL_EXIT_NEGO_FAILURE = 133,
 
  111  SDL_EXIT_LOGON_FAILURE = 134,
 
  112  SDL_EXIT_ACCOUNT_LOCKED_OUT = 135,
 
  113  SDL_EXIT_PRE_CONNECT_FAILED = 136,
 
  114  SDL_EXIT_CONNECT_UNDEFINED = 137,
 
  115  SDL_EXIT_POST_CONNECT_FAILED = 138,
 
  116  SDL_EXIT_DNS_ERROR = 139,
 
  117  SDL_EXIT_DNS_NAME_NOT_FOUND = 140,
 
  118  SDL_EXIT_CONNECT_FAILED = 141,
 
  119  SDL_EXIT_MCS_CONNECT_INITIAL_ERROR = 142,
 
  120  SDL_EXIT_TLS_CONNECT_FAILED = 143,
 
  121  SDL_EXIT_INSUFFICIENT_PRIVILEGES = 144,
 
  122  SDL_EXIT_CONNECT_CANCELLED = 145,
 
  124  SDL_EXIT_CONNECT_TRANSPORT_FAILED = 147,
 
  125  SDL_EXIT_CONNECT_PASSWORD_EXPIRED = 148,
 
  126  SDL_EXIT_CONNECT_PASSWORD_MUST_CHANGE = 149,
 
  127  SDL_EXIT_CONNECT_KDC_UNREACHABLE = 150,
 
  128  SDL_EXIT_CONNECT_ACCOUNT_DISABLED = 151,
 
  129  SDL_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED = 152,
 
  130  SDL_EXIT_CONNECT_CLIENT_REVOKED = 153,
 
  131  SDL_EXIT_CONNECT_WRONG_PASSWORD = 154,
 
  132  SDL_EXIT_CONNECT_ACCESS_DENIED = 155,
 
  133  SDL_EXIT_CONNECT_ACCOUNT_RESTRICTION = 156,
 
  134  SDL_EXIT_CONNECT_ACCOUNT_EXPIRED = 157,
 
  135  SDL_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED = 158,
 
  136  SDL_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS = 159,
 
  138  SDL_EXIT_UNKNOWN = 255,
 
  141struct sdl_exit_code_map_t
 
  145  const char* code_tag;
 
  148#define ENTRY(x, y) { x, y, #y } 
  149static const struct sdl_exit_code_map_t sdl_exit_code_map[] = {
 
  150  ENTRY(FREERDP_ERROR_SUCCESS, SDL_EXIT_SUCCESS), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_DISCONNECT),
 
  151  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LOGOFF), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_IDLE_TIMEOUT),
 
  152  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LOGON_TIMEOUT),
 
  153  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_REPLACED),
 
  154  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_OUT_OF_MEMORY),
 
  155  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_DENIED),
 
  156  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_DENIED_FIPS),
 
  157  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_USER_PRIVILEGES),
 
  158  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_FRESH_CREDENTIALS_REQUIRED),
 
  159  ENTRY(ERRINFO_LOGOFF_BY_USER, SDL_EXIT_DISCONNECT_BY_USER),
 
  160  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_UNKNOWN),
 
  163  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_INTERNAL),
 
  164  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_LICENSE_SERVER),
 
  165  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_LICENSE),
 
  166  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT_MSG),
 
  167  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_HWID_DOESNT_MATCH),
 
  168  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT),
 
  169  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_FINISH_PROTOCOL),
 
  170  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CLIENT_ENDED_PROTOCOL),
 
  171  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_BAD_CLIENT_ENCRYPTION),
 
  172  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_UPGRADE),
 
  173  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_NO_REMOTE_CONNECTIONS),
 
  174  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_LICENSE_CANT_UPGRADE),
 
  177  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_RDP),
 
  180  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_PARSE_ARGUMENTS), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_MEMORY),
 
  181  ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_PROTOCOL), ENTRY(FREERDP_ERROR_NONE, SDL_EXIT_CONN_FAILED),
 
  183  ENTRY(FREERDP_ERROR_AUTHENTICATION_FAILED, SDL_EXIT_AUTH_FAILURE),
 
  184  ENTRY(FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED, SDL_EXIT_NEGO_FAILURE),
 
  185  ENTRY(FREERDP_ERROR_CONNECT_LOGON_FAILURE, SDL_EXIT_LOGON_FAILURE),
 
  186  ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT, SDL_EXIT_ACCOUNT_LOCKED_OUT),
 
  187  ENTRY(FREERDP_ERROR_PRE_CONNECT_FAILED, SDL_EXIT_PRE_CONNECT_FAILED),
 
  188  ENTRY(FREERDP_ERROR_CONNECT_UNDEFINED, SDL_EXIT_CONNECT_UNDEFINED),
 
  189  ENTRY(FREERDP_ERROR_POST_CONNECT_FAILED, SDL_EXIT_POST_CONNECT_FAILED),
 
  190  ENTRY(FREERDP_ERROR_DNS_ERROR, SDL_EXIT_DNS_ERROR),
 
  191  ENTRY(FREERDP_ERROR_DNS_NAME_NOT_FOUND, SDL_EXIT_DNS_NAME_NOT_FOUND),
 
  192  ENTRY(FREERDP_ERROR_CONNECT_FAILED, SDL_EXIT_CONNECT_FAILED),
 
  193  ENTRY(FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR, SDL_EXIT_MCS_CONNECT_INITIAL_ERROR),
 
  194  ENTRY(FREERDP_ERROR_TLS_CONNECT_FAILED, SDL_EXIT_TLS_CONNECT_FAILED),
 
  195  ENTRY(FREERDP_ERROR_INSUFFICIENT_PRIVILEGES, SDL_EXIT_INSUFFICIENT_PRIVILEGES),
 
  196  ENTRY(FREERDP_ERROR_CONNECT_CANCELLED, SDL_EXIT_CONNECT_CANCELLED),
 
  197  ENTRY(FREERDP_ERROR_CONNECT_TRANSPORT_FAILED, SDL_EXIT_CONNECT_TRANSPORT_FAILED),
 
  198  ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED, SDL_EXIT_CONNECT_PASSWORD_EXPIRED),
 
  199  ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE, SDL_EXIT_CONNECT_PASSWORD_MUST_CHANGE),
 
  200  ENTRY(FREERDP_ERROR_CONNECT_KDC_UNREACHABLE, SDL_EXIT_CONNECT_KDC_UNREACHABLE),
 
  201  ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED, SDL_EXIT_CONNECT_ACCOUNT_DISABLED),
 
  202  ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED,
 
  203        SDL_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED),
 
  204  ENTRY(FREERDP_ERROR_CONNECT_CLIENT_REVOKED, SDL_EXIT_CONNECT_CLIENT_REVOKED),
 
  205  ENTRY(FREERDP_ERROR_CONNECT_WRONG_PASSWORD, SDL_EXIT_CONNECT_WRONG_PASSWORD),
 
  206  ENTRY(FREERDP_ERROR_CONNECT_ACCESS_DENIED, SDL_EXIT_CONNECT_ACCESS_DENIED),
 
  207  ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION, SDL_EXIT_CONNECT_ACCOUNT_RESTRICTION),
 
  208  ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED, SDL_EXIT_CONNECT_ACCOUNT_EXPIRED),
 
  209  ENTRY(FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED, SDL_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED),
 
  210  ENTRY(FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS,
 
  211        SDL_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS)
 
  214static const struct sdl_exit_code_map_t* sdl_map_entry_by_code(
int exit_code)
 
  216  for (
const auto& x : sdl_exit_code_map)
 
  218    const struct sdl_exit_code_map_t* cur = &x;
 
  219    if (cur->code == exit_code)
 
  225static void sdl_hide_connection_dialog(
SdlContext* sdl)
 
  228  std::lock_guard<CriticalSection> lock(sdl->critical);
 
  229  if (sdl->connection_dialog)
 
  230    sdl->connection_dialog->hide();
 
  233static const struct sdl_exit_code_map_t* sdl_map_entry_by_error(UINT32 error)
 
  235  for (
const auto& x : sdl_exit_code_map)
 
  237    const struct sdl_exit_code_map_t* cur = &x;
 
  238    if (cur->error == 
static_cast<uint32_t
>(error))
 
  244static int sdl_map_error_to_exit_code(UINT32 error)
 
  246  const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_error(error);
 
  250  return SDL_EXIT_CONN_FAILED;
 
  253static const char* sdl_map_error_to_code_tag(UINT32 error)
 
  255  const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_error(error);
 
  257    return entry->code_tag;
 
  261static const char* sdl_map_to_code_tag(
int code)
 
  263  const struct sdl_exit_code_map_t* entry = sdl_map_entry_by_code(code);
 
  265    return entry->code_tag;
 
  269static int error_info_to_error(freerdp* instance, DWORD* pcode, 
char** msg, 
size_t* len)
 
  271  const DWORD code = freerdp_error_info(instance);
 
  272  const char* name = freerdp_get_error_info_name(code);
 
  273  const char* str = freerdp_get_error_info_string(code);
 
  274  const int exit_code = sdl_map_error_to_exit_code(code);
 
  276  winpr_asprintf(msg, len, 
"Terminate with %s due to ERROR_INFO %s [0x%08" PRIx32 
"]: %s",
 
  277                 sdl_map_error_to_code_tag(code), name, code, str);
 
  278  WLog_DBG(SDL_TAG, 
"%s", *msg);
 
  286static BOOL sdl_begin_paint(rdpContext* context)
 
  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();
 
  303  auto gdi = context->gdi;
 
  305  WINPR_ASSERT(gdi->primary);
 
  307  HGDI_DC hdc = gdi->primary->hdc;
 
  313  WINPR_ASSERT(hwnd->invalid);
 
  314  hwnd->invalid->null = TRUE;
 
  324  auto gdi = sdl->context()->gdi;
 
  325  return gdi_send_suppress_output(gdi, FALSE);
 
  328class SdlEventUpdateTriggerGuard
 
  334  explicit SdlEventUpdateTriggerGuard(
SdlContext* sdl) : _sdl(sdl)
 
  337  ~SdlEventUpdateTriggerGuard()
 
  339    _sdl->update_complete.set();
 
  341  SdlEventUpdateTriggerGuard(
const SdlEventUpdateTriggerGuard&) = 
delete;
 
  342  SdlEventUpdateTriggerGuard(SdlEventUpdateTriggerGuard&&) = 
delete;
 
  343  SdlEventUpdateTriggerGuard& operator=(
const SdlEventUpdateTriggerGuard&) = 
delete;
 
  344  SdlEventUpdateTriggerGuard& operator=(SdlEventUpdateTriggerGuard&&) = 
delete;
 
  348                                    SDL_Surface* surface, SDL_Point offset, SDL_Rect srcRect)
 
  350  SDL_Rect dstRect = { offset.x + srcRect.x, offset.y + srcRect.y, srcRect.w, srcRect.h };
 
  351  return window.blit(surface, srcRect, dstRect);
 
  354static bool sdl_draw_to_window_rect(
SdlContext* sdl, 
SdlWindow& window, SDL_Surface* surface,
 
  355                                    SDL_Point offset, 
const std::vector<SDL_Rect>& rects = {})
 
  359    return sdl_draw_to_window_rect(sdl, window, surface, offset,
 
  360                                   { 0, 0, surface->w, surface->h });
 
  362  for (
auto& srcRect : rects)
 
  364    if (!sdl_draw_to_window_rect(sdl, window, surface, offset, srcRect))
 
  370static bool sdl_draw_to_window_scaled_rect(
SdlContext* sdl, 
SdlWindow& window, SDL_Surface* surface,
 
  373  SDL_Rect dstRect = srcRect;
 
  374  sdl_scale_coordinates(sdl, window.id(), &dstRect.x, &dstRect.y, FALSE, TRUE);
 
  375  sdl_scale_coordinates(sdl, window.id(), &dstRect.w, &dstRect.h, FALSE, TRUE);
 
  376  return window.blit(surface, srcRect, dstRect);
 
  379static BOOL sdl_draw_to_window_scaled_rect(
SdlContext* sdl, 
SdlWindow& window, SDL_Surface* surface,
 
  380                                           const std::vector<SDL_Rect>& rects = {})
 
  384    return sdl_draw_to_window_scaled_rect(sdl, window, surface,
 
  385                                          { 0, 0, surface->w, surface->h });
 
  387  for (
const auto& srcRect : rects)
 
  389    if (!sdl_draw_to_window_scaled_rect(sdl, window, surface, srcRect))
 
  396                               const std::vector<SDL_Rect>& rects = {})
 
  400  auto context = sdl->context();
 
  401  auto gdi = context->gdi;
 
  403  auto size = window.rect();
 
  407    if (gdi->width < size.w)
 
  409      window.setOffsetX((size.w - gdi->width) / 2);
 
  411    if (gdi->height < size.h)
 
  413      window.setOffsetY((size.h - gdi->height) / 2);
 
  416    auto surface = sdl->primary.get();
 
  417    if (!sdl_draw_to_window_rect(sdl, window, surface, { window.offsetX(), window.offsetY() },
 
  423    if (!sdl_draw_to_window_scaled_rect(sdl, window, sdl->primary.get(), rects))
 
  426  window.updateSurface();
 
  430static BOOL sdl_draw_to_window(
SdlContext* sdl, std::map<Uint32, SdlWindow>& windows,
 
  431                               const std::vector<SDL_Rect>& rects = {})
 
  433  for (
auto& window : windows)
 
  435    if (!sdl_draw_to_window(sdl, window.second, rects))
 
  442static BOOL sdl_end_paint_process(rdpContext* context)
 
  444  auto sdl = get_context(context);
 
  446  WINPR_ASSERT(context);
 
  448  SdlEventUpdateTriggerGuard guard(sdl);
 
  450  auto gdi = context->gdi;
 
  452  WINPR_ASSERT(gdi->primary);
 
  454  HGDI_DC hdc = gdi->primary->hdc;
 
  460  WINPR_ASSERT(hwnd->invalid || (hwnd->ninvalid == 0));
 
  462  if (hwnd->invalid->null)
 
  465  WINPR_ASSERT(hwnd->invalid);
 
  466  if (gdi->suppressOutput || hwnd->invalid->null)
 
  469  const INT32 ninvalid = hwnd->ninvalid;
 
  470  const GDI_RGN* cinvalid = hwnd->cinvalid;
 
  475  std::vector<SDL_Rect> rects;
 
  476  for (INT32 x = 0; x < ninvalid; x++)
 
  478    auto& rgn = cinvalid[x];
 
  479    rects.push_back({ rgn.x, rgn.y, rgn.w, rgn.h });
 
  482  return sdl_draw_to_window(sdl, sdl->windows, rects);
 
  489static BOOL sdl_end_paint(rdpContext* context)
 
  491  auto sdl = get_context(context);
 
  494  std::lock_guard<CriticalSection> lock(sdl->critical);
 
  495  const BOOL rc = sdl_push_user_event(SDL_USEREVENT_UPDATE, context);
 
  500static void sdl_destroy_primary(
SdlContext* sdl)
 
  504  sdl->primary.reset();
 
  505  sdl->primary_format.reset();
 
  509static BOOL sdl_create_primary(
SdlContext* sdl)
 
  511  rdpGdi* gdi = 
nullptr;
 
  515  gdi = sdl->context()->gdi;
 
  518  sdl_destroy_primary(sdl);
 
  519  sdl->primary = SDLSurfacePtr(
 
  520      SDL_CreateRGBSurfaceWithFormatFrom(gdi->primary_buffer, 
static_cast<int>(gdi->width),
 
  521                                         static_cast<int>(gdi->height),
 
  522                                         static_cast<int>(FreeRDPGetBitsPerPixel(gdi->dstFormat)),
 
  523                                         static_cast<int>(gdi->stride), sdl->sdl_pixel_format),
 
  525  sdl->primary_format = SDLPixelFormatPtr(SDL_AllocFormat(sdl->sdl_pixel_format), SDL_FreeFormat);
 
  527  if (!sdl->primary || !sdl->primary_format)
 
  530  SDL_SetSurfaceBlendMode(sdl->primary.get(), SDL_BLENDMODE_NONE);
 
  531  SDL_FillRect(sdl->primary.get(), 
nullptr,
 
  532               SDL_MapRGBA(sdl->primary_format.get(), 0, 0, 0, 0xff));
 
  537static BOOL sdl_desktop_resize(rdpContext* context)
 
  539  rdpGdi* gdi = 
nullptr;
 
  540  rdpSettings* settings = 
nullptr;
 
  541  auto sdl = get_context(context);
 
  544  WINPR_ASSERT(context);
 
  546  settings = context->settings;
 
  547  WINPR_ASSERT(settings);
 
  549  std::lock_guard<CriticalSection> lock(sdl->critical);
 
  554  return sdl_create_primary(sdl);
 
  558static BOOL sdl_play_sound(rdpContext* context, 
const PLAY_SOUND_UPDATE* play_sound)
 
  561  WINPR_UNUSED(context);
 
  562  WINPR_UNUSED(play_sound);
 
  569  sdl->initialize.set();
 
  571  HANDLE handles[] = { sdl->initialized.handle(), freerdp_abort_event(sdl->context()) };
 
  573  const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
 
  585static BOOL sdl_pre_connect(freerdp* instance)
 
  587  WINPR_ASSERT(instance);
 
  588  WINPR_ASSERT(instance->context);
 
  590  auto sdl = get_context(instance->context);
 
  592  auto settings = instance->context->settings;
 
  593  WINPR_ASSERT(settings);
 
  608  PubSub_SubscribeChannelConnected(instance->context->pubSub, sdl_OnChannelConnectedEventHandler);
 
  609  PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
 
  610                                      sdl_OnChannelDisconnectedEventHandler);
 
  615    UINT32 maxHeight = 0;
 
  617    if (!sdl_wait_for_init(sdl))
 
  620    std::lock_guard<CriticalSection> lock(sdl->critical);
 
  622      sdl->connection_dialog = std::make_unique<SDLConnectionDialog>(instance->context);
 
  623    if (sdl->connection_dialog)
 
  625      sdl->connection_dialog->setTitle(
"Connecting to '%s'",
 
  627      sdl->connection_dialog->showInfo(
 
  628          "The connection is being established\n\nPlease wait...");
 
  630    if (!sdl_detect_monitors(sdl, &maxWidth, &maxHeight))
 
  633    if ((maxWidth != 0) && (maxHeight != 0) &&
 
  636      WLog_Print(sdl->log, WLOG_INFO, 
"Update size to %ux%u", maxWidth, maxHeight);
 
  648      WLog_Print(sdl->log, WLOG_INFO, 
"auth-only, but no password set. Please provide one.");
 
  655    WLog_Print(sdl->log, WLOG_INFO, 
"Authentication only. Don't connect SDL.");
 
  662static const char* sdl_window_get_title(rdpSettings* settings)
 
  664  const char* windowTitle = 
nullptr;
 
  667  const char* name = 
nullptr;
 
  668  const char* prefix = 
"FreeRDP:";
 
  680  addPort = (port != 3389);
 
  682  char buffer[MAX_PATH + 64] = {};
 
  685    (void)sprintf_s(buffer, 
sizeof(buffer), 
"%s %s", prefix, name);
 
  687    (
void)sprintf_s(buffer, 
sizeof(buffer), 
"%s %s:%" PRIu32, prefix, name, port);
 
  694static void sdl_term_handler([[maybe_unused]] 
int signum, [[maybe_unused]] 
const char* signame,
 
  695                             [[maybe_unused]] 
void* context)
 
  705  std::lock_guard<CriticalSection> lock(sdl->critical);
 
  706  sdl->windows.clear();
 
  707  sdl->connection_dialog.reset();
 
  709  sdl_destroy_primary(sdl);
 
  711  freerdp_del_signal_cleanup_handler(sdl->context(), sdl_term_handler);
 
  716static BOOL sdl_create_windows(
SdlContext* sdl)
 
  720  auto settings = sdl->context()->settings;
 
  721  auto title = sdl_window_get_title(settings);
 
  723  ScopeGuard guard([&]() { sdl->windows_created.set(); });
 
  727  for (UINT32 x = 0; x < windowCount; x++)
 
  729    auto id = sdl_monitor_id_for_index(sdl, x);
 
  733        freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x));
 
  735    Uint32 w = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
 
  736    Uint32 h = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
 
  744    Uint32 flags = SDL_WINDOW_SHOWN;
 
  745    auto startupX = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
 
  746    auto startupY = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
 
  748    if (monitor->attributes.desktopScaleFactor > 100)
 
  750#if SDL_VERSION_ATLEAST(2, 0, 1) 
  751      flags |= SDL_WINDOW_ALLOW_HIGHDPI;
 
  758      flags |= SDL_WINDOW_FULLSCREEN;
 
  763      flags |= SDL_WINDOW_BORDERLESS;
 
  767      flags |= SDL_WINDOW_BORDERLESS;
 
  770                    static_cast<int>(startupX),
 
  771                    static_cast<int>(startupY),
 
  776    if (!window.window())
 
  781      auto r = window.rect();
 
  782      window.setOffsetX(0 - r.x);
 
  783      window.setOffsetY(0 - r.y);
 
  786    sdl->windows.insert({ window.id(), std::move(window) });
 
  792static BOOL sdl_wait_create_windows(
SdlContext* sdl)
 
  794  std::lock_guard<CriticalSection> lock(sdl->critical);
 
  795  sdl->windows_created.clear();
 
  796  if (!sdl_push_user_event(SDL_USEREVENT_CREATE_WINDOWS, sdl))
 
  799  HANDLE handles[] = { sdl->initialized.handle(), freerdp_abort_event(sdl->context()) };
 
  801  const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
 
  813  std::lock_guard<CriticalSection> lock(sdl->critical);
 
  814  if (freerdp_shall_disconnect_context(sdl->context()))
 
  816    if (sdl->rdp_thread_running)
 
  818    if (!sdl->connection_dialog)
 
  820    return !sdl->connection_dialog->running();
 
  830  HANDLE handles[] = { sdl->initialize.handle(), freerdp_abort_event(sdl->context()) };
 
  831  const DWORD status = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
 
  840  SDL_Init(SDL_INIT_VIDEO);
 
  842#if SDL_VERSION_ATLEAST(2, 0, 16) 
  843  SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, 
"0");
 
  845#if SDL_VERSION_ATLEAST(2, 0, 8) 
  846  SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, 
"0");
 
  849  freerdp_add_signal_cleanup_handler(sdl->context(), sdl_term_handler);
 
  851  sdl->initialized.set();
 
  853  while (!shall_abort(sdl))
 
  855    SDL_Event windowEvent = {};
 
  856    while (!shall_abort(sdl) && SDL_WaitEventTimeout(
nullptr, 1000))
 
  861      const int prc = SDL_PeepEvents(&windowEvent, 1, SDL_GETEVENT, SDL_FIRSTEVENT,
 
  862                                     SDL_USEREVENT_RETRY_DIALOG);
 
  865        if (sdl_log_error(prc, sdl->log, 
"SDL_PeepEvents"))
 
  869#if defined(WITH_DEBUG_SDL_EVENTS) 
  870      SDL_Log(
"got event %s [0x%08" PRIx32 
"]", sdl_event_type_str(windowEvent.type),
 
  873      std::lock_guard<CriticalSection> lock(sdl->critical);
 
  876      if (freerdp_shall_disconnect_context(sdl->context()))
 
  879      if (sdl->connection_dialog)
 
  881        if (sdl->connection_dialog->handle(windowEvent))
 
  887      switch (windowEvent.type)
 
  890          freerdp_abort_connect_context(sdl->context());
 
  895          const SDL_KeyboardEvent* ev = &windowEvent.key;
 
  896          sdl->input.keyboard_handle_event(ev);
 
  899        case SDL_KEYMAPCHANGED:
 
  903        case SDL_MOUSEMOTION:
 
  905          const SDL_MouseMotionEvent* ev = &windowEvent.motion;
 
  906          sdl_handle_mouse_motion(sdl, ev);
 
  909        case SDL_MOUSEBUTTONDOWN:
 
  910        case SDL_MOUSEBUTTONUP:
 
  912          const SDL_MouseButtonEvent* ev = &windowEvent.button;
 
  913          sdl_handle_mouse_button(sdl, ev);
 
  918          const SDL_MouseWheelEvent* ev = &windowEvent.wheel;
 
  919          sdl_handle_mouse_wheel(sdl, ev);
 
  924          const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
 
  925          sdl_handle_touch_down(sdl, ev);
 
  930          const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
 
  931          sdl_handle_touch_up(sdl, ev);
 
  934        case SDL_FINGERMOTION:
 
  936          const SDL_TouchFingerEvent* ev = &windowEvent.tfinger;
 
  937          sdl_handle_touch_motion(sdl, ev);
 
  940#if SDL_VERSION_ATLEAST(2, 0, 10) 
  941        case SDL_DISPLAYEVENT:
 
  943          const SDL_DisplayEvent* ev = &windowEvent.display;
 
  944          sdl->disp.handle_display_event(ev);
 
  948        case SDL_WINDOWEVENT:
 
  950          const SDL_WindowEvent* ev = &windowEvent.window;
 
  951          auto window = sdl->windows.find(ev->windowID);
 
  952          if (window != sdl->windows.end())
 
  953            sdl->disp.handle_window_event(ev);
 
  956            case SDL_WINDOWEVENT_RESIZED:
 
  957            case SDL_WINDOWEVENT_SIZE_CHANGED:
 
  959              if (window != sdl->windows.end())
 
  961                window->second.fill();
 
  962                window->second.updateSurface();
 
  966            case SDL_WINDOWEVENT_MOVED:
 
  968              if (window != sdl->windows.end())
 
  970                auto r = window->second.rect();
 
  971                auto id = window->second.id();
 
  972                WLog_DBG(SDL_TAG, 
"%lu: %dx%d-%dx%d", 
id, r.x, r.y, r.w, r.h);
 
  982        case SDL_RENDER_TARGETS_RESET:
 
  985        case SDL_RENDER_DEVICE_RESET:
 
  988        case SDL_APP_WILLENTERFOREGROUND:
 
  991        case SDL_USEREVENT_CERT_DIALOG:
 
  993          auto title = 
static_cast<const char*
>(windowEvent.user.data1);
 
  994          auto msg = 
static_cast<const char*
>(windowEvent.user.data2);
 
  995          sdl_cert_dialog_show(title, msg);
 
  998        case SDL_USEREVENT_SHOW_DIALOG:
 
 1000          auto title = 
static_cast<const char*
>(windowEvent.user.data1);
 
 1001          auto msg = 
static_cast<const char*
>(windowEvent.user.data2);
 
 1002          sdl_message_dialog_show(title, msg, windowEvent.user.code);
 
 1005        case SDL_USEREVENT_SCARD_DIALOG:
 
 1007          auto title = 
static_cast<const char*
>(windowEvent.user.data1);
 
 1008          auto msg = 
static_cast<const char**
>(windowEvent.user.data2);
 
 1009          sdl_scard_dialog_show(title, windowEvent.user.code, msg);
 
 1012        case SDL_USEREVENT_AUTH_DIALOG:
 
 1013          sdl_auth_dialog_show(
 
 1016        case SDL_USEREVENT_UPDATE:
 
 1018          auto context = 
static_cast<rdpContext*
>(windowEvent.user.data1);
 
 1019          sdl_end_paint_process(context);
 
 1022        case SDL_USEREVENT_CREATE_WINDOWS:
 
 1024          auto ctx = 
static_cast<SdlContext*
>(windowEvent.user.data1);
 
 1025          sdl_create_windows(ctx);
 
 1028        case SDL_USEREVENT_WINDOW_RESIZEABLE:
 
 1030          auto window = 
static_cast<SdlWindow*
>(windowEvent.user.data1);
 
 1031          const SDL_bool use = windowEvent.user.code != 0 ? SDL_TRUE : SDL_FALSE;
 
 1033            window->resizeable(use);
 
 1036        case SDL_USEREVENT_WINDOW_FULLSCREEN:
 
 1038          auto window = 
static_cast<SdlWindow*
>(windowEvent.user.data1);
 
 1039          const SDL_bool enter = windowEvent.user.code != 0 ? SDL_TRUE : SDL_FALSE;
 
 1041            window->fullscreen(enter);
 
 1044        case SDL_USEREVENT_WINDOW_MINIMIZE:
 
 1046          for (
auto& window : sdl->windows)
 
 1048            window.second.minimize();
 
 1052        case SDL_USEREVENT_POINTER_NULL:
 
 1053          SDL_ShowCursor(SDL_DISABLE);
 
 1055        case SDL_USEREVENT_POINTER_DEFAULT:
 
 1057          SDL_Cursor* def = SDL_GetDefaultCursor();
 
 1059          SDL_ShowCursor(SDL_ENABLE);
 
 1062        case SDL_USEREVENT_POINTER_POSITION:
 
 1065              static_cast<INT32
>(
reinterpret_cast<uintptr_t
>(windowEvent.user.data1));
 
 1067              static_cast<INT32
>(
reinterpret_cast<uintptr_t
>(windowEvent.user.data2));
 
 1069          SDL_Window* window = SDL_GetMouseFocus();
 
 1072            const Uint32 
id = SDL_GetWindowID(window);
 
 1076            if (sdl_scale_coordinates(sdl, 
id, &sx, &sy, FALSE, FALSE))
 
 1077              SDL_WarpMouseInWindow(window, sx, sy);
 
 1081        case SDL_USEREVENT_POINTER_SET:
 
 1082          sdl_Pointer_Set_Process(&windowEvent.user);
 
 1084        case SDL_USEREVENT_QUIT:
 
 1093  sdl_cleanup_sdl(sdl);
 
 1105static BOOL sdl_post_connect(freerdp* instance)
 
 1107  WINPR_ASSERT(instance);
 
 1109  auto context = instance->context;
 
 1110  WINPR_ASSERT(context);
 
 1112  auto sdl = get_context(context);
 
 1115  sdl_hide_connection_dialog(sdl);
 
 1122      WLog_Print(sdl->log, WLOG_INFO, 
"auth-only, but no password set. Please provide one.");
 
 1126    WLog_Print(sdl->log, WLOG_INFO, 
"Authentication only. Don't connect to X.");
 
 1130  if (!sdl_wait_create_windows(sdl))
 
 1133  sdl->sdl_pixel_format = SDL_PIXELFORMAT_BGRA32;
 
 1134  if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
 
 1137  if (!sdl_create_primary(sdl))
 
 1140  if (!sdl_register_pointer(instance->context->graphics))
 
 1143  WINPR_ASSERT(context->update);
 
 1145  context->update->BeginPaint = sdl_begin_paint;
 
 1146  context->update->EndPaint = sdl_end_paint;
 
 1147  context->update->PlaySound = sdl_play_sound;
 
 1148  context->update->DesktopResize = sdl_desktop_resize;
 
 1149  context->update->SetKeyboardIndicators = sdlInput::keyboard_set_indicators;
 
 1150  context->update->SetKeyboardImeStatus = sdlInput::keyboard_set_ime_status;
 
 1152  sdl->update_resizeable(FALSE);
 
 1161static void sdl_post_disconnect(freerdp* instance)
 
 1166  if (!instance->context)
 
 1169  PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
 
 1170                                     sdl_OnChannelConnectedEventHandler);
 
 1171  PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
 
 1172                                        sdl_OnChannelDisconnectedEventHandler);
 
 1176static void sdl_post_final_disconnect(freerdp* instance)
 
 1181  if (!instance->context)
 
 1185static void sdl_client_cleanup(
SdlContext* sdl, 
int exit_code, 
const std::string& error_msg)
 
 1189  rdpContext* context = sdl->context();
 
 1190  WINPR_ASSERT(context);
 
 1192  rdpSettings* settings = context->settings;
 
 1193  WINPR_ASSERT(settings);
 
 1195  sdl->rdp_thread_running = 
false;
 
 1196  bool showError = 
false;
 
 1198    WLog_Print(sdl->log, WLOG_INFO, 
"Authentication only, exit status %s [%" PRId32 
"]",
 
 1199               sdl_map_to_code_tag(exit_code), exit_code);
 
 1204      case SDL_EXIT_SUCCESS:
 
 1205      case SDL_EXIT_DISCONNECT:
 
 1206      case SDL_EXIT_LOGOFF:
 
 1207      case SDL_EXIT_DISCONNECT_BY_USER:
 
 1208      case SDL_EXIT_CONNECT_CANCELLED:
 
 1212        std::lock_guard<CriticalSection> lock(sdl->critical);
 
 1213        if (sdl->connection_dialog && !error_msg.empty())
 
 1215          sdl->connection_dialog->showError(error_msg.c_str());
 
 1224    sdl_hide_connection_dialog(sdl);
 
 1226  sdl->exit_code = exit_code;
 
 1227  sdl_push_user_event(SDL_USEREVENT_QUIT);
 
 1228#if SDL_VERSION_ATLEAST(2, 0, 16) 
 1233static int sdl_client_thread_connect(
SdlContext* sdl, std::string& error_msg)
 
 1237  auto instance = sdl->context()->instance;
 
 1238  WINPR_ASSERT(instance);
 
 1240  sdl->rdp_thread_running = 
true;
 
 1241  BOOL rc = freerdp_connect(instance);
 
 1243  rdpContext* context = sdl->context();
 
 1244  WINPR_ASSERT(context);
 
 1246  rdpSettings* settings = context->settings;
 
 1247  WINPR_ASSERT(settings);
 
 1249  int exit_code = SDL_EXIT_SUCCESS;
 
 1252    UINT32 error = freerdp_get_last_error(context);
 
 1253    exit_code = sdl_map_error_to_exit_code(error);
 
 1258    DWORD code = freerdp_get_last_error(context);
 
 1259    freerdp_abort_connect_context(context);
 
 1260    WLog_Print(sdl->log, WLOG_ERROR, 
"Authentication only, %s [0x%08" PRIx32 
"] %s",
 
 1261               freerdp_get_last_error_name(code), code, freerdp_get_last_error_string(code));
 
 1267    DWORD code = freerdp_error_info(instance);
 
 1268    if (exit_code == SDL_EXIT_SUCCESS)
 
 1270      char* msg = 
nullptr;
 
 1272      exit_code = error_info_to_error(instance, &code, &msg, &len);
 
 1278    auto last = freerdp_get_last_error(context);
 
 1279    if (error_msg.empty())
 
 1281      char* msg = 
nullptr;
 
 1283      winpr_asprintf(&msg, &len, 
"%s [0x%08" PRIx32 
"]\n%s",
 
 1284                     freerdp_get_last_error_name(last), last,
 
 1285                     freerdp_get_last_error_string(last));
 
 1291    if (exit_code == SDL_EXIT_SUCCESS)
 
 1293      if (last == FREERDP_ERROR_AUTHENTICATION_FAILED)
 
 1294        exit_code = SDL_EXIT_AUTH_FAILURE;
 
 1295      else if (code == ERRINFO_SUCCESS)
 
 1296        exit_code = SDL_EXIT_CONN_FAILED;
 
 1299    sdl_hide_connection_dialog(sdl);
 
 1304static int sdl_client_thread_run(
SdlContext* sdl, std::string& error_msg)
 
 1308  auto context = sdl->context();
 
 1309  WINPR_ASSERT(context);
 
 1311  auto instance = context->instance;
 
 1312  WINPR_ASSERT(instance);
 
 1314  int exit_code = SDL_EXIT_SUCCESS;
 
 1315  while (!freerdp_shall_disconnect_context(context))
 
 1317    HANDLE handles[MAXIMUM_WAIT_OBJECTS] = {};
 
 1323    if (freerdp_focus_required(instance))
 
 1325      auto ctx = get_context(context);
 
 1327      if (!ctx->input.keyboard_focus_in())
 
 1329      if (!ctx->input.keyboard_focus_in())
 
 1333    const DWORD nCount = freerdp_get_event_handles(context, handles, ARRAYSIZE(handles));
 
 1337      WLog_Print(sdl->log, WLOG_ERROR, 
"freerdp_get_event_handles failed");
 
 1341    const DWORD status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
 
 1343    if (status == WAIT_FAILED)
 
 1346    if (!freerdp_check_event_handles(context))
 
 1348      if (client_auto_reconnect(instance))
 
 1351        sdl_hide_connection_dialog(sdl);
 
 1360        if (freerdp_error_info(instance) == 0)
 
 1361          exit_code = SDL_EXIT_CONN_FAILED;
 
 1364      if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
 
 1365        WLog_Print(sdl->log, WLOG_ERROR, 
"WaitForMultipleObjects failed with %" PRIu32 
"",
 
 1367      if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
 
 1368        WLog_Print(sdl->log, WLOG_ERROR, 
"Failed to check FreeRDP event handles");
 
 1373  if (exit_code == SDL_EXIT_SUCCESS)
 
 1377      char* msg = 
nullptr;
 
 1379      exit_code = error_info_to_error(instance, &code, &msg, &len);
 
 1385    if ((code == ERRINFO_LOGOFF_BY_USER) &&
 
 1386        (freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested))
 
 1388      const char* msg = 
"Error info says user did not initiate but disconnect ultimatum says " 
 1389                        "they did; treat this as a user logoff";
 
 1390      char* emsg = 
nullptr;
 
 1392      winpr_asprintf(&emsg, &len, 
"%s", msg);
 
 1397      WLog_Print(sdl->log, WLOG_INFO, 
"%s", msg);
 
 1398      exit_code = SDL_EXIT_LOGOFF;
 
 1402  freerdp_disconnect(instance);
 
 1409static DWORD WINAPI sdl_client_thread_proc(
SdlContext* sdl)
 
 1413  std::string error_msg;
 
 1414  int exit_code = sdl_client_thread_connect(sdl, error_msg);
 
 1415  if (exit_code == SDL_EXIT_SUCCESS)
 
 1416    exit_code = sdl_client_thread_run(sdl, error_msg);
 
 1417  sdl_client_cleanup(sdl, exit_code, error_msg);
 
 1419  return static_cast<DWORD
>(exit_code);
 
 1425static BOOL sdl_client_global_init()
 
 1429  const DWORD wVersionRequested = MAKEWORD(1, 1);
 
 1430  const int rc = WSAStartup(wVersionRequested, &wsaData);
 
 1433    WLog_ERR(SDL_TAG, 
"WSAStartup failed with %s [%d]", gai_strerrorA(rc), rc);
 
 1438  return freerdp_handle_signals() != 0;
 
 1442static void sdl_client_global_uninit()
 
 1449static BOOL sdl_client_new(freerdp* instance, rdpContext* context)
 
 1453  if (!instance || !context)
 
 1460  instance->PreConnect = sdl_pre_connect;
 
 1461  instance->PostConnect = sdl_post_connect;
 
 1462  instance->PostDisconnect = sdl_post_disconnect;
 
 1463  instance->PostFinalDisconnect = sdl_post_final_disconnect;
 
 1464  instance->AuthenticateEx = sdl_authenticate_ex;
 
 1465  instance->VerifyCertificateEx = sdl_verify_certificate_ex;
 
 1466  instance->VerifyChangedCertificateEx = sdl_verify_changed_certificate_ex;
 
 1467  instance->LogonErrorInfo = sdl_logon_error_info;
 
 1468  instance->PresentGatewayMessage = sdl_present_gateway_message;
 
 1469  instance->ChooseSmartcard = sdl_choose_smartcard;
 
 1470  instance->RetryDialog = sdl_retry_dialog;
 
 1472#if defined(WITH_WEBVIEW) 
 1473  instance->GetAccessToken = sdl_webview_get_access_token;
 
 1475  instance->GetAccessToken = client_cli_get_access_token;
 
 1482static void sdl_client_free([[maybe_unused]] freerdp* instance, rdpContext* context)
 
 1492static int sdl_client_start(rdpContext* context)
 
 1494  auto sdl = get_context(context);
 
 1497  sdl->thread = std::thread(sdl_client_thread_proc, sdl);
 
 1501static int sdl_client_stop(rdpContext* context)
 
 1503  auto sdl = get_context(context);
 
 1508  HANDLE 
event = freerdp_abort_event(context);
 
 1509  if (!SetEvent(event))
 
 1516static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
 
 1518  WINPR_ASSERT(pEntryPoints);
 
 1520  ZeroMemory(pEntryPoints, 
sizeof(RDP_CLIENT_ENTRY_POINTS));
 
 1521  pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
 
 1522  pEntryPoints->Size = 
sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
 
 1523  pEntryPoints->GlobalInit = sdl_client_global_init;
 
 1524  pEntryPoints->GlobalUninit = sdl_client_global_uninit;
 
 1526  pEntryPoints->ClientNew = sdl_client_new;
 
 1527  pEntryPoints->ClientFree = sdl_client_free;
 
 1528  pEntryPoints->ClientStart = sdl_client_start;
 
 1529  pEntryPoints->ClientStop = sdl_client_stop;
 
 1536    freerdp_client_context_free(&sdl->common.context);
 
 1539static const char* category2str(
int category)
 
 1543    case SDL_LOG_CATEGORY_APPLICATION:
 
 1544      return "SDL_LOG_CATEGORY_APPLICATION";
 
 1545    case SDL_LOG_CATEGORY_ERROR:
 
 1546      return "SDL_LOG_CATEGORY_ERROR";
 
 1547    case SDL_LOG_CATEGORY_ASSERT:
 
 1548      return "SDL_LOG_CATEGORY_ASSERT";
 
 1549    case SDL_LOG_CATEGORY_SYSTEM:
 
 1550      return "SDL_LOG_CATEGORY_SYSTEM";
 
 1551    case SDL_LOG_CATEGORY_AUDIO:
 
 1552      return "SDL_LOG_CATEGORY_AUDIO";
 
 1553    case SDL_LOG_CATEGORY_VIDEO:
 
 1554      return "SDL_LOG_CATEGORY_VIDEO";
 
 1555    case SDL_LOG_CATEGORY_RENDER:
 
 1556      return "SDL_LOG_CATEGORY_RENDER";
 
 1557    case SDL_LOG_CATEGORY_INPUT:
 
 1558      return "SDL_LOG_CATEGORY_INPUT";
 
 1559    case SDL_LOG_CATEGORY_TEST:
 
 1560      return "SDL_LOG_CATEGORY_TEST";
 
 1561    case SDL_LOG_CATEGORY_RESERVED1:
 
 1562      return "SDL_LOG_CATEGORY_RESERVED1";
 
 1563    case SDL_LOG_CATEGORY_RESERVED2:
 
 1564      return "SDL_LOG_CATEGORY_RESERVED2";
 
 1565    case SDL_LOG_CATEGORY_RESERVED3:
 
 1566      return "SDL_LOG_CATEGORY_RESERVED3";
 
 1567    case SDL_LOG_CATEGORY_RESERVED4:
 
 1568      return "SDL_LOG_CATEGORY_RESERVED4";
 
 1569    case SDL_LOG_CATEGORY_RESERVED5:
 
 1570      return "SDL_LOG_CATEGORY_RESERVED5";
 
 1571    case SDL_LOG_CATEGORY_RESERVED6:
 
 1572      return "SDL_LOG_CATEGORY_RESERVED6";
 
 1573    case SDL_LOG_CATEGORY_RESERVED7:
 
 1574      return "SDL_LOG_CATEGORY_RESERVED7";
 
 1575    case SDL_LOG_CATEGORY_RESERVED8:
 
 1576      return "SDL_LOG_CATEGORY_RESERVED8";
 
 1577    case SDL_LOG_CATEGORY_RESERVED9:
 
 1578      return "SDL_LOG_CATEGORY_RESERVED9";
 
 1579    case SDL_LOG_CATEGORY_RESERVED10:
 
 1580      return "SDL_LOG_CATEGORY_RESERVED10";
 
 1581    case SDL_LOG_CATEGORY_CUSTOM:
 
 1583      return "SDL_LOG_CATEGORY_CUSTOM";
 
 1587static SDL_LogPriority wloglevel2dl(DWORD level)
 
 1592      return SDL_LOG_PRIORITY_VERBOSE;
 
 1594      return SDL_LOG_PRIORITY_DEBUG;
 
 1596      return SDL_LOG_PRIORITY_INFO;
 
 1598      return SDL_LOG_PRIORITY_WARN;
 
 1600      return SDL_LOG_PRIORITY_ERROR;
 
 1602      return SDL_LOG_PRIORITY_CRITICAL;
 
 1605      return SDL_LOG_PRIORITY_VERBOSE;
 
 1609static DWORD sdlpriority2wlog(SDL_LogPriority priority)
 
 1611  DWORD level = WLOG_OFF;
 
 1614    case SDL_LOG_PRIORITY_VERBOSE:
 
 1617    case SDL_LOG_PRIORITY_DEBUG:
 
 1620    case SDL_LOG_PRIORITY_INFO:
 
 1623    case SDL_LOG_PRIORITY_WARN:
 
 1626    case SDL_LOG_PRIORITY_ERROR:
 
 1629    case SDL_LOG_PRIORITY_CRITICAL:
 
 1639static void SDLCALL winpr_LogOutputFunction(
void* userdata, 
int category, SDL_LogPriority priority,
 
 1640                                            const char* message)
 
 1642  auto sdl = 
static_cast<SdlContext*
>(userdata);
 
 1645  const DWORD level = sdlpriority2wlog(priority);
 
 1646  auto log = sdl->log;
 
 1647  if (!WLog_IsLevelActive(log, level))
 
 1650  WLog_PrintTextMessage(log, level, __LINE__, __FILE__, __func__, 
"[%s] %s",
 
 1651                        category2str(category), message);
 
 1654int main(
int argc, 
char* argv[])
 
 1658  RDP_CLIENT_ENTRY_POINTS clientEntryPoints = {};
 
 1660  freerdp_client_warn_experimental(argc, argv);
 
 1661  freerdp_client_warn_deprecated(argc, argv);
 
 1663            "SDL2 client does not support clipboard! Only SDL3 client has (partial) support");
 
 1665  RdpClientEntry(&clientEntryPoints);
 
 1667      reinterpret_cast<sdl_rdp_context*
>(freerdp_client_context_new(&clientEntryPoints)),
 
 1672  auto sdl = sdl_rdp->sdl;
 
 1674  auto settings = sdl->context()->settings;
 
 1675  WINPR_ASSERT(settings);
 
 1677  status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE);
 
 1680    rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
 
 1682      sdl_list_monitors(sdl);
 
 1687        case COMMAND_LINE_STATUS_PRINT:
 
 1688        case COMMAND_LINE_STATUS_PRINT_VERSION:
 
 1689        case COMMAND_LINE_STATUS_PRINT_BUILDCONFIG:
 
 1691        case COMMAND_LINE_STATUS_PRINT_HELP:
 
 1693          SdlPref::print_config_file_help(2);
 
 1700  SDL_LogSetOutputFunction(winpr_LogOutputFunction, sdl);
 
 1701  auto level = WLog_GetLogLevel(sdl->log);
 
 1702  SDL_LogSetAllPriority(wloglevel2dl(level));
 
 1704  auto context = sdl->context();
 
 1705  WINPR_ASSERT(context);
 
 1707  if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CREATE_REQUEST, FALSE))
 
 1710  if (freerdp_client_start(context) != 0)
 
 1715  if (freerdp_client_stop(context) != 0)
 
 1718  if (sdl->exit_code != 0)
 
 1719    rc = sdl->exit_code;
 
 1724BOOL SdlContext::update_fullscreen(BOOL enter)
 
 1726  std::lock_guard<CriticalSection> lock(critical);
 
 1727  for (
const auto& window : windows)
 
 1729    if (!sdl_push_user_event(SDL_USEREVENT_WINDOW_FULLSCREEN, &window.second, enter))
 
 1736BOOL SdlContext::update_minimize()
 
 1738  std::lock_guard<CriticalSection> lock(critical);
 
 1739  return sdl_push_user_event(SDL_USEREVENT_WINDOW_MINIMIZE);
 
 1742BOOL SdlContext::update_resizeable(BOOL enable)
 
 1744  std::lock_guard<CriticalSection> lock(critical);
 
 1746  const auto settings = context()->settings;
 
 1749  BOOL use = (dyn && enable) || smart;
 
 1751  for (
const auto& window : windows)
 
 1753    if (!sdl_push_user_event(SDL_USEREVENT_WINDOW_RESIZEABLE, &window.second, use))
 
 1761SdlContext::SdlContext(rdpContext* context)
 
 1762    : _context(context), log(WLog_Get(SDL_TAG)), update_complete(true), disp(this), input(this),
 
 1763      primary(nullptr, SDL_FreeSurface), primary_format(nullptr, SDL_FreeFormat),
 
 1764      rdp_thread_running(false)
 
 1766  WINPR_ASSERT(context);
 
 1770rdpContext* SdlContext::context()
 const 
 1775rdpClientContext* SdlContext::common()
 const 
 1777  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_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.