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
295
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
313
314 if (cliprdr_file_context_set_local_clipboard_data(_file, sdlClip::ClipDataCb, this,
315 cmimes.data(), cmimes.size()))
316 return true;
317
318
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
330
331
332
333
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
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
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
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
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}