28#include <winpr/wlog.h>
29#include <winpr/image.h>
31#include "sdl_clip.hpp"
32#include "sdl_context.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";
40[[nodiscard]]
static 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_jxl[] =
"image/jxl";
52static const char s_mime_avif[] =
"image/avif";
53static const char s_mime_png[] =
"image/png";
54static const char s_mime_webp[] =
"image/webp";
55static const char s_mime_jpg[] =
"image/jpeg";
57static const char s_mime_tiff[] =
"image/tiff";
58static const char s_mime_uri_list[] =
"text/uri-list";
59static const char s_mime_html[] =
"text/html";
61#define BMP_MIME_LIST "image/bmp", "image/x-bmp", "image/x-MS-bmp", "image/x-win-bitmap"
63[[nodiscard]]
static const std::vector<const char*>& s_mime_bitmap()
65 static std::vector<const char*> values;
68 values = std::vector<const char*>({ BMP_MIME_LIST });
73[[nodiscard]]
static const std::vector<const char*>& s_mime_image()
75 static std::vector<const char*> values;
78 if (winpr_image_format_is_supported(WINPR_IMAGE_WEBP))
79 values.push_back(s_mime_webp);
81 if (winpr_image_format_is_supported(WINPR_IMAGE_PNG))
82 values.push_back(s_mime_png);
84 if (winpr_image_format_is_supported(WINPR_IMAGE_JPEG))
85 values.push_back(s_mime_jpg);
87 auto bmp = std::vector<const char*>({ BMP_MIME_LIST });
88 values.insert(values.end(), bmp.begin(), bmp.end());
93static const char s_mime_gnome_copied_files[] =
"x-special/gnome-copied-files";
94static const char s_mime_mate_copied_files[] =
"x-special/mate-copied-files";
96static const char s_mime_freerdp_update[] =
"x-special/freerdp-clipboard-update";
98static const char* s_type_HtmlFormat =
"HTML Format";
99static const char* s_type_FileGroupDescriptorW =
"FileGroupDescriptorW";
101class ClipboardLockGuard
104 explicit ClipboardLockGuard(wClipboard* clipboard) : _clipboard(clipboard)
106 ClipboardLock(_clipboard);
108 ClipboardLockGuard(
const ClipboardLockGuard& other) =
delete;
109 ClipboardLockGuard(ClipboardLockGuard&& other) =
delete;
111 ClipboardLockGuard& operator=(
const ClipboardLockGuard& rhs) =
delete;
112 ClipboardLockGuard& operator=(ClipboardLockGuard&& rhs) =
delete;
114 ~ClipboardLockGuard()
116 ClipboardUnlock(_clipboard);
120 wClipboard* _clipboard;
125 return (lhs.formatId < rhs.formatId);
130 return (lhs.formatId == rhs.formatId);
134 : _sdl(
sdl), _file(cliprdr_file_context_new(this)), _log(WLog_Get(TAG)),
135 _system(ClipboardCreate()), _event(CreateEventA(nullptr, TRUE, FALSE, nullptr)),
136 _uuid(
sdl::utils::generate_uuid_v4())
140 std::stringstream ss;
141 ss << s_mime_freerdp_update <<
"-" << _uuid;
142 _mime_uuid = ss.str();
144 std::ignore = cliprdr_file_context_set_locally_available(_file, TRUE);
149 cliprdr_file_context_free(_file);
150 ClipboardDestroy(_system);
151 std::ignore = CloseHandle(_event);
154bool sdlClip::init(CliprdrClientContext* clip)
159 _ctx->MonitorReady = sdlClip::MonitorReady;
160 _ctx->ServerCapabilities = sdlClip::ReceiveServerCapabilities;
161 _ctx->ServerFormatList = sdlClip::ReceiveServerFormatList;
162 _ctx->ServerFormatListResponse = sdlClip::ReceiveFormatListResponse;
163 _ctx->ServerFormatDataRequest = sdlClip::ReceiveFormatDataRequest;
164 _ctx->ServerFormatDataResponse = sdlClip::ReceiveFormatDataResponse;
166 return cliprdr_file_context_init(_file, _ctx);
169bool sdlClip::uninit(CliprdrClientContext* clip)
172 if (!cliprdr_file_context_uninit(_file, _ctx))
175 clip->custom =
nullptr;
179bool sdlClip::contains(
const char** mime_types, Sint32 count)
181 for (Sint32 x = 0; x < count; x++)
183 const auto mime = mime_types[x];
184 if (mime && (strcmp(_mime_uuid.c_str(), mime) == 0))
190bool sdlClip::handleEvent(
const SDL_ClipboardEvent& ev)
192 if (!_ctx || !_sync || ev.owner)
194 _last_timestamp = ev.timestamp;
195 if (!_current_mimetypes.empty())
199 SDL_SetClipboardData(sdlClip::ClipDataCb, sdlClip::ClipCleanCb,
this, ev.mime_types,
200 WINPR_ASSERTING_INT_CAST(
size_t, ev.num_mime_types));
201 _current_mimetypes.clear();
207 if (ev.timestamp == _last_timestamp)
212 if (contains(ev.mime_types, ev.num_mime_types))
217 clearServerFormats();
219 const std::string mime_html = s_mime_html;
221 const std::vector<std::string> mime_bitmap = { BMP_MIME_LIST };
222 const std::string mime_webp = s_mime_webp;
223 const std::string mime_png = s_mime_png;
224 const std::string mime_jpeg = s_mime_jpg;
225 const std::string mime_tiff = s_mime_tiff;
226 const std::vector<std::string> mime_images = { mime_webp, mime_png, mime_jpeg,
227 mime_tiff, s_mime_avif, s_mime_jxl };
229 std::vector<std::string> clientFormatNames;
230 std::vector<CLIPRDR_FORMAT> clientFormats;
232 size_t nformats = WINPR_ASSERTING_INT_CAST(
size_t, ev.num_mime_types);
233 const char** clipboard_mime_formats = ev.mime_types;
235 WLog_Print(_log, WLOG_TRACE,
"SDL has %" PRIuz
" formats", nformats);
237 bool textPushed =
false;
238 bool imgPushed =
false;
239 bool filePushed =
false;
241 for (
size_t i = 0; i < nformats; i++)
243 std::string local_mime = clipboard_mime_formats[i];
244 WLog_Print(_log, WLOG_TRACE,
" - %s", local_mime.c_str());
246 if (std::find(s_mime_text().begin(), s_mime_text().end(), local_mime) !=
252 clientFormats.push_back({ CF_TEXT,
nullptr });
253 clientFormats.push_back({ CF_OEMTEXT,
nullptr });
254 clientFormats.push_back({ CF_UNICODETEXT,
nullptr });
258 else if (local_mime == mime_html)
260 clientFormatNames.emplace_back(s_type_HtmlFormat);
261 else if ((std::find(mime_bitmap.begin(), mime_bitmap.end(), local_mime) !=
262 mime_bitmap.end()) ||
263 (std::find(mime_images.begin(), mime_images.end(), local_mime) !=
269 clientFormats.push_back({ CF_DIB,
nullptr });
270#if defined(WINPR_UTILS_IMAGE_DIBv5)
271 clientFormats.push_back({ CF_DIBV5,
nullptr });
274 if (winpr_image_format_is_supported(WINPR_IMAGE_BITMAP))
276 for (
auto& bmp : mime_bitmap)
277 clientFormatNames.push_back(bmp);
280 if (winpr_image_format_is_supported(WINPR_IMAGE_JPEG))
281 clientFormatNames.push_back(mime_jpeg);
282 if (winpr_image_format_is_supported(WINPR_IMAGE_WEBP))
283 clientFormatNames.push_back(mime_webp);
284 if (winpr_image_format_is_supported(WINPR_IMAGE_PNG))
285 clientFormatNames.push_back(mime_png);
287 clientFormatNames.emplace_back(s_type_HtmlFormat);
290 clientFormatNames.push_back(local_mime);
292 else if (mime_is_file(local_mime))
296 clientFormatNames.emplace_back(s_type_FileGroupDescriptorW);
302 std::sort(clientFormatNames.begin(), clientFormatNames.end());
303 clientFormatNames.erase(std::unique(clientFormatNames.begin(), clientFormatNames.end()),
304 clientFormatNames.end());
306 for (
auto& name : clientFormatNames)
308 clientFormats.push_back({ ClipboardRegisterFormat(_system, name.c_str()), name.data() });
311 std::sort(clientFormats.begin(), clientFormats.end(),
312 [](
const auto& a,
const auto& b) { return a < b; });
313 auto u = std::unique(clientFormats.begin(), clientFormats.end());
314 clientFormats.erase(u, clientFormats.end());
317 { CB_FORMAT_LIST, 0, 0 },
318 static_cast<UINT32
>(clientFormats.size()),
319 clientFormats.data(),
322 WLog_Print(_log, WLOG_TRACE,
323 "-------------- client format list [%" PRIu32
"] ------------------",
324 formatList.numFormats);
325 for (UINT32 x = 0; x < formatList.numFormats; x++)
327 auto format = &formatList.formats[x];
328 WLog_Print(_log, WLOG_TRACE,
"client announces %" PRIu32
" [%s][%s]", format->formatId,
329 ClipboardGetFormatIdString(format->formatId), format->formatName);
332 if (cliprdr_file_context_notify_new_client_format_list(_file) != CHANNEL_RC_OK)
336 WINPR_ASSERT(_ctx->ClientFormatList);
337 return _ctx->ClientFormatList(_ctx, &formatList) == CHANNEL_RC_OK;
342 WINPR_UNUSED(monitorReady);
343 WINPR_ASSERT(context);
344 WINPR_ASSERT(monitorReady);
346 auto clipboard =
static_cast<sdlClip*
>(
347 cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
348 WINPR_ASSERT(clipboard);
350 auto ret = clipboard->SendClientCapabilities();
351 if (ret != CHANNEL_RC_OK)
354 clipboard->_sync =
true;
355 if (!sdl_push_user_event(SDL_EVENT_CLIPBOARD_UPDATE))
356 return ERROR_INTERNAL_ERROR;
358 return CHANNEL_RC_OK;
361UINT sdlClip::SendClientCapabilities()
364 CB_CAPSTYPE_GENERAL, 12, CB_CAPS_VERSION_2,
365 CB_USE_LONG_FORMAT_NAMES | cliprdr_file_context_current_flags(_file)
372 WINPR_ASSERT(_ctx->ClientCapabilities);
373 return _ctx->ClientCapabilities(_ctx, &capabilities);
376void sdlClip::clearServerFormats()
378 _serverFormats.clear();
380 cliprdr_file_context_clear(_file);
383UINT sdlClip::SendFormatListResponse(BOOL status)
386 { CB_FORMAT_LIST_RESPONSE,
static_cast<UINT16
>(status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL),
390 WINPR_ASSERT(_ctx->ClientFormatListResponse);
391 return _ctx->ClientFormatListResponse(_ctx, &formatListResponse);
394UINT sdlClip::SendDataResponse(
const BYTE* data,
size_t size)
398 if (size > UINT32_MAX)
399 return ERROR_INVALID_PARAMETER;
401 response.common.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
402 response.common.dataLen =
static_cast<UINT32
>(size);
403 response.requestedFormatData = data;
406 WINPR_ASSERT(_ctx->ClientFormatDataResponse);
407 return _ctx->ClientFormatDataResponse(_ctx, &response);
410UINT sdlClip::SendDataRequest(uint32_t formatID,
const std::string& mime)
414 _request_queue.emplace(formatID, mime);
417 WINPR_ASSERT(_ctx->ClientFormatDataRequest);
418 UINT ret = _ctx->ClientFormatDataRequest(_ctx, &request);
419 if (ret != CHANNEL_RC_OK)
421 WLog_Print(_log, WLOG_ERROR,
"error sending ClientFormatDataRequest, cancelling request");
422 _request_queue.pop();
428std::string sdlClip::getServerFormat(uint32_t
id)
430 for (
auto& fmt : _serverFormats)
432 if (fmt.formatId() ==
id)
434 if (fmt.formatName())
435 return fmt.formatName();
443uint32_t sdlClip::serverIdForMime(
const std::string& mime)
445 std::string cmp = mime;
446 if (mime_is_html(mime))
447 cmp = s_type_HtmlFormat;
448 if (mime_is_file(mime))
449 cmp = s_type_FileGroupDescriptorW;
451 for (
auto& format : _serverFormats)
453 if (!format.formatName())
455 if (cmp == format.formatName())
456 return format.formatId();
459 if (mime_is_image(mime))
461 if (mime_is_text(mime))
462 return CF_UNICODETEXT;
467UINT sdlClip::ReceiveServerCapabilities(CliprdrClientContext* context,
470 WINPR_ASSERT(context);
471 WINPR_ASSERT(capabilities);
473 auto capsPtr =
reinterpret_cast<const BYTE*
>(capabilities->capabilitySets);
474 WINPR_ASSERT(capsPtr);
476 auto clipboard =
static_cast<sdlClip*
>(
477 cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
478 WINPR_ASSERT(clipboard);
480 if (!cliprdr_file_context_remote_set_flags(clipboard->_file, 0))
481 return ERROR_INTERNAL_ERROR;
483 for (UINT32 i = 0; i < capabilities->cCapabilitiesSets; i++)
487 if (caps->capabilitySetType == CB_CAPSTYPE_GENERAL)
491 if (!cliprdr_file_context_remote_set_flags(clipboard->_file, generalCaps->generalFlags))
492 return ERROR_INTERNAL_ERROR;
495 capsPtr += caps->capabilitySetLength;
498 return CHANNEL_RC_OK;
501UINT sdlClip::ReceiveServerFormatList(CliprdrClientContext* context,
509 if (!context || !context->custom)
510 return ERROR_INVALID_PARAMETER;
512 auto filecontext =
static_cast<CliprdrFileContext*
>(context->custom);
513 auto clipboard =
static_cast<sdlClip*
>(cliprdr_file_context_get_context(filecontext));
514 WINPR_ASSERT(clipboard);
516 clipboard->clearServerFormats();
518 for (UINT32 i = 0; i < formatList->numFormats; i++)
522 clipboard->_serverFormats.emplace_back(format->formatId, format->formatName);
524 if (format->formatName)
526 if (strcmp(format->formatName, s_type_HtmlFormat) == 0)
531 else if (strcmp(format->formatName, s_type_FileGroupDescriptorW) == 0)
539 switch (format->formatId)
557 clipboard->_current_mimetypes.clear();
560 ClipboardLockGuard systemlock(clipboard->_system);
561 std::scoped_lock lock(clipboard->_lock);
562 auto res = cliprdr_file_context_notify_new_server_format_list(filecontext);
563 if (res != CHANNEL_RC_OK)
569 clipboard->_current_mimetypes.insert(clipboard->_current_mimetypes.end(),
570 s_mime_text().begin(), s_mime_text().end());
574 clipboard->_current_mimetypes.insert(clipboard->_current_mimetypes.end(),
575 s_mime_bitmap().begin(), s_mime_bitmap().end());
576 clipboard->_current_mimetypes.insert(clipboard->_current_mimetypes.end(),
577 s_mime_image().begin(), s_mime_image().end());
581 clipboard->_current_mimetypes.push_back(s_mime_html);
585 clipboard->_current_mimetypes.push_back(s_mime_uri_list);
586 clipboard->_current_mimetypes.push_back(s_mime_gnome_copied_files);
587 clipboard->_current_mimetypes.push_back(s_mime_mate_copied_files);
589 clipboard->_current_mimetypes.push_back(clipboard->_mime_uuid.c_str());
591 auto& mime = clipboard->_current_mimetypes;
592 std::sort(mime.begin(), mime.end());
593 mime.erase(std::unique(mime.begin(), mime.end()), mime.end());
595 WLog_Print(clipboard->_log, WLOG_TRACE,
596 "-------------- server mime types [%" PRIuz
"] ------------------", mime.size());
597 for (
const auto& m : mime)
599 WLog_Print(clipboard->_log, WLOG_TRACE,
"server announces %s]", m);
602 auto s = clipboard->_current_mimetypes.size();
603 SDL_Event ev = { SDL_EVENT_CLIPBOARD_UPDATE };
604 ev.clipboard.owner =
true;
605 ev.clipboard.timestamp = SDL_GetTicksNS();
606 ev.clipboard.num_mime_types = WINPR_ASSERTING_INT_CAST(Sint32, s);
607 ev.clipboard.mime_types = clipboard->_current_mimetypes.data();
609 auto rc = (SDL_PushEvent(&ev) == 1);
610 return clipboard->SendFormatListResponse(rc);
613UINT sdlClip::ReceiveFormatListResponse(WINPR_ATTR_UNUSED CliprdrClientContext* context,
616 WINPR_ASSERT(context);
617 WINPR_ASSERT(formatListResponse);
619 if (formatListResponse->common.msgFlags & CB_RESPONSE_FAIL)
620 WLog_WARN(TAG,
"format list update failed");
621 return CHANNEL_RC_OK;
625static const char* getCurrentTextMime()
628 for (
auto m : s_mime_text())
630 if (SDL_HasClipboardData(m))
637static const char* getCurrentImageMime()
639 const std::vector<const char*> types{ s_mime_jpg, s_mime_png, s_mime_webp, s_mime_avif,
640 s_mime_jxl, s_mime_tiff, BMP_MIME_LIST };
641 for (
const auto& m : types)
643 if (SDL_HasClipboardData(m))
649std::shared_ptr<BYTE> sdlClip::ReceiveFormatDataRequestHandle(
652 const char* mime =
nullptr;
657 std::shared_ptr<BYTE> data;
659 WINPR_ASSERT(clipboard);
660 WINPR_ASSERT(formatDataRequest);
663 auto localFormatId = formatId = formatDataRequest->requestedFormatId;
664 WLog_Print(clipboard->_log, WLOG_DEBUG,
"Requesting format %s [0x%08" PRIx32
"] [%s]",
665 ClipboardGetFormatIdString(localFormatId), localFormatId,
666 ClipboardGetFormatName(clipboard->_system, localFormatId));
668 ClipboardLockGuard systemlock(clipboard->_system);
669 std::scoped_lock lock(clipboard->_lock);
671 const UINT32 fileFormatId =
672 ClipboardGetFormatId(clipboard->_system, s_type_FileGroupDescriptorW);
673 const UINT32 htmlFormatId = ClipboardGetFormatId(clipboard->_system, s_type_HtmlFormat);
680 mime = getCurrentTextMime();
683 localFormatId = ClipboardGetFormatId(clipboard->_system, mime);
688 mime = s_mime_bitmap().at(0);
689 localFormatId = ClipboardGetFormatId(clipboard->_system, mime);
697 if (formatId == fileFormatId)
699 localFormatId = ClipboardGetFormatId(clipboard->_system, s_mime_uri_list);
700 mime = s_mime_uri_list;
702 else if (formatId == htmlFormatId)
705 if (!SDL_HasClipboardData(s_mime_html))
707 mime = getCurrentImageMime();
709 localFormatId = ClipboardGetFormatId(clipboard->_system, mime);
713 localFormatId = ClipboardGetFormatId(clipboard->_system, s_mime_html);
719 const char* formatName = ClipboardGetFormatName(clipboard->_system, formatId);
720 if (formatName && SDL_HasClipboardData(formatName))
722 localFormatId = ClipboardGetFormatId(clipboard->_system, formatName);
733 auto sdldata = std::shared_ptr<void>(SDL_GetClipboardData(mime, &size), SDL_free);
737 if (fileFormatId == formatId)
739 auto bdata =
static_cast<const char*
>(sdldata.get());
740 if (!cliprdr_file_context_update_client_data(clipboard->_file, bdata, size))
744 res = ClipboardSetData(clipboard->_system, localFormatId, sdldata.get(),
745 static_cast<uint32_t
>(size));
752 auto ptr =
static_cast<BYTE*
>(ClipboardGetData(clipboard->_system, formatId, &ptrlen));
753 data = std::shared_ptr<BYTE>(ptr, free);
758 if (fileFormatId == formatId)
760 BYTE* ddata =
nullptr;
762 const UINT32 flags = cliprdr_file_context_remote_get_flags(clipboard->_file);
763 const UINT32 error = cliprdr_serialize_file_list_ex(
767 auto tmp = std::shared_ptr<BYTE>(ddata, free);
779UINT sdlClip::ReceiveFormatDataRequest(CliprdrClientContext* context,
782 WINPR_ASSERT(context);
783 WINPR_ASSERT(formatDataRequest);
785 auto clipboard =
static_cast<sdlClip*
>(
786 cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
787 WINPR_ASSERT(clipboard);
790 auto rc = ReceiveFormatDataRequestHandle(clipboard, formatDataRequest, len);
791 return clipboard->SendDataResponse(rc.get(), len);
794UINT sdlClip::ReceiveFormatDataResponse(CliprdrClientContext* context,
797 WINPR_ASSERT(context);
798 WINPR_ASSERT(formatDataResponse);
800 const UINT32 size = formatDataResponse->common.dataLen;
801 const BYTE* data = formatDataResponse->requestedFormatData;
803 auto clipboard =
static_cast<sdlClip*
>(
804 cliprdr_file_context_get_context(
static_cast<CliprdrFileContext*
>(context->custom)));
805 WINPR_ASSERT(clipboard);
807 ClipboardLockGuard systemlock(clipboard->_system);
808 std::scoped_lock lock(clipboard->_lock);
809 if (clipboard->_request_queue.empty())
815 WLog_Print(clipboard->_log, WLOG_WARN,
816 "format data response with no pending request (late reply?), ignoring");
817 return CHANNEL_RC_OK;
822 UINT32 srcFormatId = 0;
823 auto& request = clipboard->_request_queue.front();
824 bool success = (formatDataResponse->common.msgFlags & CB_RESPONSE_OK) &&
825 !(formatDataResponse->common.msgFlags & CB_RESPONSE_FAIL);
826 request.setSuccess(success);
830 WLog_Print(clipboard->_log, WLOG_WARN,
831 "clipboard data request for format %" PRIu32
" [%s], mime %s failed",
832 request.format(), request.formatstr().c_str(), request.mime().c_str());
836 switch (request.format())
841 srcFormatId = request.format();
846 srcFormatId = request.format();
851 auto name = clipboard->getServerFormat(request.format());
854 if (name == s_type_FileGroupDescriptorW)
857 ClipboardGetFormatId(clipboard->_system, s_type_FileGroupDescriptorW);
859 if (cliprdr_file_context_has_local_support(clipboard->_file))
861 if (!cliprdr_file_context_update_server_data(
862 clipboard->_file, clipboard->_system, data, size))
864 WLog_Print(clipboard->_log, WLOG_WARN,
865 "File clipboard failed to update");
869 else if (name == s_type_HtmlFormat)
871 srcFormatId = ClipboardGetFormatId(clipboard->_system, s_type_HtmlFormat);
878 if (!ClipboardSetData(clipboard->_system, srcFormatId, data, size))
880 WLog_Print(clipboard->_log, WLOG_ERROR,
"error when setting clipboard data");
881 return ERROR_INTERNAL_ERROR;
883 WLog_Print(clipboard->_log, WLOG_DEBUG,
"updated clipboard data %s [0x%08" PRIx32
"]",
884 ClipboardGetFormatName(clipboard->_system, srcFormatId), srcFormatId);
887 if (!SetEvent(clipboard->_event))
889 WLog_Print(clipboard->_log, WLOG_ERROR,
"error when setting clipboard event");
890 return ERROR_INTERNAL_ERROR;
893 return CHANNEL_RC_OK;
896const void* sdlClip::ClipDataCb(
void* userdata,
const char* mime_type,
size_t* size)
898 auto clip =
static_cast<sdlClip*
>(userdata);
901 WINPR_ASSERT(mime_type);
906 if (mime_is_text(mime_type))
907 mime_type =
"text/plain";
910 ClipboardLockGuard systemlock(clip->_system);
911 std::scoped_lock lock(clip->_lock);
914 auto cache = clip->_cache_data.find(mime_type);
915 if (cache != clip->_cache_data.end())
917 *size = cache->second.size;
918 return cache->second.ptr.get();
921 auto formatID = clip->serverIdForMime(mime_type);
925 auto mimeFormatID = ClipboardRegisterFormat(clip->_system, mime_type);
926 auto fptr = ClipboardGetData(clip->_system, mimeFormatID, &fsize);
929 auto ptr = std::shared_ptr<void>(fptr, free);
930 clip->_cache_data.insert({ mime_type, { fsize, ptr } });
932 auto fcache = clip->_cache_data.find(mime_type);
933 if (fcache != clip->_cache_data.end())
935 *size = fcache->second.size;
936 return fcache->second.ptr.get();
940 WLog_Print(clip->_log, WLOG_DEBUG,
"requesting format %s [%s 0x%08" PRIx32
"]", mime_type,
941 ClipboardGetFormatName(clip->_system, formatID), formatID);
942 if (clip->SendDataRequest(formatID, mime_type))
946 HANDLE hdl[2] = { freerdp_abort_event(clip->_sdl->context()), clip->_event };
948 const UINT32 timeout =
950 DWORD status = WaitForMultipleObjects(ARRAYSIZE(hdl), hdl, FALSE, timeout);
952 if (status != WAIT_OBJECT_0 + 1)
954 std::scoped_lock lock(clip->_lock);
955 clip->_request_queue.pop();
957 if (status == WAIT_TIMEOUT)
958 WLog_Print(clip->_log, WLOG_ERROR,
959 "no reply in 10 seconds, returning empty content");
966 ClipboardLockGuard systemlock(clip->_system);
967 std::scoped_lock lock(clip->_lock);
968 auto request = clip->_request_queue.front();
969 clip->_request_queue.pop();
971 if (clip->_request_queue.empty())
972 std::ignore = ResetEvent(clip->_event);
974 if (request.success())
976 auto formatID = ClipboardRegisterFormat(clip->_system, mime_type);
977 auto data = ClipboardGetData(clip->_system, formatID, &len);
980 WLog_Print(clip->_log, WLOG_ERROR,
"error retrieving clipboard data");
984 auto ptr = std::shared_ptr<void>(data, free);
985 clip->_cache_data.insert({ mime_type, { len, ptr } });
994void sdlClip::ClipCleanCb(
void* userdata)
996 auto clip =
static_cast<sdlClip*
>(userdata);
998 ClipboardLockGuard give_me_a_name(clip->_system);
999 std::scoped_lock lock(clip->_lock);
1000 ClipboardEmpty(clip->_system);
1003bool sdlClip::mime_is_file(
const std::string& mime)
1005 if (strncmp(s_mime_uri_list, mime.c_str(),
sizeof(s_mime_uri_list)) == 0)
1007 if (strncmp(s_mime_gnome_copied_files, mime.c_str(),
sizeof(s_mime_gnome_copied_files)) == 0)
1009 if (strncmp(s_mime_mate_copied_files, mime.c_str(),
sizeof(s_mime_mate_copied_files)) == 0)
1014bool sdlClip::mime_is_text(
const std::string& mime)
1016 for (
const auto& tmime : s_mime_text())
1018 assert(tmime !=
nullptr);
1026bool sdlClip::mime_is_image(
const std::string& mime)
1028 for (
const auto& imime : s_mime_image())
1030 assert(imime !=
nullptr);
1038bool sdlClip::mime_is_bmp(
const std::string& mime)
1040 for (
const auto& imime : s_mime_bitmap())
1042 assert(imime !=
nullptr);
1050bool sdlClip::mime_is_html(
const std::string& mime)
1052 return mime.compare(s_mime_html) == 0;
1055ClipRequest::ClipRequest(UINT32 format,
const std::string& mime)
1056 : _format(format), _mime(mime), _success(false)
1060uint32_t ClipRequest::format()
const
1065std::string ClipRequest::formatstr()
const
1067 return ClipboardGetFormatIdString(_format);
1070std::string ClipRequest::mime()
const
1075bool ClipRequest::success()
const
1080void ClipRequest::setSuccess(
bool status)
1085CliprdrFormat::CliprdrFormat(uint32_t formatID,
const char* formatName) : _formatID(formatID)
1088 _formatName = formatName;
1091uint32_t CliprdrFormat::formatId()
const
1096const char* CliprdrFormat::formatName()
const
1098 if (_formatName.empty())
1100 return _formatName.c_str();
object that handles clipboard context for the SDL3 client
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.