FreeRDP
Loading...
Searching...
No Matches
sdlClip Class Reference

object that handles clipboard context for the SDL3 client More...

#include <sdl_clip.hpp>

Public Member Functions

 sdlClip (SdlContext *sdl)
 
 sdlClip (const sdlClip &)=delete
 
 sdlClip (sdlClip &&)=delete
 
sdlClip & operator= (const sdlClip &)=delete
 
sdlClip & operator= (sdlClip &&)=delete
 
bool init (CliprdrClientContext *clip)
 
bool uninit (CliprdrClientContext *clip)
 
bool handleEvent (const SDL_ClipboardEvent &ev)
 
void handleDataRequests ()
 

Detailed Description

object that handles clipboard context for the SDL3 client

Definition at line 76 of file sdl_clip.hpp.

Constructor & Destructor Documentation

◆ sdlClip()

sdlClip::sdlClip ( SdlContext *  sdl)
explicit

Definition at line 211 of file sdl_clip.cpp.

212 : _sdl(sdl), _file(cliprdr_file_context_new(this)), _log(WLog_Get(TAG)),
213 _system(ClipboardCreate()), _event(CreateEventA(nullptr, TRUE, FALSE, nullptr)),
214 _uuid(sdl::utils::generate_uuid_v4())
215{
216 WINPR_ASSERT(sdl);
217
218 std::stringstream ss;
219 ss << s_mime_freerdp_update << "-" << _uuid;
220 _mime_uuid = ss.str();
221
222 std::ignore = cliprdr_file_context_set_locally_available(_file, TRUE);
223}

◆ ~sdlClip()

sdlClip::~sdlClip ( )
virtual

Definition at line 225 of file sdl_clip.cpp.

226{
227 cliprdr_file_context_free(_file);
228 ClipboardDestroy(_system);
229 std::ignore = CloseHandle(_event);
230}

Member Function Documentation

◆ handleDataRequests()

void sdlClip::handleDataRequests ( )

Definition at line 1001 of file sdl_clip.cpp.

1002{
1003 for (;;)
1004 {
1005 uint32_t formatId = 0;
1006 {
1007 std::scoped_lock lock(_lock);
1008 if (_server_requests.empty())
1009 return;
1010 formatId = _server_requests.front();
1011 _server_requests.pop_front();
1012 }
1013 if (!_ctx)
1014 continue;
1015
1016 uint32_t len = 0;
1017 auto data = getLocalData(formatId, len);
1018 if (SendDataResponse(data.get(), len) != CHANNEL_RC_OK)
1019 WLog_Print(_log, WLOG_WARN, "failed to send clipboard data response");
1020 }
1021}

◆ handleEvent()

bool sdlClip::handleEvent ( const SDL_ClipboardEvent &  ev)

Definition at line 275 of file sdl_clip.cpp.

