sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_waylanddatamanager.c (13372B)


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