Atlas - SDL_waylanddatamanager.c
Home / ext / SDL2 / src / video / wayland Lines: 1 | Size: 13245 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 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#if SDL_VIDEO_DRIVER_WAYLAND 25 26#include <fcntl.h> 27#include <unistd.h> 28#include <limits.h> 29#include <signal.h> 30 31#include "SDL_stdinc.h" 32#include "SDL_assert.h" 33#include "../../core/unix/SDL_poll.h" 34 35#include "SDL_waylandvideo.h" 36#include "SDL_waylanddatamanager.h" 37 38#include "SDL_waylanddyn.h" 39 40static ssize_t 41write_pipe(int fd, const void* buffer, size_t total_length, size_t *pos) 42{ 43 int ready = 0; 44 ssize_t bytes_written = 0; 45 ssize_t length = total_length - *pos; 46 47 sigset_t sig_set; 48 sigset_t old_sig_set; 49 struct timespec zerotime = {0}; 50 51 ready = SDL_IOReady(fd, SDL_TRUE, 1 * 1000); 52 53 sigemptyset(&sig_set); 54 sigaddset(&sig_set, SIGPIPE); 55 56 pthread_sigmask(SIG_BLOCK, &sig_set, &old_sig_set); 57 58 if (ready == 0) { 59 bytes_written = SDL_SetError("Pipe timeout"); 60 } else if (ready < 0) { 61 bytes_written = SDL_SetError("Pipe select error"); 62 } else { 63 if (length > 0) { 64 bytes_written = write(fd, (Uint8*)buffer + *pos, SDL_min(length, PIPE_BUF)); 65 } 66 67 if (bytes_written > 0) { 68 *pos += bytes_written; 69 } 70 } 71 72 sigtimedwait(&sig_set, 0, &zerotime); 73 pthread_sigmask(SIG_SETMASK, &old_sig_set, NULL); 74 75 return bytes_written; 76} 77 78static ssize_t 79read_pipe(int fd, void** buffer, size_t* total_length, SDL_bool null_terminate) 80{ 81 int ready = 0; 82 void* output_buffer = NULL; 83 char temp[PIPE_BUF]; 84 size_t new_buffer_length = 0; 85 ssize_t bytes_read = 0; 86 size_t pos = 0; 87 88 ready = SDL_IOReady(fd, SDL_FALSE, 1 * 1000); 89 90 if (ready == 0) { 91 bytes_read = SDL_SetError("Pipe timeout"); 92 } else if (ready < 0) { 93 bytes_read = SDL_SetError("Pipe select error"); 94 } else { 95 bytes_read = read(fd, temp, sizeof(temp)); 96 } 97 98 if (bytes_read > 0) { 99 pos = *total_length; 100 *total_length += bytes_read; 101 102 if (null_terminate == SDL_TRUE) { 103 new_buffer_length = *total_length + 1; 104 } else { 105 new_buffer_length = *total_length; 106 } 107 108 if (*buffer == NULL) { 109 output_buffer = SDL_malloc(new_buffer_length); 110 } else { 111 output_buffer = SDL_realloc(*buffer, new_buffer_length); 112 } 113 114 if (output_buffer == NULL) { 115 bytes_read = SDL_OutOfMemory(); 116 } else { 117 SDL_memcpy((Uint8*)output_buffer + pos, temp, bytes_read); 118 119 if (null_terminate == SDL_TRUE) { 120 SDL_memset((Uint8*)output_buffer + (new_buffer_length - 1), 0, 1); 121 } 122 123 *buffer = output_buffer; 124 } 125 } 126 127 return bytes_read; 128} 129 130#define MIME_LIST_SIZE 4 131 132static const char* mime_conversion_list[MIME_LIST_SIZE][2] = { 133 {"text/plain", TEXT_MIME}, 134 {"TEXT", TEXT_MIME}, 135 {"UTF8_STRING", TEXT_MIME}, 136 {"STRING", TEXT_MIME} 137}; 138 139const char* 140Wayland_convert_mime_type(const char *mime_type) 141{ 142 const char *found = mime_type; 143 144 size_t index = 0; 145 146 for (index = 0; index < MIME_LIST_SIZE; ++index) { 147 if (strcmp(mime_conversion_list[index][0], mime_type) == 0) { 148 found = mime_conversion_list[index][1]; 149 break; 150 } 151 } 152 153 return found; 154} 155 156static SDL_MimeDataList* 157mime_data_list_find(struct wl_list* list, 158 const char* mime_type) 159{ 160 SDL_MimeDataList *found = NULL; 161 162 SDL_MimeDataList *mime_list = NULL; 163 wl_list_for_each(mime_list, list, link) { 164 if (strcmp(mime_list->mime_type, mime_type) == 0) { 165 found = mime_list; 166 break; 167 } 168 } 169 return found; 170} 171 172static int 173mime_data_list_add(struct wl_list* list, 174 const char* mime_type, 175 void* buffer, size_t length) 176{ 177 int status = 0; 178 size_t mime_type_length = 0; 179 180 SDL_MimeDataList *mime_data = NULL; 181 182 mime_data = mime_data_list_find(list, mime_type); 183 184 if (mime_data == NULL) { 185 mime_data = SDL_calloc(1, sizeof(*mime_data)); 186 if (mime_data == NULL) { 187 status = SDL_OutOfMemory(); 188 } else { 189 WAYLAND_wl_list_insert(list, &(mime_data->link)); 190 191 mime_type_length = strlen(mime_type) + 1; 192 mime_data->mime_type = SDL_malloc(mime_type_length); 193 if (mime_data->mime_type == NULL) { 194 status = SDL_OutOfMemory(); 195 } else { 196 SDL_memcpy(mime_data->mime_type, mime_type, mime_type_length); 197 } 198 } 199 } 200 201 if (mime_data != NULL && buffer != NULL && length > 0) { 202 if (mime_data->data != NULL) { 203 SDL_free(mime_data->data); 204 } 205 mime_data->data = buffer; 206 mime_data->length = length; 207 } 208 209 return status; 210} 211 212static void 213mime_data_list_free(struct wl_list *list) 214{ 215 SDL_MimeDataList *mime_data = NULL; 216 SDL_MimeDataList *next = NULL; 217 218 wl_list_for_each_safe(mime_data, next, list, link) { 219 if (mime_data->data != NULL) { 220 SDL_free(mime_data->data); 221 } 222 if (mime_data->mime_type != NULL) { 223 SDL_free(mime_data->mime_type); 224 } 225 SDL_free(mime_data); 226 } 227} 228 229ssize_t 230Wayland_data_source_send(SDL_WaylandDataSource *source, 231 const char *mime_type, int fd) 232{ 233 size_t written_bytes = 0; 234 ssize_t status = 0; 235 SDL_MimeDataList *mime_data = NULL; 236 237 mime_type = Wayland_convert_mime_type(mime_type); 238 mime_data = mime_data_list_find(&source->mimes, 239 mime_type); 240 241 if (mime_data == NULL || mime_data->data == NULL) { 242 status = SDL_SetError("Invalid mime type"); 243 close(fd); 244 } else { 245 while (write_pipe(fd, mime_data->data, mime_data->length, 246 &written_bytes) > 0); 247 close(fd); 248 status = written_bytes; 249 } 250 return status; 251} 252 253int Wayland_data_source_add_data(SDL_WaylandDataSource *source, 254 const char *mime_type, 255 const void *buffer, 256 size_t length) 257{ 258 int status = 0; 259 if (length > 0) { 260 void *internal_buffer = SDL_malloc(length); 261 if (internal_buffer == NULL) { 262 status = SDL_OutOfMemory(); 263 } else { 264 SDL_memcpy(internal_buffer, buffer, length); 265 status = mime_data_list_add(&source->mimes, mime_type, 266 internal_buffer, length); 267 } 268 } 269 return status; 270} 271 272SDL_bool 273Wayland_data_source_has_mime(SDL_WaylandDataSource *source, 274 const char *mime_type) 275{ 276 SDL_bool found = SDL_FALSE; 277 278 if (source != NULL) { 279 found = mime_data_list_find(&source->mimes, mime_type) != NULL; 280 } 281 return found; 282} 283 284void* 285Wayland_data_source_get_data(SDL_WaylandDataSource *source, 286 size_t *length, const char* mime_type, 287 SDL_bool null_terminate) 288{ 289 SDL_MimeDataList *mime_data = NULL; 290 void *buffer = NULL; 291 *length = 0; 292 293 if (source == NULL) { 294 SDL_SetError("Invalid data source"); 295 } else { 296 mime_data = mime_data_list_find(&source->mimes, mime_type); 297 if (mime_data != NULL && mime_data->length > 0) { 298 buffer = SDL_malloc(mime_data->length); 299 if (buffer == NULL) { 300 *length = SDL_OutOfMemory(); 301 } else { 302 *length = mime_data->length; 303 SDL_memcpy(buffer, mime_data->data, mime_data->length); 304 } 305 } 306 } 307 308 return buffer; 309} 310 311void 312Wayland_data_source_destroy(SDL_WaylandDataSource *source) 313{ 314 if (source != NULL) { 315 wl_data_source_destroy(source->source); 316 mime_data_list_free(&source->mimes); 317 SDL_free(source); 318 } 319} 320 321void* 322Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, 323 size_t *length, const char* mime_type, 324 SDL_bool null_terminate) 325{ 326 SDL_WaylandDataDevice *data_device = NULL; 327 328 int pipefd[2]; 329 void *buffer = NULL; 330 *length = 0; 331 332 if (offer == NULL) { 333 SDL_SetError("Invalid data offer"); 334 } else if ((data_device = offer->data_device) == NULL) { 335 SDL_SetError("Data device not initialized"); 336 } else if (pipe2(pipefd, O_CLOEXEC|O_NONBLOCK) == -1) { 337 SDL_SetError("Could not read pipe"); 338 } else { 339 wl_data_offer_receive(offer->offer, mime_type, pipefd[1]); 340 341 /* TODO: Needs pump and flush? */ 342 WAYLAND_wl_display_flush(data_device->video_data->display); 343 344 close(pipefd[1]); 345 346 while (read_pipe(pipefd[0], &buffer, length, null_terminate) > 0); 347 close(pipefd[0]); 348 } 349 return buffer; 350} 351 352int 353Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer, 354 const char* mime_type) 355{ 356 return mime_data_list_add(&offer->mimes, mime_type, NULL, 0); 357} 358 359 360SDL_bool 361Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer, 362 const char *mime_type) 363{ 364 SDL_bool found = SDL_FALSE; 365 366 if (offer != NULL) { 367 found = mime_data_list_find(&offer->mimes, mime_type) != NULL; 368 } 369 return found; 370} 371 372void 373Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer) 374{ 375 if (offer != NULL) { 376 wl_data_offer_destroy(offer->offer); 377 mime_data_list_free(&offer->mimes); 378 SDL_free(offer); 379 } 380} 381 382int 383Wayland_data_device_clear_selection(SDL_WaylandDataDevice *data_device) 384{ 385 int status = 0; 386 387 if (data_device == NULL || data_device->data_device == NULL) { 388 status = SDL_SetError("Invalid Data Device"); 389 } else if (data_device->selection_source != 0) { 390 wl_data_device_set_selection(data_device->data_device, NULL, 0); 391 data_device->selection_source = NULL; 392 } 393 return status; 394} 395 396int 397Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device, 398 SDL_WaylandDataSource *source) 399{ 400 int status = 0; 401 size_t num_offers = 0; 402 size_t index = 0; 403 404 if (data_device == NULL) { 405 status = SDL_SetError("Invalid Data Device"); 406 } else if (source == NULL) { 407 status = SDL_SetError("Invalid source"); 408 } else { 409 SDL_MimeDataList *mime_data = NULL; 410 411 wl_list_for_each(mime_data, &(source->mimes), link) { 412 wl_data_source_offer(source->source, 413 mime_data->mime_type); 414 415 /* TODO - Improve system for multiple mime types to same data */ 416 for (index = 0; index < MIME_LIST_SIZE; ++index) { 417 if (strcmp(mime_conversion_list[index][1], mime_data->mime_type) == 0) { 418 wl_data_source_offer(source->source, 419 mime_conversion_list[index][0]); 420 } 421 } 422 /* */ 423 424 ++num_offers; 425 } 426 427 if (num_offers == 0) { 428 Wayland_data_device_clear_selection(data_device); 429 status = SDL_SetError("No mime data"); 430 } else { 431 /* Only set if there is a valid serial if not set it later */ 432 if (data_device->selection_serial != 0) { 433 wl_data_device_set_selection(data_device->data_device, 434 source->source, 435 data_device->selection_serial); 436 } 437 data_device->selection_source = source; 438 } 439 } 440 441 return status; 442} 443 444int 445Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device, 446 uint32_t serial) 447{ 448 int status = -1; 449 if (data_device != NULL) { 450 status = 0; 451 452 /* If there was no serial and there is a pending selection set it now. */ 453 if (data_device->selection_serial == 0 454 && data_device->selection_source != NULL) { 455 wl_data_device_set_selection(data_device->data_device, 456 data_device->selection_source->source, 457 serial); 458 } 459 460 data_device->selection_serial = serial; 461 } 462 463 return status; 464} 465 466#endif /* SDL_VIDEO_DRIVER_WAYLAND */ 467 468/* vi: set ts=4 sw=4 expandtab: */ 469[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.