276{
277 std::unique_ptr<char*, decltype(&SDL_free)> current(nullptr, SDL_free);
278 const char** mime_types = ev.mime_types;
279 size_t nformats = WINPR_ASSERTING_INT_CAST(size_t, ev.num_mime_types);
280 if (_ctx && _sync && ev.owner && (ev.num_mime_types == 1))
281 {
282 if (strcmp(first_announcement[0], ev.mime_types[0]) == 0)
283 {
284 current.reset(SDL_GetClipboardMimeTypes(&nformats));
285 mime_types = const_cast<const char**>(current.get());
286 if (!mime_types)
287 nformats = 0;
288 }
289 }
290 else if (!_ctx || !_sync || ev.owner)
291 {
292 _last_timestamp = ev.timestamp;
293
294 /* The channel thread replaces _current_mimetypes on every server format list, so take
295 * them under the lock instead of trusting pointers carried in the event. */
296 std::vector<std::string> mimes;
297 {
298 ClipboardLockGuard systemlock(_system);
299 std::scoped_lock lock(_lock);
300 mimes.swap(_current_mimetypes);
301 if (!mimes.empty())
302 _cache_data.clear();
303 }
304 if (mimes.empty())
305 return true;
306
307 std::vector<const char*> cmimes;
308 cmimes.reserve(mimes.size());
309 for (const auto& m : mimes)
310 cmimes.push_back(m.c_str());
311
312 /* Server files need native clipboard items on some platforms (macOS), which only the
313 * file context can offer. It requests the data with ClipDataCb like SDL does. */
314 if (cliprdr_file_context_set_local_clipboard_data(_file, sdlClip::ClipDataCb, this,
315 cmimes.data(), cmimes.size()))
316 return true;
317
318 /* SDL copies the mime type strings */
319 return SDL_SetClipboardData(sdlClip::ClipDataCb, sdlClip::ClipCleanCb, this, cmimes.data(),
320 cmimes.size());
321 }
322
323 if (ev.timestamp == _last_timestamp)
324 return true;
325
326 if (contains(mime_types, WINPR_ASSERTING_INT_CAST(Sint32, nformats)))
327 return true;
328
329 /* SDL holds this session's server data right now, so this update was queued before our
330 * later SDL_SetClipboardData took effect: typically the selection a compositor re-sends on
331 * focus-in, racing a server format list. Announcing it would replace the fresh server
332 * clipboard with the stale local one (and the server would then ask us for data we no
333 * longer own). A genuine local change cancels our data before its update is queued. */
334 if (ownsClipboard())
335 {
336 WLog_Print(_log, WLOG_DEBUG, "ignoring stale local clipboard update");
337 return true;
338 }
339
340 {
341 ClipboardLockGuard systemlock(_system);
342 std::scoped_lock lock(_lock);
343 clearServerFormats();
344 }
345
346 const std::string mime_html = s_mime_html;
347
348 const std::vector<std::string> mime_bitmap = { BMP_MIME_LIST };
349 const std::string mime_webp = s_mime_webp;
350 const std::string mime_png = s_mime_png;
351 const std::string mime_jpeg = s_mime_jpg;
352 const std::string mime_tiff = s_mime_tiff;
353 const std::vector<std::string> mime_images = { mime_webp, mime_png, mime_jpeg,
354 mime_tiff, s_mime_avif, s_mime_jxl };
355
356 std::vector<std::string> clientFormatNames;
357 std::vector<CLIPRDR_FORMAT> clientFormats;
358
359 const char** clipboard_mime_formats = mime_types;
360
361 WLog_Print(_log, WLOG_TRACE, "SDL has %" PRIuz " formats", nformats);
362
363 bool textPushed = false;
364 bool imgPushed = false;
365 bool filePushed = false;
366
367 for (size_t i = 0; i < nformats; i++)
368 {
369 std::string local_mime = clipboard_mime_formats[i];
370 WLog_Print(_log, WLOG_TRACE, " - %s", local_mime.c_str());
371
372 if (std::find(s_mime_text().begin(), s_mime_text().end(), local_mime) !=
373 s_mime_text().end())
374 {
375 /* text formats */
376 if (!textPushed)
377 {
378 clientFormats.push_back({ CF_TEXT, nullptr });
379 clientFormats.push_back({ CF_OEMTEXT, nullptr });
380 clientFormats.push_back({ CF_UNICODETEXT, nullptr });
381 textPushed = true;
382 }
383 }
384 else if (local_mime == mime_html)
385 /* html */
386 clientFormatNames.emplace_back(s_type_HtmlFormat);
387 else if ((std::find(mime_bitmap.begin(), mime_bitmap.end(), local_mime) !=
388 mime_bitmap.end()) ||
389 (std::find(mime_images.begin(), mime_images.end(), local_mime) !=
390 mime_images.end()))
391 {
392 /* image formats */
393 if (!imgPushed)
394 {
395 clientFormats.push_back({ CF_DIB, nullptr });
396#if defined(WINPR_UTILS_IMAGE_DIBv5)
397 clientFormats.push_back({ CF_DIBV5, nullptr });
398#endif
399
400 if (winpr_image_format_is_supported(WINPR_IMAGE_BITMAP))
401 {
402 for (auto& bmp : mime_bitmap)
403 clientFormatNames.push_back(bmp);
404 }
405
406 if (winpr_image_format_is_supported(WINPR_IMAGE_JPEG))
407 clientFormatNames.push_back(mime_jpeg);
408 if (winpr_image_format_is_supported(WINPR_IMAGE_WEBP))
409 clientFormatNames.push_back(mime_webp);
410 if (winpr_image_format_is_supported(WINPR_IMAGE_PNG))
411 clientFormatNames.push_back(mime_png);
412
413 clientFormatNames.emplace_back(s_type_HtmlFormat);
414 imgPushed = true;
415 }
416 clientFormatNames.push_back(local_mime);
417 }
418 else if (mime_is_file(local_mime) || (local_mime == s_type_file_url))
419 {
420 if (!filePushed)
421 {
422 clientFormatNames.emplace_back(s_type_FileGroupDescriptorW);
423 filePushed = true;
424 }
425 }
426 }
427
428 std::sort(clientFormatNames.begin(), clientFormatNames.end());
429 clientFormatNames.erase(std::unique(clientFormatNames.begin(), clientFormatNames.end()),
430 clientFormatNames.end());
431
432 for (auto& name : clientFormatNames)
433 {
434 clientFormats.push_back({ ClipboardRegisterFormat(_system, name.c_str()), name.data() });
435 }
436
437 std::sort(clientFormats.begin(), clientFormats.end(),
438 [](const auto& a, const auto& b) { return a < b; });
439 auto u = std::unique(clientFormats.begin(), clientFormats.end());
440 clientFormats.erase(u, clientFormats.end());
441
442 const CLIPRDR_FORMAT_LIST formatList = {
443 { CB_FORMAT_LIST, 0, 0 },
444 static_cast<UINT32>(clientFormats.size()),
445 clientFormats.data(),
446 };
447
448 WLog_Print(_log, WLOG_TRACE,
449 "-------------- client format list [%" PRIu32 "] ------------------",
450 formatList.numFormats);
451 for (UINT32 x = 0; x < formatList.numFormats; x++)
452 {
453 auto format = &formatList.formats[x];
454 WLog_Print(_log, WLOG_TRACE, "client announces %" PRIu32 " [%s][%s]", format->formatId,
455 ClipboardGetFormatIdString(format->formatId), format->formatName);
456 }
457
458 if (cliprdr_file_context_notify_new_client_format_list(_file) != CHANNEL_RC_OK)
459 return false;
460
461 WINPR_ASSERT(_ctx);
462 WINPR_ASSERT(_ctx->ClientFormatList);
463 return _ctx->ClientFormatList(_ctx, &formatList) == CHANNEL_RC_OK;
464}

