28#include <winpr/wlog.h> 
   29#include <winpr/image.h> 
   31#include "sdl_clip.hpp" 
   32#include "sdl_freerdp.hpp" 
   34#define TAG CLIENT_TAG("sdl.cliprdr") 
   36#define mime_text_plain "text/plain" 
   38const char mime_text_utf8[] = mime_text_plain 
";charset=utf-8";
 
   40static const std::vector<const char*>& s_mime_text()
 
   42  static std::vector<const char*> values;
 
   45    values = std::vector<const char*>(
 
   46        { mime_text_plain, mime_text_utf8, 
"UTF8_STRING", 
"COMPOUND_TEXT", 
"TEXT", 
"STRING" });
 
   51static const char s_mime_png[] = 
"image/png";
 
   52static const char s_mime_webp[] = 
"image/webp";
 
   53static const char s_mime_jpg[] = 
"image/jpeg";
 
   55static const char s_mime_tiff[] = 
"image/tiff";
 
   56static const char s_mime_uri_list[] = 
"text/uri-list";
 
   57static const char s_mime_html[] = 
"text/html";
 
   59#define BMP_MIME_LIST "image/bmp", "image/x-bmp", "image/x-MS-bmp", "image/x-win-bitmap" 
   61static const std::vector<const char*>& s_mime_bitmap()
 
   63  static std::vector<const char*> values;
 
   66    values = std::vector<const char*>({ BMP_MIME_LIST });
 
   71static const std::vector<const char*>& s_mime_image()
 
   73  static std::vector<const char*> values;
 
   76    if (winpr_image_format_is_supported(WINPR_IMAGE_WEBP))
 
   77      values.push_back(s_mime_webp);
 
   79    if (winpr_image_format_is_supported(WINPR_IMAGE_PNG))
 
   80      values.push_back(s_mime_png);
 
   82    if (winpr_image_format_is_supported(WINPR_IMAGE_JPEG))
 
   83      values.push_back(s_mime_jpg);
 
   85    auto bmp = std::vector<const char*>({ s_mime_tiff, BMP_MIME_LIST });
 
   86    values.insert(values.end(), bmp.begin(), bmp.end());
 
   91static const char s_mime_gnome_copied_files[] = 
"x-special/gnome-copied-files";
 
   92static const char s_mime_mate_copied_files[] = 
"x-special/mate-copied-files";
 
   94static const char s_mime_freerdp_update[] = 
"x-special/freerdp-clipboard-update";
 
   96static const char* s_type_HtmlFormat = 
"HTML Format";
 
   97static const char* s_type_FileGroupDescriptorW = 
"FileGroupDescriptorW";
 
   99class ClipboardLockGuard
 
  102  explicit ClipboardLockGuard(wClipboard* clipboard) : _clipboard(clipboard)
 
  104    ClipboardLock(_clipboard);
 
  106  ClipboardLockGuard(
const ClipboardLockGuard& other) = 
delete;
 
  107  ClipboardLockGuard(ClipboardLockGuard&& other) = 
delete;
 
  109  ClipboardLockGuard& operator=(
const ClipboardLockGuard& rhs) = 
delete;
 
  110  ClipboardLockGuard& operator=(ClipboardLockGuard&& rhs) = 
delete;
 
  112  ~ClipboardLockGuard()
 
  114    ClipboardUnlock(_clipboard);
 
  118  wClipboard* _clipboard;
 
  123  return (lhs.formatId < rhs.formatId);
 
  128  return (lhs.formatId == rhs.formatId);
 
  132    : _sdl(sdl), _file(cliprdr_file_context_new(this)), _log(WLog_Get(TAG)),
 
  133      _system(ClipboardCreate()), _event(CreateEventA(nullptr, TRUE, FALSE, nullptr)),
 
  134      _uuid(sdl::utils::generate_uuid_v4())
 
  138  std::stringstream ss;
 
  139  ss << s_mime_freerdp_update << 
"-" << _uuid;
 
  140  _mime_uuid = ss.str();
 
  145  cliprdr_file_context_free(_file);
 
  146  ClipboardDestroy(_system);
 
  147  (void)CloseHandle(_event);
 
  150BOOL sdlClip::init(CliprdrClientContext* clip)
 
  155  _ctx->MonitorReady = sdlClip::MonitorReady;
 
  156  _ctx->ServerCapabilities = sdlClip::ReceiveServerCapabilities;
 
  157  _ctx->ServerFormatList = sdlClip::ReceiveServerFormatList;
 
  158  _ctx->ServerFormatListResponse = sdlClip::ReceiveFormatListResponse;
 
  159  _ctx->ServerFormatDataRequest = sdlClip::ReceiveFormatDataRequest;
 
  160  _ctx->ServerFormatDataResponse = sdlClip::ReceiveFormatDataResponse;
 
  162  return cliprdr_file_context_init(_file, _ctx);
 
  165BOOL sdlClip::uninit(CliprdrClientContext* clip)
 
  168  if (!cliprdr_file_context_uninit(_file, _ctx))
 
  171  clip->custom = 
nullptr;
 
  175bool sdlClip::contains(
const char** mime_types, Sint32 count)
 
  177  for (Sint32 x = 0; x < count; x++)
 
  179    const auto mime = mime_types[x];
 
  180    if (mime && (strcmp(_mime_uuid.c_str(), mime) == 0))
 
  186bool sdlClip::handle_update(
const SDL_ClipboardEvent& ev)
 
  188  if (!_ctx || !_sync || ev.owner)
 
  190    _last_timestamp = ev.timestamp;
 
  191    if (!_current_mimetypes.empty())
 
  195          SDL_SetClipboardData(sdlClip::ClipDataCb, sdlClip::ClipCleanCb, 
this, ev.mime_types,
 
  196                               WINPR_ASSERTING_INT_CAST(
size_t, ev.num_mime_types));
 
  197      _current_mimetypes.clear();
 
  203  if (ev.timestamp == _last_timestamp)
 
  208  if (contains(ev.mime_types, ev.num_mime_types))
 
  213  clearServerFormats();
 
  215  std::string mime_html = s_mime_html;
 
  217  std::vector<std::string> mime_bitmap = { BMP_MIME_LIST };
 
  218  std::string mime_webp = s_mime_webp;
 
  219  std::string mime_png = s_mime_png;
 
  220  std::string mime_jpeg = s_mime_jpg;
 
  221  std::string mime_tiff = s_mime_tiff;
 
  222  std::vector<std::string> mime_images = { mime_webp, mime_png, mime_jpeg, mime_tiff };
 
  224  std::vector<std::string> clientFormatNames;
 
  225  std::vector<CLIPRDR_FORMAT> clientFormats;
 
  227  size_t nformats = WINPR_ASSERTING_INT_CAST(
size_t, ev.num_mime_types);
 
  228  const char** clipboard_mime_formats = ev.mime_types;
 
  230  WLog_Print(_log, WLOG_TRACE, 
"SDL has %" PRIuz 
" formats", nformats);
 
  232  bool textPushed = 
false;
 
  233  bool imgPushed = 
false;
 
  235  for (
size_t i = 0; i < nformats; i++)
 
  237    std::string local_mime = clipboard_mime_formats[i];
 
  238    WLog_Print(_log, WLOG_TRACE, 
" - %s", local_mime.c_str());
 
  240    if (std::find(s_mime_text().begin(), s_mime_text().end(), local_mime) !=
 
  246        clientFormats.push_back({ CF_TEXT, 
nullptr });
 
  247        clientFormats.push_back({ CF_OEMTEXT, 
nullptr });
 
  248        clientFormats.push_back({ CF_UNICODETEXT, 
nullptr });
 
  252    else if (local_mime == mime_html)
 
  254      clientFormatNames.emplace_back(s_type_HtmlFormat);
 
  255    else if ((std::find(mime_bitmap.begin(), mime_bitmap.end(), local_mime) !=
 
  256              mime_bitmap.end()) ||
 
  257             (std::find(mime_images.begin(), mime_images.end(), local_mime) !=
 
  263        clientFormats.push_back({ CF_DIB, 
nullptr });
 
  264#if defined(WINPR_UTILS_IMAGE_DIBv5) 
  265        clientFormats.push_back({ CF_DIBV5, 
nullptr });
 
  268        for (
auto& bmp : mime_bitmap)
 
  269          clientFormatNames.push_back(bmp);
 
  271        for (
auto& img : mime_images)
 
  272          clientFormatNames.push_back(img);
 
  274        clientFormatNames.emplace_back(s_type_HtmlFormat);
 
  280  for (
auto& name : clientFormatNames)
 
  282    clientFormats.push_back({ ClipboardRegisterFormat(_system, name.c_str()), name.data() });
 
  285  std::sort(clientFormats.begin(), clientFormats.end(),
 
  286            [](
const auto& a, 
const auto& b) { return a < b; });
 
  287  auto u = std::unique(clientFormats.begin(), clientFormats.end());
 
  288  clientFormats.erase(u, clientFormats.end());
 
  291    { CB_FORMAT_LIST, 0, 0 },
 
  292    static_cast<UINT32
>(clientFormats.size()),
 
  293    clientFormats.data(),
 
  296  WLog_Print(_log, WLOG_TRACE,
 
  297             "-------------- client format list [%" PRIu32 
"] ------------------",
 
  298             formatList.numFormats);
 
  299  for (UINT32 x = 0; x < formatList.numFormats; x++)
 
  301    auto format = &formatList.formats[x];
 
  302    WLog_Print(_log, WLOG_TRACE, 
"client announces %" PRIu32 
" [%s][%s]", format->formatId,
 
  303               ClipboardGetFormatIdString(format->formatId), format->formatName);
 
  307  WINPR_ASSERT(_ctx->ClientFormatList);
 
  308  return _ctx->ClientFormatList(_ctx, &formatList) == CHANNEL_RC_OK;
 
  313  WINPR_UNUSED(monitorReady);
 
  314  WINPR_ASSERT(context);
 
  315  WINPR_ASSERT(monitorReady);
 
  317  auto clipboard = 
static_cast<sdlClip*
>(
 
  318      cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
 
  319  WINPR_ASSERT(clipboard);
 
  321  auto ret = clipboard->SendClientCapabilities();
 
  322  if (ret != CHANNEL_RC_OK)
 
  325  clipboard->_sync = 
true;
 
  326  if (!sdl_push_user_event(SDL_EVENT_CLIPBOARD_UPDATE))
 
  327    return ERROR_INTERNAL_ERROR;
 
  329  return CHANNEL_RC_OK;
 
  332UINT sdlClip::SendClientCapabilities()
 
  335    CB_CAPSTYPE_GENERAL, 12, CB_CAPS_VERSION_2,
 
  336    CB_USE_LONG_FORMAT_NAMES | cliprdr_file_context_current_flags(_file)
 
  343  WINPR_ASSERT(_ctx->ClientCapabilities);
 
  344  return _ctx->ClientCapabilities(_ctx, &capabilities);
 
  347void sdlClip::clearServerFormats()
 
  349  _serverFormats.clear();
 
  351  cliprdr_file_context_clear(_file);
 
  354UINT sdlClip::SendFormatListResponse(BOOL status)
 
  357    { CB_FORMAT_LIST_RESPONSE, 
static_cast<UINT16
>(status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL),
 
  361  WINPR_ASSERT(_ctx->ClientFormatListResponse);
 
  362  return _ctx->ClientFormatListResponse(_ctx, &formatListResponse);
 
  365UINT sdlClip::SendDataResponse(
const BYTE* data, 
size_t size)
 
  369  if (size > UINT32_MAX)
 
  370    return ERROR_INVALID_PARAMETER;
 
  372  response.common.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
 
  373  response.common.dataLen = 
static_cast<UINT32
>(size);
 
  374  response.requestedFormatData = data;
 
  377  WINPR_ASSERT(_ctx->ClientFormatDataResponse);
 
  378  return _ctx->ClientFormatDataResponse(_ctx, &response);
 
  381UINT sdlClip::SendDataRequest(uint32_t formatID, 
const std::string& mime)
 
  385  _request_queue.emplace(formatID, mime);
 
  388  WINPR_ASSERT(_ctx->ClientFormatDataRequest);
 
  389  UINT ret = _ctx->ClientFormatDataRequest(_ctx, &request);
 
  390  if (ret != CHANNEL_RC_OK)
 
  392    WLog_Print(_log, WLOG_ERROR, 
"error sending ClientFormatDataRequest, cancelling request");
 
  393    _request_queue.pop();
 
  399std::string sdlClip::getServerFormat(uint32_t 
id)
 
  401  for (
auto& fmt : _serverFormats)
 
  403    if (fmt.formatId() == 
id)
 
  405      if (fmt.formatName())
 
  406        return fmt.formatName();
 
  414uint32_t sdlClip::serverIdForMime(
const std::string& mime)
 
  416  std::string cmp = mime;
 
  417  if (mime_is_html(mime))
 
  418    cmp = s_type_HtmlFormat;
 
  419  if (mime_is_file(mime))
 
  420    cmp = s_type_FileGroupDescriptorW;
 
  422  for (
auto& format : _serverFormats)
 
  424    if (!format.formatName())
 
  426    if (cmp == format.formatName())
 
  427      return format.formatId();
 
  430  if (mime_is_image(mime))
 
  432  if (mime_is_text(mime))
 
  433    return CF_UNICODETEXT;
 
  438UINT sdlClip::ReceiveServerCapabilities(CliprdrClientContext* context,
 
  441  WINPR_ASSERT(context);
 
  442  WINPR_ASSERT(capabilities);
 
  444  auto capsPtr = 
reinterpret_cast<const BYTE*
>(capabilities->capabilitySets);
 
  445  WINPR_ASSERT(capsPtr);
 
  447  auto clipboard = 
static_cast<sdlClip*
>(
 
  448      cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
 
  449  WINPR_ASSERT(clipboard);
 
  451  if (!cliprdr_file_context_remote_set_flags(clipboard->_file, 0))
 
  452    return ERROR_INTERNAL_ERROR;
 
  454  for (UINT32 i = 0; i < capabilities->cCapabilitiesSets; i++)
 
  458    if (caps->capabilitySetType == CB_CAPSTYPE_GENERAL)
 
  462      if (!cliprdr_file_context_remote_set_flags(clipboard->_file, generalCaps->generalFlags))
 
  463        return ERROR_INTERNAL_ERROR;
 
  466    capsPtr += caps->capabilitySetLength;
 
  469  return CHANNEL_RC_OK;
 
  472UINT sdlClip::ReceiveServerFormatList(CliprdrClientContext* context,
 
  480  if (!context || !context->custom)
 
  481    return ERROR_INVALID_PARAMETER;
 
  483  auto clipboard = 
static_cast<sdlClip*
>(
 
  484      cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
 
  485  WINPR_ASSERT(clipboard);
 
  487  clipboard->clearServerFormats();
 
  489  for (UINT32 i = 0; i < formatList->numFormats; i++)
 
  493    clipboard->_serverFormats.emplace_back(format->formatId, format->formatName);
 
  495    if (format->formatName)
 
  497      if (strcmp(format->formatName, s_type_HtmlFormat) == 0)
 
  502      else if (strcmp(format->formatName, s_type_FileGroupDescriptorW) == 0)
 
  510      switch (format->formatId)
 
  528  clipboard->_current_mimetypes.clear();
 
  531    clipboard->_current_mimetypes.insert(clipboard->_current_mimetypes.end(),
 
  532                                         s_mime_text().begin(), s_mime_text().end());
 
  536    clipboard->_current_mimetypes.insert(clipboard->_current_mimetypes.end(),
 
  537                                         s_mime_bitmap().begin(), s_mime_bitmap().end());
 
  538    clipboard->_current_mimetypes.insert(clipboard->_current_mimetypes.end(),
 
  539                                         s_mime_image().begin(), s_mime_image().end());
 
  543    clipboard->_current_mimetypes.push_back(s_mime_html);
 
  547    clipboard->_current_mimetypes.push_back(s_mime_uri_list);
 
  548    clipboard->_current_mimetypes.push_back(s_mime_gnome_copied_files);
 
  549    clipboard->_current_mimetypes.push_back(s_mime_mate_copied_files);
 
  551  clipboard->_current_mimetypes.push_back(clipboard->_mime_uuid.c_str());
 
  553  auto s = clipboard->_current_mimetypes.size();
 
  554  SDL_Event ev = { SDL_EVENT_CLIPBOARD_UPDATE };
 
  555  ev.clipboard.owner = 
true;
 
  556  ev.clipboard.timestamp = SDL_GetTicksNS();
 
  557  ev.clipboard.num_mime_types = WINPR_ASSERTING_INT_CAST(Sint32, s);
 
  558  ev.clipboard.mime_types = clipboard->_current_mimetypes.data();
 
  560  auto rc = (SDL_PushEvent(&ev) == 1);
 
  561  return clipboard->SendFormatListResponse(rc);
 
  564UINT sdlClip::ReceiveFormatListResponse(WINPR_ATTR_UNUSED CliprdrClientContext* context,
 
  567  WINPR_ASSERT(context);
 
  568  WINPR_ASSERT(formatListResponse);
 
  570  if (formatListResponse->common.msgFlags & CB_RESPONSE_FAIL)
 
  571    WLog_WARN(TAG, 
"format list update failed");
 
  572  return CHANNEL_RC_OK;
 
  575std::shared_ptr<BYTE> sdlClip::ReceiveFormatDataRequestHandle(
 
  578  const char* mime = 
nullptr;
 
  583  std::shared_ptr<BYTE> data;
 
  585  WINPR_ASSERT(clipboard);
 
  586  WINPR_ASSERT(formatDataRequest);
 
  589  auto localFormatId = formatId = formatDataRequest->requestedFormatId;
 
  590  WLog_Print(clipboard->_log, WLOG_DEBUG, 
"Requesting format %s [0x%08" PRIx32 
"] [%s]",
 
  591             ClipboardGetFormatIdString(localFormatId), localFormatId,
 
  592             ClipboardGetFormatName(clipboard->_system, localFormatId));
 
  594  ClipboardLockGuard systemlock(clipboard->_system);
 
  595  std::lock_guard<CriticalSection> lock(clipboard->_lock);
 
  597  const UINT32 fileFormatId =
 
  598      ClipboardGetFormatId(clipboard->_system, s_type_FileGroupDescriptorW);
 
  599  const UINT32 htmlFormatId = ClipboardGetFormatId(clipboard->_system, s_type_HtmlFormat);
 
  606      localFormatId = ClipboardGetFormatId(clipboard->_system, mime_text_plain);
 
  607      mime = mime_text_utf8;
 
  612      mime = s_mime_bitmap()[0];
 
  613      localFormatId = ClipboardGetFormatId(clipboard->_system, mime);
 
  621      if (formatId == fileFormatId)
 
  623        localFormatId = ClipboardGetFormatId(clipboard->_system, s_mime_uri_list);
 
  624        mime = s_mime_uri_list;
 
  626      else if (formatId == htmlFormatId)
 
  629        if (!SDL_HasClipboardData(s_mime_html))
 
  631          for (
const auto& cmime : s_mime_image())
 
  633            if (SDL_HasClipboardData(cmime))
 
  635              localFormatId = ClipboardGetFormatId(clipboard->_system, cmime);
 
  643          localFormatId = ClipboardGetFormatId(clipboard->_system, s_mime_html);
 
  653    auto sdldata = std::shared_ptr<void>(SDL_GetClipboardData(mime, &size), SDL_free);
 
  657    if (fileFormatId == formatId)
 
  659      auto bdata = 
static_cast<const char*
>(sdldata.get());
 
  660      if (!cliprdr_file_context_update_client_data(clipboard->_file, bdata, size))
 
  664    res = ClipboardSetData(clipboard->_system, localFormatId, sdldata.get(),
 
  665                           static_cast<uint32_t
>(size));
 
  672  auto ptr = 
static_cast<BYTE*
>(ClipboardGetData(clipboard->_system, formatId, &ptrlen));
 
  673  data = std::shared_ptr<BYTE>(ptr, free);
 
  678  if (fileFormatId == formatId)
 
  680    BYTE* ddata = 
nullptr;
 
  682    const UINT32 flags = cliprdr_file_context_remote_get_flags(clipboard->_file);
 
  683    const UINT32 error = cliprdr_serialize_file_list_ex(
 
  687    auto tmp = std::shared_ptr<BYTE>(ddata, free);
 
  699UINT sdlClip::ReceiveFormatDataRequest(CliprdrClientContext* context,
 
  702  WINPR_ASSERT(context);
 
  703  WINPR_ASSERT(formatDataRequest);
 
  705  auto clipboard = 
static_cast<sdlClip*
>(
 
  706      cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
 
  707  WINPR_ASSERT(clipboard);
 
  710  auto rc = ReceiveFormatDataRequestHandle(clipboard, formatDataRequest, len);
 
  711  return clipboard->SendDataResponse(rc.get(), len);
 
  714UINT sdlClip::ReceiveFormatDataResponse(CliprdrClientContext* context,
 
  717  WINPR_ASSERT(context);
 
  718  WINPR_ASSERT(formatDataResponse);
 
  720  const UINT32 size = formatDataResponse->common.dataLen;
 
  721  const BYTE* data = formatDataResponse->requestedFormatData;
 
  723  auto clipboard = 
static_cast<sdlClip*
>(
 
  724      cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
 
  725  WINPR_ASSERT(clipboard);
 
  727  ClipboardLockGuard systemlock(clipboard->_system);
 
  728  std::lock_guard<CriticalSection> lock(clipboard->_lock);
 
  729  if (clipboard->_request_queue.empty())
 
  731    WLog_Print(clipboard->_log, WLOG_ERROR, 
"no pending format request");
 
  732    return ERROR_INTERNAL_ERROR;
 
  737    UINT32 srcFormatId = 0;
 
  738    auto& request = clipboard->_request_queue.front();
 
  739    bool success = (formatDataResponse->common.msgFlags & CB_RESPONSE_OK) &&
 
  740                   !(formatDataResponse->common.msgFlags & CB_RESPONSE_FAIL);
 
  741    request.setSuccess(success);
 
  745      WLog_Print(clipboard->_log, WLOG_WARN,
 
  746                 "clipboard data request for format %" PRIu32 
" [%s], mime %s failed",
 
  747                 request.format(), request.formatstr().c_str(), request.mime().c_str());
 
  751    switch (request.format())
 
  756        srcFormatId = request.format();
 
  761        srcFormatId = request.format();
 
  766        auto name = clipboard->getServerFormat(request.format());
 
  769          if (name == s_type_FileGroupDescriptorW)
 
  772                ClipboardGetFormatId(clipboard->_system, s_type_FileGroupDescriptorW);
 
  774            if (!cliprdr_file_context_update_server_data(
 
  775                    clipboard->_file, clipboard->_system, data, size))
 
  776              return ERROR_INTERNAL_ERROR;
 
  778          else if (name == s_type_HtmlFormat)
 
  780            srcFormatId = ClipboardGetFormatId(clipboard->_system, s_type_HtmlFormat);
 
  787    if (!ClipboardSetData(clipboard->_system, srcFormatId, data, size))
 
  789      WLog_Print(clipboard->_log, WLOG_ERROR, 
"error when setting clipboard data");
 
  790      return ERROR_INTERNAL_ERROR;
 
  792    WLog_Print(clipboard->_log, WLOG_DEBUG, 
"updated clipboard data %s [0x%08" PRIx32 
"]",
 
  793               ClipboardGetFormatName(clipboard->_system, srcFormatId), srcFormatId);
 
  796  if (!SetEvent(clipboard->_event))
 
  798    WLog_Print(clipboard->_log, WLOG_ERROR, 
"error when setting clipboard event");
 
  799    return ERROR_INTERNAL_ERROR;
 
  802  return CHANNEL_RC_OK;
 
  805const void* sdlClip::ClipDataCb(
void* userdata, 
const char* mime_type, 
size_t* size)
 
  807  auto clip = 
static_cast<sdlClip*
>(userdata);
 
  810  WINPR_ASSERT(mime_type);
 
  815  if (mime_is_text(mime_type))
 
  816    mime_type = 
"text/plain";
 
  819    ClipboardLockGuard systemlock(clip->_system);
 
  820    std::lock_guard<CriticalSection> lock(clip->_lock);
 
  823    auto cache = clip->_cache_data.find(mime_type);
 
  824    if (cache != clip->_cache_data.end())
 
  826      *size = cache->second.size;
 
  827      return cache->second.ptr.get();
 
  830    auto formatID = clip->serverIdForMime(mime_type);
 
  834    auto mimeFormatID = ClipboardRegisterFormat(clip->_system, mime_type);
 
  835    auto fptr = ClipboardGetData(clip->_system, mimeFormatID, &fsize);
 
  838      auto ptr = std::shared_ptr<void>(fptr, free);
 
  839      clip->_cache_data.insert({ mime_type, { fsize, ptr } });
 
  841      auto fcache = clip->_cache_data.find(mime_type);
 
  842      if (fcache != clip->_cache_data.end())
 
  844        *size = fcache->second.size;
 
  845        return fcache->second.ptr.get();
 
  849    WLog_Print(clip->_log, WLOG_DEBUG, 
"requesting format %s [%s 0x%08" PRIx32 
"]", mime_type,
 
  850               ClipboardGetFormatName(clip->_system, formatID), formatID);
 
  851    if (clip->SendDataRequest(formatID, mime_type))
 
  855    HANDLE hdl[2] = { freerdp_abort_event(clip->_sdl->context()), clip->_event };
 
  857    DWORD status = WaitForMultipleObjects(ARRAYSIZE(hdl), hdl, FALSE, 10 * 1000);
 
  859    if (status != WAIT_OBJECT_0 + 1)
 
  861      std::lock_guard<CriticalSection> lock(clip->_lock);
 
  862      clip->_request_queue.pop();
 
  864      if (status == WAIT_TIMEOUT)
 
  865        WLog_Print(clip->_log, WLOG_ERROR,
 
  866                   "no reply in 10 seconds, returning empty content");
 
  873    ClipboardLockGuard systemlock(clip->_system);
 
  874    std::lock_guard<CriticalSection> lock(clip->_lock);
 
  875    auto request = clip->_request_queue.front();
 
  876    clip->_request_queue.pop();
 
  878    if (clip->_request_queue.empty())
 
  879      (void)ResetEvent(clip->_event);
 
  881    if (request.success())
 
  883      auto formatID = ClipboardRegisterFormat(clip->_system, mime_type);
 
  884      auto data = ClipboardGetData(clip->_system, formatID, &len);
 
  887        WLog_Print(clip->_log, WLOG_ERROR, 
"error retrieving clipboard data");
 
  891      auto ptr = std::shared_ptr<void>(data, free);
 
  892      clip->_cache_data.insert({ mime_type, { len, ptr } });
 
  901void sdlClip::ClipCleanCb(
void* userdata)
 
  903  auto clip = 
static_cast<sdlClip*
>(userdata);
 
  905  ClipboardLockGuard give_me_a_name(clip->_system);
 
  906  std::lock_guard<CriticalSection> lock(clip->_lock);
 
  907  ClipboardEmpty(clip->_system);
 
  910bool sdlClip::mime_is_file(
const std::string& mime)
 
  912  if (strncmp(s_mime_uri_list, mime.c_str(), 
sizeof(s_mime_uri_list)) == 0)
 
  914  if (strncmp(s_mime_gnome_copied_files, mime.c_str(), 
sizeof(s_mime_gnome_copied_files)) == 0)
 
  916  if (strncmp(s_mime_mate_copied_files, mime.c_str(), 
sizeof(s_mime_mate_copied_files)) == 0)
 
  921bool sdlClip::mime_is_text(
const std::string& mime)
 
  923  for (
const auto& tmime : s_mime_text())
 
  925    assert(tmime != 
nullptr);
 
  933bool sdlClip::mime_is_image(
const std::string& mime)
 
  935  for (
const auto& imime : s_mime_image())
 
  937    assert(imime != 
nullptr);
 
  945bool sdlClip::mime_is_bmp(
const std::string& mime)
 
  947  for (
const auto& imime : s_mime_bitmap())
 
  949    assert(imime != 
nullptr);
 
  957bool sdlClip::mime_is_html(
const std::string& mime)
 
  959  return mime.compare(s_mime_html) == 0;
 
  962ClipRequest::ClipRequest(UINT32 format, 
const std::string& mime)
 
  963    : _format(format), _mime(mime), _success(false)
 
  967uint32_t ClipRequest::format()
 const 
  972std::string ClipRequest::formatstr()
 const 
  974  return ClipboardGetFormatIdString(_format);
 
  977std::string ClipRequest::mime()
 const 
  982bool ClipRequest::success()
 const 
  987void ClipRequest::setSuccess(
bool status)
 
object that handles clipboard context for the SDL3 client