Atlas - SDL_waylanddatamanager.c
Home / ext / SDL / src / video / wayland Lines: 1 | Size: 25521 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22#include "SDL_internal.h" 23 24#ifdef SDL_VIDEO_DRIVER_WAYLAND 25 26#include <fcntl.h> 27#include <unistd.h> 28#include <limits.h> 29#include <signal.h> 30 31#include "../../core/unix/SDL_poll.h" 32#include "../../events/SDL_events_c.h" 33#include "../SDL_clipboard_c.h" 34 35#include "SDL_waylandvideo.h" 36#include "SDL_waylandevents_c.h" 37#include "SDL_waylanddatamanager.h" 38#include "primary-selection-unstable-v1-client-protocol.h" 39 40/* This is arbitrary, but reading while polling should block for less than a frame, to 41 * prevent hanging while pumping events. 42 * 43 * When querying the clipboard data directly, a larger value is needed to avoid timing 44 * out if the source needs to process or transfer a large amount of data. 45 */ 46#define DEFAULT_PIPE_TIMEOUT_NS SDL_MS_TO_NS(14) 47#define EXTENDED_PIPE_TIMEOUT_NS SDL_MS_TO_NS(5000) 48 49/* sigtimedwait() is an optional part of POSIX.1-2001, and OpenBSD doesn't implement it. 50 * Based on https://comp.unix.programmer.narkive.com/rEDH0sPT/sigtimedwait-implementation 51 */ 52#ifndef HAVE_SIGTIMEDWAIT 53#include <errno.h> 54#include <time.h> 55static int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) 56{ 57 struct timespec elapsed = { 0 }, rem = { 0 }; 58 sigset_t pending; 59 60 do { 61 // Check the pending signals, and call sigwait if there is at least one of interest in the set. 62 sigpending(&pending); 63 for (int signo = 1; signo < NSIG; ++signo) { 64 if (sigismember(set, signo) && sigismember(&pending, signo)) { 65 if (!sigwait(set, &signo)) { 66 if (info) { 67 SDL_zerop(info); 68 info->si_signo = signo; 69 } 70 return signo; 71 } else { 72 return -1; 73 } 74 } 75 } 76 77 if (timeout->tv_sec || timeout->tv_nsec) { 78 long ns = 20000000L; // 2/100ths of a second 79 nanosleep(&(struct timespec){ 0, ns }, &rem); 80 ns -= rem.tv_nsec; 81 elapsed.tv_sec += (elapsed.tv_nsec + ns) / 1000000000L; 82 elapsed.tv_nsec = (elapsed.tv_nsec + ns) % 1000000000L; 83 } 84 } while (elapsed.tv_sec < timeout->tv_sec || (elapsed.tv_sec == timeout->tv_sec && elapsed.tv_nsec < timeout->tv_nsec)); 85 86 errno = EAGAIN; 87 return -1; 88} 89#endif 90 91static ssize_t write_pipe(int fd, const void *buffer, size_t total_length, size_t *pos) 92{ 93 int ready = 0; 94 ssize_t bytes_written = 0; 95 ssize_t length = total_length - *pos; 96 97 sigset_t sig_set; 98 sigset_t old_sig_set; 99 struct timespec zerotime = { 0 }; 100 101 ready = SDL_IOReady(fd, SDL_IOR_WRITE, DEFAULT_PIPE_TIMEOUT_NS); 102 103 sigemptyset(&sig_set); 104 sigaddset(&sig_set, SIGPIPE); 105 106#ifdef SDL_THREADS_DISABLED 107 sigprocmask(SIG_BLOCK, &sig_set, &old_sig_set); 108#else 109 pthread_sigmask(SIG_BLOCK, &sig_set, &old_sig_set); 110#endif 111 112 if (ready == 0) { 113 bytes_written = SDL_SetError("Pipe timeout"); 114 } else if (ready < 0) { 115 bytes_written = SDL_SetError("Pipe select error"); 116 } else { 117 if (length > 0) { 118 bytes_written = write(fd, (Uint8 *)buffer + *pos, SDL_min(length, PIPE_BUF)); 119 } 120 121 if (bytes_written > 0) { 122 *pos += bytes_written; 123 } 124 } 125 126 sigtimedwait(&sig_set, NULL, &zerotime); 127 128#ifdef SDL_THREADS_DISABLED 129 sigprocmask(SIG_SETMASK, &old_sig_set, NULL); 130#else 131 pthread_sigmask(SIG_SETMASK, &old_sig_set, NULL); 132#endif 133 134 return bytes_written; 135} 136 137static ssize_t read_pipe(int fd, void **buffer, size_t *total_length, Sint64 timeout_ns) 138{ 139 int ready = 0; 140 void *output_buffer = NULL; 141 char temp[PIPE_BUF]; 142 size_t new_buffer_length = 0; 143 ssize_t bytes_read = 0; 144 size_t pos = 0; 145 146 ready = SDL_IOReady(fd, SDL_IOR_READ, timeout_ns); 147 148 if (ready == 0) { 149 bytes_read = SDL_SetError("Pipe timeout"); 150 } else if (ready < 0) { 151 bytes_read = SDL_SetError("Pipe select error"); 152 } else { 153 bytes_read = read(fd, temp, sizeof(temp)); 154 } 155 156 if (bytes_read > 0) { 157 pos = *total_length; 158 *total_length += bytes_read; 159 160 new_buffer_length = *total_length + sizeof(Uint32); 161 162 if (!*buffer) { 163 output_buffer = SDL_malloc(new_buffer_length); 164 } else { 165 output_buffer = SDL_realloc(*buffer, new_buffer_length); 166 } 167 168 if (!output_buffer) { 169 bytes_read = -1; 170 } else { 171 SDL_memcpy((Uint8 *)output_buffer + pos, temp, bytes_read); 172 SDL_memset((Uint8 *)output_buffer + (new_buffer_length - sizeof(Uint32)), 0, sizeof(Uint32)); 173 174 *buffer = output_buffer; 175 } 176 } 177 178 return bytes_read; 179} 180 181static SDL_MimeDataList *mime_data_list_find(struct wl_list *list, 182 const char *mime_type) 183{ 184 SDL_MimeDataList *found = NULL; 185 186 SDL_MimeDataList *mime_list = NULL; 187 wl_list_for_each (mime_list, list, link) { 188 if (SDL_strcmp(mime_list->mime_type, mime_type) == 0) { 189 found = mime_list; 190 break; 191 } 192 } 193 return found; 194} 195 196static bool mime_data_list_add(struct wl_list *list, 197 const char *mime_type, 198 const void *buffer, size_t length) 199{ 200 bool result = true; 201 size_t mime_type_length = 0; 202 SDL_MimeDataList *mime_data = NULL; 203 void *internal_buffer = NULL; 204 205 if (buffer) { 206 internal_buffer = SDL_malloc(length); 207 if (!internal_buffer) { 208 return false; 209 } 210 SDL_memcpy(internal_buffer, buffer, length); 211 } 212 213 mime_data = mime_data_list_find(list, mime_type); 214 215 if (!mime_data) { 216 mime_data = SDL_calloc(1, sizeof(*mime_data)); 217 if (!mime_data) { 218 result = false; 219 } else { 220 WAYLAND_wl_list_insert(list, &(mime_data->link)); 221 222 mime_type_length = SDL_strlen(mime_type) + 1; 223 mime_data->mime_type = SDL_malloc(mime_type_length); 224 if (!mime_data->mime_type) { 225 result = false; 226 } else { 227 SDL_memcpy(mime_data->mime_type, mime_type, mime_type_length); 228 } 229 } 230 } 231 232 if (mime_data && buffer && length > 0) { 233 SDL_free(mime_data->data); 234 mime_data->data = internal_buffer; 235 mime_data->length = length; 236 } else { 237 SDL_free(internal_buffer); 238 } 239 240 return result; 241} 242 243static void mime_data_list_free(struct wl_list *list) 244{ 245 SDL_MimeDataList *mime_data = NULL; 246 SDL_MimeDataList *next = NULL; 247 248 wl_list_for_each_safe (mime_data, next, list, link) { 249 SDL_free(mime_data->data); 250 SDL_free(mime_data->mime_type); 251 SDL_free(mime_data); 252 } 253} 254 255static size_t Wayland_send_data(const void *data, size_t length, int fd) 256{ 257 size_t result = 0; 258 259 if (length > 0 && data) { 260 while (write_pipe(fd, data, length, &result) > 0) { 261 // Just keep spinning 262 } 263 } 264 close(fd); 265 266 return result; 267} 268 269ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source, const char *mime_type, int fd) 270{ 271 const void *data = NULL; 272 size_t length = 0; 273 274 if (SDL_strcmp(mime_type, SDL_DATA_ORIGIN_MIME) == 0) { 275 data = source->data_device->id_str; 276 length = SDL_strlen(source->data_device->id_str); 277 } else if (source->callback) { 278 data = source->callback(source->userdata.data, mime_type, &length); 279 } 280 281 return Wayland_send_data(data, length, fd); 282} 283 284ssize_t Wayland_primary_selection_source_send(SDL_WaylandPrimarySelectionSource *source, const char *mime_type, int fd) 285{ 286 const void *data = NULL; 287 size_t length = 0; 288 289 if (source->callback) { 290 data = source->callback(source->userdata.data, mime_type, &length); 291 } 292 293 return Wayland_send_data(data, length, fd); 294} 295 296void Wayland_data_source_set_callback(SDL_WaylandDataSource *source, 297 SDL_ClipboardDataCallback callback, 298 void *userdata, 299 Uint32 sequence) 300{ 301 if (source) { 302 source->callback = callback; 303 source->userdata.sequence = sequence; 304 source->userdata.data = userdata; 305 } 306} 307 308void Wayland_primary_selection_source_set_callback(SDL_WaylandPrimarySelectionSource *source, 309 SDL_ClipboardDataCallback callback, 310 void *userdata) 311{ 312 if (source) { 313 source->callback = callback; 314 source->userdata.sequence = 0; 315 source->userdata.data = userdata; 316 } 317} 318 319static void *Wayland_clone_data_buffer(const void *buffer, const size_t *len) 320{ 321 void *clone = NULL; 322 if (*len > 0 && buffer) { 323 clone = SDL_malloc((*len)+sizeof(Uint32)); 324 if (clone) { 325 SDL_memcpy(clone, buffer, *len); 326 SDL_memset((Uint8 *)clone + *len, 0, sizeof(Uint32)); 327 } 328 } 329 return clone; 330} 331 332void *Wayland_data_source_get_data(SDL_WaylandDataSource *source, 333 const char *mime_type, size_t *length) 334{ 335 void *buffer = NULL; 336 const void *internal_buffer; 337 *length = 0; 338 339 if (!source) { 340 SDL_SetError("Invalid data source"); 341 } else if (source->callback) { 342 internal_buffer = source->callback(source->userdata.data, mime_type, length); 343 buffer = Wayland_clone_data_buffer(internal_buffer, length); 344 } 345 346 return buffer; 347} 348 349void *Wayland_primary_selection_source_get_data(SDL_WaylandPrimarySelectionSource *source, 350 const char *mime_type, size_t *length) 351{ 352 void *buffer = NULL; 353 const void *internal_buffer; 354 *length = 0; 355 356 if (!source) { 357 SDL_SetError("Invalid primary selection source"); 358 } else if (source->callback) { 359 internal_buffer = source->callback(source->userdata.data, mime_type, length); 360 buffer = Wayland_clone_data_buffer(internal_buffer, length); 361 } 362 363 return buffer; 364} 365 366void Wayland_data_source_destroy(SDL_WaylandDataSource *source) 367{ 368 if (source) { 369 SDL_WaylandDataDevice *data_device = (SDL_WaylandDataDevice *)source->data_device; 370 if (data_device && (data_device->selection_source == source)) { 371 data_device->selection_source = NULL; 372 } 373 wl_data_source_destroy(source->source); 374 if (source->userdata.sequence) { 375 SDL_CancelClipboardData(source->userdata.sequence); 376 } else { 377 SDL_free(source->userdata.data); 378 } 379 SDL_free(source); 380 } 381} 382 383void Wayland_primary_selection_source_destroy(SDL_WaylandPrimarySelectionSource *source) 384{ 385 if (source) { 386 SDL_WaylandPrimarySelectionDevice *primary_selection_device = (SDL_WaylandPrimarySelectionDevice *)source->primary_selection_device; 387 if (primary_selection_device && (primary_selection_device->selection_source == source)) { 388 primary_selection_device->selection_source = NULL; 389 } 390 zwp_primary_selection_source_v1_destroy(source->source); 391 if (source->userdata.sequence == 0) { 392 SDL_free(source->userdata.data); 393 } 394 SDL_free(source); 395 } 396} 397 398static void offer_source_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data) 399{ 400 if (!callback) { 401 return; 402 } 403 404 SDL_WaylandDataOffer *offer = data; 405 char *id = NULL; 406 size_t length = 0; 407 408 wl_callback_destroy(offer->callback); 409 offer->callback = NULL; 410 411 while (read_pipe(offer->read_fd, (void **)&id, &length, DEFAULT_PIPE_TIMEOUT_NS) > 0) { 412 } 413 close(offer->read_fd); 414 offer->read_fd = -1; 415 416 if (id) { 417 const bool source_is_external = SDL_strncmp(offer->data_device->id_str, id, length) != 0; 418 SDL_free(id); 419 if (source_is_external) { 420 Wayland_data_offer_notify_from_mimes(offer, false); 421 } 422 } 423} 424 425static struct wl_callback_listener offer_source_listener = { 426 offer_source_done_handler 427}; 428 429static void Wayland_data_offer_check_source(SDL_WaylandDataOffer *offer, const char *mime_type) 430{ 431 SDL_WaylandDataDevice *data_device = NULL; 432 int pipefd[2]; 433 434 if (!offer) { 435 SDL_SetError("Invalid data offer"); 436 return; 437 } 438 data_device = offer->data_device; 439 if (!data_device) { 440 SDL_SetError("Data device not initialized"); 441 } else if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1) { 442 SDL_SetError("Could not read pipe"); 443 } else { 444 if (offer->callback) { 445 wl_callback_destroy(offer->callback); 446 } 447 if (offer->read_fd >= 0) { 448 close(offer->read_fd); 449 } 450 451 offer->read_fd = pipefd[0]; 452 453 wl_data_offer_receive(offer->offer, mime_type, pipefd[1]); 454 close(pipefd[1]); 455 456 offer->callback = wl_display_sync(offer->data_device->seat->display->display); 457 wl_callback_add_listener(offer->callback, &offer_source_listener, offer); 458 459 WAYLAND_wl_display_flush(data_device->seat->display->display); 460 } 461} 462 463void Wayland_data_offer_notify_from_mimes(SDL_WaylandDataOffer *offer, bool check_origin) 464{ 465 int nformats = 0; 466 char **new_mime_types = NULL; 467 if (offer) { 468 size_t alloc_size = 0; 469 470 // Do a first pass to compute allocation size. 471 SDL_MimeDataList *item = NULL; 472 wl_list_for_each(item, &offer->mimes, link) { 473 // If origin metadata is found, queue a check and wait for confirmation that this offer isn't recursive. 474 if (check_origin && SDL_strcmp(item->mime_type, SDL_DATA_ORIGIN_MIME) == 0) { 475 Wayland_data_offer_check_source(offer, item->mime_type); 476 return; 477 } 478 479 ++nformats; 480 alloc_size += SDL_strlen(item->mime_type) + 1; 481 } 482 483 alloc_size += (nformats + 1) * sizeof(char *); 484 485 new_mime_types = SDL_AllocateTemporaryMemory(alloc_size); 486 if (!new_mime_types) { 487 SDL_LogError(SDL_LOG_CATEGORY_INPUT, "unable to allocate new_mime_types"); 488 return; 489 } 490 491 // Second pass to fill. 492 char *strPtr = (char *)(new_mime_types + nformats + 1); 493 item = NULL; 494 int i = 0; 495 wl_list_for_each(item, &offer->mimes, link) { 496 new_mime_types[i] = strPtr; 497 strPtr = stpcpy(strPtr, item->mime_type) + 1; 498 i++; 499 } 500 new_mime_types[nformats] = NULL; 501 } 502 503 SDL_SendClipboardUpdate(false, new_mime_types, nformats); 504} 505 506void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, const char *mime_type, size_t *length, bool extended_timeout) 507{ 508 SDL_WaylandDataDevice *data_device = NULL; 509 const Sint64 timeout = extended_timeout ? EXTENDED_PIPE_TIMEOUT_NS : DEFAULT_PIPE_TIMEOUT_NS; 510 511 int pipefd[2]; 512 void *buffer = NULL; 513 *length = 0; 514 515 if (!offer) { 516 SDL_SetError("Invalid data offer"); 517 return NULL; 518 } 519 data_device = offer->data_device; 520 if (!data_device) { 521 SDL_SetError("Data device not initialized"); 522 } else if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1) { 523 SDL_SetError("Could not read pipe"); 524 } else { 525 wl_data_offer_receive(offer->offer, mime_type, pipefd[1]); 526 close(pipefd[1]); 527 528 WAYLAND_wl_display_flush(data_device->seat->display->display); 529 530 while (read_pipe(pipefd[0], &buffer, length, timeout) > 0) { 531 } 532 close(pipefd[0]); 533 } 534 SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, 535 ". In Wayland_data_offer_receive for '%s', buffer (%zu) at %p", 536 mime_type, *length, buffer); 537 return buffer; 538} 539 540void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer *offer, 541 const char *mime_type, size_t *length) 542{ 543 SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL; 544 545 int pipefd[2]; 546 void *buffer = NULL; 547 *length = 0; 548 549 if (!offer) { 550 SDL_SetError("Invalid data offer"); 551 return NULL; 552 } 553 primary_selection_device = offer->primary_selection_device; 554 if (!primary_selection_device) { 555 SDL_SetError("Primary selection device not initialized"); 556 } else if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) == -1) { 557 SDL_SetError("Could not read pipe"); 558 } else { 559 zwp_primary_selection_offer_v1_receive(offer->offer, mime_type, pipefd[1]); 560 close(pipefd[1]); 561 562 WAYLAND_wl_display_flush(primary_selection_device->seat->display->display); 563 564 while (read_pipe(pipefd[0], &buffer, length, EXTENDED_PIPE_TIMEOUT_NS) > 0) { 565 } 566 close(pipefd[0]); 567 } 568 SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, 569 ". In Wayland_primary_selection_offer_receive for '%s', buffer (%zu) at %p", 570 mime_type, *length, buffer); 571 return buffer; 572} 573 574bool Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer, 575 const char *mime_type) 576{ 577 return mime_data_list_add(&offer->mimes, mime_type, NULL, 0); 578} 579 580bool Wayland_primary_selection_offer_add_mime(SDL_WaylandPrimarySelectionOffer *offer, 581 const char *mime_type) 582{ 583 return mime_data_list_add(&offer->mimes, mime_type, NULL, 0); 584} 585 586bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer, 587 const char *mime_type) 588{ 589 bool found = false; 590 591 if (offer) { 592 found = mime_data_list_find(&offer->mimes, mime_type) != NULL; 593 } 594 return found; 595} 596 597bool Wayland_primary_selection_offer_has_mime(SDL_WaylandPrimarySelectionOffer *offer, 598 const char *mime_type) 599{ 600 bool found = false; 601 602 if (offer) { 603 found = mime_data_list_find(&offer->mimes, mime_type) != NULL; 604 } 605 return found; 606} 607 608void Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer) 609{ 610 if (offer) { 611 if (offer->callback) { 612 wl_callback_destroy(offer->callback); 613 } 614 if (offer->read_fd >= 0) { 615 close(offer->read_fd); 616 } 617 wl_data_offer_destroy(offer->offer); 618 mime_data_list_free(&offer->mimes); 619 SDL_free(offer); 620 } 621} 622 623void Wayland_primary_selection_offer_destroy(SDL_WaylandPrimarySelectionOffer *offer) 624{ 625 if (offer) { 626 zwp_primary_selection_offer_v1_destroy(offer->offer); 627 mime_data_list_free(&offer->mimes); 628 SDL_free(offer); 629 } 630} 631 632bool Wayland_data_device_clear_selection(SDL_WaylandDataDevice *data_device) 633{ 634 bool result = true; 635 636 if (!data_device || !data_device->data_device) { 637 result = SDL_SetError("Invalid Data Device"); 638 } else if (data_device->selection_source) { 639 wl_data_device_set_selection(data_device->data_device, NULL, data_device->seat->last_implicit_grab_serial); 640 Wayland_data_source_destroy(data_device->selection_source); 641 data_device->selection_source = NULL; 642 } 643 return result; 644} 645 646bool Wayland_primary_selection_device_clear_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device) 647{ 648 bool result = true; 649 650 if (!primary_selection_device || !primary_selection_device->primary_selection_device) { 651 result = SDL_SetError("Invalid Primary Selection Device"); 652 } else if (primary_selection_device->selection_source) { 653 zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device, 654 NULL, primary_selection_device->seat->last_implicit_grab_serial); 655 Wayland_primary_selection_source_destroy(primary_selection_device->selection_source); 656 primary_selection_device->selection_source = NULL; 657 } 658 return result; 659} 660 661bool Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device, 662 SDL_WaylandDataSource *source, 663 const char **mime_types, 664 size_t mime_count) 665{ 666 bool result = true; 667 668 if (!data_device) { 669 result = SDL_SetError("Invalid Data Device"); 670 } else if (!source) { 671 result = SDL_SetError("Invalid source"); 672 } else { 673 size_t index = 0; 674 const char *mime_type; 675 676 for (index = 0; index < mime_count; ++index) { 677 mime_type = mime_types[index]; 678 wl_data_source_offer(source->source, 679 mime_type); 680 } 681 682 // Advertise the data origin MIME 683 wl_data_source_offer(source->source, SDL_DATA_ORIGIN_MIME); 684 685 if (index == 0) { 686 Wayland_data_device_clear_selection(data_device); 687 result = SDL_SetError("No mime data"); 688 } else { 689 // Only set if there is a valid serial if not set it later 690 if (data_device->selection_serial != 0) { 691 wl_data_device_set_selection(data_device->data_device, 692 source->source, 693 data_device->selection_serial); 694 } 695 if (data_device->selection_source) { 696 Wayland_data_source_destroy(data_device->selection_source); 697 } 698 data_device->selection_source = source; 699 source->data_device = data_device; 700 } 701 } 702 703 return result; 704} 705 706bool Wayland_primary_selection_device_set_selection(SDL_WaylandPrimarySelectionDevice *primary_selection_device, 707 SDL_WaylandPrimarySelectionSource *source, 708 const char **mime_types, 709 size_t mime_count) 710{ 711 bool result = true; 712 713 if (!primary_selection_device) { 714 result = SDL_SetError("Invalid Primary Selection Device"); 715 } else if (!source) { 716 result = SDL_SetError("Invalid source"); 717 } else { 718 size_t index = 0; 719 const char *mime_type = mime_types[index]; 720 721 for (index = 0; index < mime_count; ++index) { 722 mime_type = mime_types[index]; 723 zwp_primary_selection_source_v1_offer(source->source, mime_type); 724 } 725 726 if (index == 0) { 727 Wayland_primary_selection_device_clear_selection(primary_selection_device); 728 result = SDL_SetError("No mime data"); 729 } else { 730 // Only set if there is a valid serial if not set it later 731 if (primary_selection_device->selection_serial != 0) { 732 zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device, 733 source->source, 734 primary_selection_device->selection_serial); 735 } 736 if (primary_selection_device->selection_source) { 737 Wayland_primary_selection_source_destroy(primary_selection_device->selection_source); 738 } 739 primary_selection_device->selection_source = source; 740 source->primary_selection_device = primary_selection_device; 741 } 742 } 743 744 return result; 745} 746 747void Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device, uint32_t serial) 748{ 749 if (data_device) { 750 data_device->selection_serial = serial; 751 752 // If there was no serial and there is a pending selection set it now. 753 if (data_device->selection_serial == 0 && data_device->selection_source) { 754 wl_data_device_set_selection(data_device->data_device, 755 data_device->selection_source->source, 756 data_device->selection_serial); 757 } 758 } 759} 760 761void Wayland_primary_selection_device_set_serial(SDL_WaylandPrimarySelectionDevice *primary_selection_device, 762 uint32_t serial) 763{ 764 if (primary_selection_device) { 765 primary_selection_device->selection_serial = serial; 766 767 // If there was no serial and there is a pending selection set it now. 768 if (primary_selection_device->selection_serial == 0 && primary_selection_device->selection_source) { 769 zwp_primary_selection_device_v1_set_selection(primary_selection_device->primary_selection_device, 770 primary_selection_device->selection_source->source, 771 primary_selection_device->selection_serial); 772 } 773 } 774} 775 776#endif // SDL_VIDEO_DRIVER_WAYLAND 777[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.