◆ init()

bool sdlClip::init ( CliprdrClientContext *  clip)

Definition at line 232 of file sdl_clip.cpp.

233{
234 WINPR_ASSERT(clip);
235 _ctx = clip;
236 clip->custom = this;
237 _ctx->MonitorReady = sdlClip::MonitorReady;
238 _ctx->ServerCapabilities = sdlClip::ReceiveServerCapabilities;
239 _ctx->ServerFormatList = sdlClip::ReceiveServerFormatList;
240 _ctx->ServerFormatListResponse = sdlClip::ReceiveFormatListResponse;
241 _ctx->ServerFormatDataRequest = sdlClip::ReceiveFormatDataRequest;
242 _ctx->ServerFormatDataResponse = sdlClip::ReceiveFormatDataResponse;
243
244 return cliprdr_file_context_init(_file, _ctx);
245}

◆ uninit()

bool sdlClip::uninit ( CliprdrClientContext *  clip)

Definition at line 247 of file sdl_clip.cpp.

248{
249 WINPR_ASSERT(clip);
250 if (!cliprdr_file_context_uninit(_file, _ctx))
251 return false;
252 ClipboardLockGuard systemlock(_system);
253 std::scoped_lock lock(_lock);
254 _ctx = nullptr;
255 clip->custom = nullptr;
256 return true;
257}

The documentation for this class was generated from the following files: