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