195{
196 std::unique_ptr<char*, decltype(&SDL_free)> current(nullptr, SDL_free);
197 const char** mime_types = ev.mime_types;
198 size_t nformats = WINPR_ASSERTING_INT_CAST(size_t, ev.num_mime_types);
199 if (_ctx && _sync && ev.owner && (ev.num_mime_types == 1))
200 {
201 if (strcmp(first_announcement[0], ev.mime_types[0]) == 0)
202 {
203 current.reset(SDL_GetClipboardMimeTypes(&nformats));
204 mime_types = const_cast<const char**>(current.get());
205 if (!mime_types)
206 nformats = 0;
207 }
208 }
209 else if (!_ctx || !_sync || ev.owner)
210 {
211 _last_timestamp = ev.timestamp;
212 if (!_current_mimetypes.empty())
213 {
214 _cache_data.clear();
215 auto rc =
216 SDL_SetClipboardData(sdlClip::ClipDataCb, sdlClip::ClipCleanCb, this, ev.mime_types,
217 WINPR_ASSERTING_INT_CAST(size_t, ev.num_mime_types));
218 _current_mimetypes.clear();
219 return rc;
220 }
221 return true;
222 }
223
224 if (ev.timestamp == _last_timestamp)
225 return true;
226
227 if (contains(mime_types, WINPR_ASSERTING_INT_CAST(Sint32, nformats)))
228 return true;
229
230 clearServerFormats();
231
232 const std::string mime_html = s_mime_html;
233
234 const std::vector<std::string> mime_bitmap = { BMP_MIME_LIST };
235 const std::string mime_webp = s_mime_webp;
236 const std::string mime_png = s_mime_png;
237 const std::string mime_jpeg = s_mime_jpg;
238 const std::string mime_tiff = s_mime_tiff;
239 const std::vector<std::string> mime_images = { mime_webp, mime_png, mime_jpeg,
240 mime_tiff, s_mime_avif, s_mime_jxl };
241
242 std::vector<std::string> clientFormatNames;
243 std::vector<CLIPRDR_FORMAT> clientFormats;
244
245 const char** clipboard_mime_formats = mime_types;
246
247 WLog_Print(_log, WLOG_TRACE, "SDL has %" PRIuz " formats", nformats);
248
249 bool textPushed = false;
250 bool imgPushed = false;
251 bool filePushed = false;
252
253 for (size_t i = 0; i < nformats; i++)
254 {
255 std::string local_mime = clipboard_mime_formats[i];
256 WLog_Print(_log, WLOG_TRACE, " - %s", local_mime.c_str());
257
258 if (std::find(s_mime_text().begin(), s_mime_text().end(), local_mime) !=
259 s_mime_text().end())
260 {
261
262 if (!textPushed)
263 {
264 clientFormats.push_back({ CF_TEXT, nullptr });
265 clientFormats.push_back({ CF_OEMTEXT, nullptr });
266 clientFormats.push_back({ CF_UNICODETEXT, nullptr });
267 textPushed = true;
268 }
269 }
270 else if (local_mime == mime_html)
271
272 clientFormatNames.emplace_back(s_type_HtmlFormat);
273 else if ((std::find(mime_bitmap.begin(), mime_bitmap.end(), local_mime) !=
274 mime_bitmap.end()) ||
275 (std::find(mime_images.begin(), mime_images.end(), local_mime) !=
276 mime_images.end()))
277 {
278
279 if (!imgPushed)
280 {
281 clientFormats.push_back({ CF_DIB, nullptr });
282#if defined(WINPR_UTILS_IMAGE_DIBv5)
283 clientFormats.push_back({ CF_DIBV5, nullptr });
284#endif
285
286 if (winpr_image_format_is_supported(WINPR_IMAGE_BITMAP))
287 {
288 for (auto& bmp : mime_bitmap)
289 clientFormatNames.push_back(bmp);
290 }
291
292 if (winpr_image_format_is_supported(WINPR_IMAGE_JPEG))
293 clientFormatNames.push_back(mime_jpeg);
294 if (winpr_image_format_is_supported(WINPR_IMAGE_WEBP))
295 clientFormatNames.push_back(mime_webp);
296 if (winpr_image_format_is_supported(WINPR_IMAGE_PNG))
297 clientFormatNames.push_back(mime_png);
298
299 clientFormatNames.emplace_back(s_type_HtmlFormat);
300 imgPushed = true;
301 }
302 clientFormatNames.push_back(local_mime);
303 }
304 else if (mime_is_file(local_mime))
305 {
306 if (!filePushed)
307 {
308 clientFormatNames.emplace_back(s_type_FileGroupDescriptorW);
309 filePushed = true;
310 }
311 }
312 }
313
314 std::sort(clientFormatNames.begin(), clientFormatNames.end());
315 clientFormatNames.erase(std::unique(clientFormatNames.begin(), clientFormatNames.end()),
316 clientFormatNames.end());
317
318 for (auto& name : clientFormatNames)
319 {
320 clientFormats.push_back({ ClipboardRegisterFormat(_system, name.c_str()), name.data() });
321 }
322
323 std::sort(clientFormats.begin(), clientFormats.end(),
324 [](const auto& a, const auto& b) { return a < b; });
325 auto u = std::unique(clientFormats.begin(), clientFormats.end());
326 clientFormats.erase(u, clientFormats.end());
327
329 { CB_FORMAT_LIST, 0, 0 },
330 static_cast<UINT32>(clientFormats.size()),
331 clientFormats.data(),
332 };
333
334 WLog_Print(_log, WLOG_TRACE,
335 "-------------- client format list [%" PRIu32 "] ------------------",
336 formatList.numFormats);
337 for (UINT32 x = 0; x < formatList.numFormats; x++)
338 {
339 auto format = &formatList.formats[x];
340 WLog_Print(_log, WLOG_TRACE, "client announces %" PRIu32 " [%s][%s]", format->formatId,
341 ClipboardGetFormatIdString(format->formatId), format->formatName);
342 }
343
344 if (cliprdr_file_context_notify_new_client_format_list(_file) != CHANNEL_RC_OK)
345 return false;
346
347 WINPR_ASSERT(_ctx);
348 WINPR_ASSERT(_ctx->ClientFormatList);
349 return _ctx->ClientFormatList(_ctx, &formatList) == CHANNEL_RC_OK;
350}