Atlas - SDL_waylanddatamanager.c

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