Fixed 2942 - Wayland: Drag and Drop / Clipboard
authorSam Lantinga <slouken@libsdl.org>
Sun, 06 Nov 2016 08:34:27 -0800
changeset 10583974f8ebcb819
parent 10582 0e1dd7514610
child 10584 14333c920cd7
Fixed 2942 - Wayland: Drag and Drop / Clipboard

x414e54

I have implemented Drag and Drop and Clipboard support for Wayland.

Drag and dropping files from nautilus to the testdropfile application seems to work and also copy and paste.
src/video/wayland/SDL_waylandclipboard.c
src/video/wayland/SDL_waylandclipboard.h
src/video/wayland/SDL_waylanddatamanager.c
src/video/wayland/SDL_waylanddatamanager.h
src/video/wayland/SDL_waylanddyn.h
src/video/wayland/SDL_waylandevents.c
src/video/wayland/SDL_waylandevents_c.h
src/video/wayland/SDL_waylandsym.h
src/video/wayland/SDL_waylandvideo.c
src/video/wayland/SDL_waylandvideo.h
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/video/wayland/SDL_waylandclipboard.c	Sun Nov 06 08:34:27 2016 -0800
     1.3 @@ -0,0 +1,123 @@
     1.4 +/*
     1.5 +  Simple DirectMedia Layer
     1.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     1.7 +
     1.8 +  This software is provided 'as-is', without any express or implied
     1.9 +  warranty.  In no event will the authors be held liable for any damages
    1.10 +  arising from the use of this software.
    1.11 +
    1.12 +  Permission is granted to anyone to use this software for any purpose,
    1.13 +  including commercial applications, and to alter it and redistribute it
    1.14 +  freely, subject to the following restrictions:
    1.15 +
    1.16 +  1. The origin of this software must not be misrepresented; you must not
    1.17 +     claim that you wrote the original software. If you use this software
    1.18 +     in a product, an acknowledgment in the product documentation would be
    1.19 +     appreciated but is not required.
    1.20 +  2. Altered source versions must be plainly marked as such, and must not be
    1.21 +     misrepresented as being the original software.
    1.22 +  3. This notice may not be removed or altered from any source distribution.
    1.23 +*/
    1.24 +#include "../../SDL_internal.h"
    1.25 +
    1.26 +#if SDL_VIDEO_DRIVER_WAYLAND
    1.27 +
    1.28 +#include "SDL_waylanddatamanager.h"
    1.29 +#include "SDL_waylandevents_c.h"
    1.30 +
    1.31 +int
    1.32 +Wayland_SetClipboardText(_THIS, const char *text)
    1.33 +{
    1.34 +    SDL_VideoData *video_data = NULL;
    1.35 +    SDL_WaylandDataDevice *data_device = NULL;
    1.36 +    
    1.37 +    int status = 0;
    1.38 + 
    1.39 +    if (_this == NULL || _this->driverdata == NULL) {
    1.40 +        status = SDL_SetError("Video driver uninitialized");
    1.41 +    } else {
    1.42 +        video_data = _this->driverdata;
    1.43 +        /* TODO: Support more than one seat */ 
    1.44 +        data_device = Wayland_get_data_device(video_data->input);
    1.45 +        if (text[0] != '\0') {
    1.46 +            SDL_WaylandDataSource* source = Wayland_data_source_create(_this);
    1.47 +            Wayland_data_source_add_data(source, TEXT_MIME, text,
    1.48 +                                         strlen(text) + 1); 
    1.49 +
    1.50 +            status = Wayland_data_device_set_selection(data_device, source);
    1.51 +            if (status != 0) {
    1.52 +                Wayland_data_source_destroy(source);
    1.53 +            }
    1.54 +        } else {
    1.55 +            status = Wayland_data_device_clear_selection(data_device);
    1.56 +        }
    1.57 +    }
    1.58 +
    1.59 +    return status;
    1.60 +}
    1.61 +
    1.62 +char *
    1.63 +Wayland_GetClipboardText(_THIS)
    1.64 +{
    1.65 +    SDL_VideoData *video_data = NULL;
    1.66 +    SDL_WaylandDataDevice *data_device = NULL;
    1.67 +
    1.68 +    char *text = NULL;
    1.69 +
    1.70 +    void *buffer = NULL;
    1.71 +    size_t length = 0;
    1.72 + 
    1.73 +    if (_this == NULL || _this->driverdata == NULL) {
    1.74 +        SDL_SetError("Video driver uninitialized");
    1.75 +    } else {
    1.76 +        video_data = _this->driverdata;
    1.77 +        /* TODO: Support more than one seat */ 
    1.78 +        data_device = Wayland_get_data_device(video_data->input);
    1.79 +        if (data_device->selection_offer != NULL) {
    1.80 +            buffer = Wayland_data_offer_receive(data_device->selection_offer,
    1.81 +                                                &length, TEXT_MIME, SDL_TRUE);
    1.82 +            if (length > 0) {
    1.83 +                text = (char*) buffer;
    1.84 +            } 
    1.85 +        } else if (data_device->selection_source != NULL) {
    1.86 +            buffer = Wayland_data_source_get_data(data_device->selection_source,
    1.87 +                                                  &length, TEXT_MIME, SDL_TRUE);
    1.88 +            if (length > 0) {
    1.89 +                text = (char*) buffer;
    1.90 +            } 
    1.91 +        }
    1.92 +    }
    1.93 +
    1.94 +    if (text == NULL) {
    1.95 +        text = SDL_strdup("");
    1.96 +    }
    1.97 +
    1.98 +    return text;
    1.99 +}
   1.100 +
   1.101 +SDL_bool
   1.102 +Wayland_HasClipboardText(_THIS)
   1.103 +{
   1.104 +    SDL_VideoData *video_data = NULL;
   1.105 +    SDL_WaylandDataDevice *data_device = NULL;
   1.106 +
   1.107 +    SDL_bool result = SDL_FALSE;    
   1.108 +    if (_this == NULL || _this->driverdata == NULL) {
   1.109 +        SDL_SetError("Video driver uninitialized");
   1.110 +    } else {
   1.111 +        video_data = _this->driverdata;
   1.112 +        data_device = Wayland_get_data_device(video_data->input);
   1.113 +        if (data_device != NULL && Wayland_data_offer_has_mime(
   1.114 +                data_device->selection_offer, TEXT_MIME)) {
   1.115 +            result = SDL_TRUE;
   1.116 +        } else if(data_device != NULL && Wayland_data_source_has_mime(
   1.117 +                data_device->selection_source, TEXT_MIME)) {
   1.118 +            result = SDL_TRUE;
   1.119 +        }
   1.120 +    }
   1.121 +    return result;
   1.122 +}
   1.123 +
   1.124 +#endif /* SDL_VIDEO_DRIVER_WAYLAND */
   1.125 +
   1.126 +/* vi: set ts=4 sw=4 expandtab: */
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/video/wayland/SDL_waylandclipboard.h	Sun Nov 06 08:34:27 2016 -0800
     2.3 @@ -0,0 +1,32 @@
     2.4 +/*
     2.5 +  Simple DirectMedia Layer
     2.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     2.7 +
     2.8 +  This software is provided 'as-is', without any express or implied
     2.9 +  warranty.  In no event will the authors be held liable for any damages
    2.10 +  arising from the use of this software.
    2.11 +
    2.12 +  Permission is granted to anyone to use this software for any purpose,
    2.13 +  including commercial applications, and to alter it and redistribute it
    2.14 +  freely, subject to the following restrictions:
    2.15 +
    2.16 +  1. The origin of this software must not be misrepresented; you must not
    2.17 +     claim that you wrote the original software. If you use this software
    2.18 +     in a product, an acknowledgment in the product documentation would be
    2.19 +     appreciated but is not required.
    2.20 +  2. Altered source versions must be plainly marked as such, and must not be
    2.21 +     misrepresented as being the original software.
    2.22 +  3. This notice may not be removed or altered from any source distribution.
    2.23 +*/
    2.24 +#include "../../SDL_internal.h"
    2.25 +
    2.26 +#ifndef _SDL_waylandclipboard_h
    2.27 +#define _SDL_waylandclipboard_h
    2.28 +
    2.29 +extern int Wayland_SetClipboardText(_THIS, const char *text);
    2.30 +extern char *Wayland_GetClipboardText(_THIS);
    2.31 +extern SDL_bool Wayland_HasClipboardText(_THIS);
    2.32 +
    2.33 +#endif /* _SDL_waylandclipboard_h */
    2.34 +
    2.35 +/* vi: set ts=4 sw=4 expandtab: */
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/video/wayland/SDL_waylanddatamanager.c	Sun Nov 06 08:34:27 2016 -0800
     3.3 @@ -0,0 +1,484 @@
     3.4 +/*
     3.5 +  Simple DirectMedia Layer
     3.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     3.7 +
     3.8 +  This software is provided 'as-is', without any express or implied
     3.9 +  warranty.  In no event will the authors be held liable for any damages
    3.10 +  arising from the use of this software.
    3.11 +
    3.12 +  Permission is granted to anyone to use this software for any purpose,
    3.13 +  including commercial applications, and to alter it and redistribute it
    3.14 +  freely, subject to the following restrictions:
    3.15 +
    3.16 +  1. The origin of this software must not be misrepresented; you must not
    3.17 +     claim that you wrote the original software. If you use this software
    3.18 +     in a product, an acknowledgment in the product documentation would be
    3.19 +     appreciated but is not required.
    3.20 +  2. Altered source versions must be plainly marked as such, and must not be
    3.21 +     misrepresented as being the original software.
    3.22 +  3. This notice may not be removed or altered from any source distribution.
    3.23 +*/
    3.24 +
    3.25 +#include "../../SDL_internal.h"
    3.26 +
    3.27 +#if SDL_VIDEO_DRIVER_WAYLAND
    3.28 +
    3.29 +#include <unistd.h>
    3.30 +#include <fcntl.h>
    3.31 +#include <limits.h>
    3.32 +#include <signal.h>
    3.33 +
    3.34 +#include "SDL_stdinc.h"
    3.35 +#include "SDL_assert.h"
    3.36 +
    3.37 +#include "SDL_waylandvideo.h"
    3.38 +#include "SDL_waylanddatamanager.h"
    3.39 +
    3.40 +#include "SDL_waylanddyn.h"
    3.41 +
    3.42 +static ssize_t
    3.43 +write_pipe(int fd, const void* buffer, size_t total_length, size_t *pos)
    3.44 +{
    3.45 +    int ready = 0;
    3.46 +    ssize_t bytes_written = 0;
    3.47 +    ssize_t length = total_length - *pos;
    3.48 +
    3.49 +    sigset_t sig_set;
    3.50 +    sigset_t old_sig_set;
    3.51 +    struct timespec zerotime = {0};
    3.52 +    fd_set set;
    3.53 +    struct timeval timeout;
    3.54 +
    3.55 +    FD_ZERO(&set);
    3.56 +    FD_SET(fd, &set);
    3.57 +
    3.58 +    timeout.tv_sec = 1;
    3.59 +    timeout.tv_usec = 0;
    3.60 +
    3.61 +    ready = select(fd + 1, NULL, &set, NULL, &timeout);
    3.62 +
    3.63 +    sigemptyset(&sig_set);
    3.64 +    sigaddset(&sig_set, SIGPIPE);  
    3.65 +
    3.66 +    pthread_sigmask(SIG_BLOCK, &sig_set, &old_sig_set); 
    3.67 +
    3.68 +    if (ready == 0) {
    3.69 +        bytes_written = SDL_SetError("Pipe timeout");
    3.70 +    } else if (ready < 0) {
    3.71 +        bytes_written = SDL_SetError("Pipe select error");
    3.72 +    } else {
    3.73 +        if (length > 0) {
    3.74 +            bytes_written = write(fd, buffer + *pos, SDL_min(length, PIPE_BUF));
    3.75 +        }
    3.76 +
    3.77 +        if (bytes_written > 0) {
    3.78 +            *pos += bytes_written;
    3.79 +        }
    3.80 +    }
    3.81 +
    3.82 +    sigtimedwait(&sig_set, 0, &zerotime);
    3.83 +    pthread_sigmask(SIG_SETMASK, &old_sig_set, NULL);
    3.84 +
    3.85 +    return bytes_written;
    3.86 +}
    3.87 +
    3.88 +static ssize_t
    3.89 +read_pipe(int fd, void** buffer, size_t* total_length, SDL_bool null_terminate)
    3.90 +{
    3.91 +    int ready = 0;
    3.92 +    void* output_buffer = NULL;
    3.93 +    char temp[PIPE_BUF];
    3.94 +    size_t new_buffer_length = 0;
    3.95 +    ssize_t bytes_read = 0;
    3.96 +    size_t pos = 0;
    3.97 +
    3.98 +    fd_set set;
    3.99 +    struct timeval timeout;
   3.100 +
   3.101 +    FD_ZERO(&set);
   3.102 +    FD_SET(fd, &set);
   3.103 +
   3.104 +    timeout.tv_sec = 1;
   3.105 +    timeout.tv_usec = 0;
   3.106 +
   3.107 +    ready = select(fd + 1, &set, NULL, NULL, &timeout);  
   3.108 +  
   3.109 +    if (ready == 0) {
   3.110 +        bytes_read = SDL_SetError("Pipe timeout");
   3.111 +    } else if (ready < 0) {
   3.112 +        bytes_read = SDL_SetError("Pipe select error");
   3.113 +    } else {
   3.114 +        bytes_read = read(fd, temp, sizeof(temp));
   3.115 +    }
   3.116 +
   3.117 +    if (bytes_read > 0) {
   3.118 +        pos = *total_length;
   3.119 +        *total_length += bytes_read;
   3.120 +
   3.121 +        if (null_terminate == SDL_TRUE) {
   3.122 +            new_buffer_length = *total_length + 1;
   3.123 +        } else {
   3.124 +            new_buffer_length = *total_length;
   3.125 +        }
   3.126 +
   3.127 +        if (*buffer == NULL) {
   3.128 +            output_buffer = SDL_malloc(new_buffer_length);
   3.129 +        } else {
   3.130 +            output_buffer = SDL_realloc(*buffer, new_buffer_length);
   3.131 +        }           
   3.132 +        
   3.133 +        if (output_buffer == NULL) {
   3.134 +            bytes_read = SDL_OutOfMemory();
   3.135 +        } else {
   3.136 +            SDL_memcpy(output_buffer + pos, temp, bytes_read);
   3.137 +
   3.138 +            if (null_terminate == SDL_TRUE) {
   3.139 +                SDL_memset(output_buffer + (new_buffer_length - 1), 0, 1);
   3.140 +            }
   3.141 +            
   3.142 +            *buffer = output_buffer;
   3.143 +        }
   3.144 +    }
   3.145 +
   3.146 +    return bytes_read;
   3.147 +}
   3.148 +
   3.149 +#define MIME_LIST_SIZE 4
   3.150 +
   3.151 +static const char* mime_conversion_list[MIME_LIST_SIZE][2] = {
   3.152 +    {"text/plain", TEXT_MIME},
   3.153 +    {"TEXT", TEXT_MIME},
   3.154 +    {"UTF8_STRING", TEXT_MIME},
   3.155 +    {"STRING", TEXT_MIME}
   3.156 +};
   3.157 +
   3.158 +const char*
   3.159 +Wayland_convert_mime_type(const char *mime_type)
   3.160 +{
   3.161 +    const char *found = mime_type;
   3.162 +
   3.163 +    size_t index = 0;
   3.164 +
   3.165 +    for (index = 0; index < MIME_LIST_SIZE; ++index) {
   3.166 +        if (strcmp(mime_conversion_list[index][0], mime_type) == 0) {
   3.167 +            found = mime_conversion_list[index][1];
   3.168 +            break;
   3.169 +        }
   3.170 +    }
   3.171 +    
   3.172 +    return found;
   3.173 +}
   3.174 +
   3.175 +static SDL_MimeDataList*
   3.176 +mime_data_list_find(struct wl_list* list, 
   3.177 +                    const char* mime_type)
   3.178 +{
   3.179 +    SDL_MimeDataList *found = NULL;
   3.180 +
   3.181 +    SDL_MimeDataList *mime_list = NULL;
   3.182 +    wl_list_for_each(mime_list, list, link) { 
   3.183 +        if (strcmp(mime_list->mime_type, mime_type) == 0) {
   3.184 +            found = mime_list;
   3.185 +            break;
   3.186 +        }
   3.187 +    }    
   3.188 +    return found;
   3.189 +}
   3.190 +
   3.191 +static int
   3.192 +mime_data_list_add(struct wl_list* list, 
   3.193 +                   const char* mime_type,
   3.194 +                   void* buffer, size_t length)
   3.195 +{
   3.196 +    int status = 0;
   3.197 +    size_t mime_type_length = 0;
   3.198 +
   3.199 +    SDL_MimeDataList *mime_data = NULL;
   3.200 +
   3.201 +    mime_data = mime_data_list_find(list, mime_type);
   3.202 +
   3.203 +    if (mime_data == NULL) {
   3.204 +        mime_data = SDL_calloc(1, sizeof(*mime_data));
   3.205 +        if (mime_data == NULL) {
   3.206 +            status = SDL_OutOfMemory();
   3.207 +        } else {
   3.208 +            WAYLAND_wl_list_insert(list, &(mime_data->link));
   3.209 +
   3.210 +            mime_type_length = strlen(mime_type) + 1;
   3.211 +            mime_data->mime_type = SDL_malloc(mime_type_length);
   3.212 +            if (mime_data->mime_type == NULL) {
   3.213 +                status = SDL_OutOfMemory();
   3.214 +            } else {
   3.215 +                SDL_memcpy(mime_data->mime_type, mime_type, mime_type_length);
   3.216 +            }
   3.217 +        }
   3.218 +    }
   3.219 +    
   3.220 +    if (mime_data != NULL && buffer != NULL && length > 0) {
   3.221 +        if (mime_data->data != NULL) {
   3.222 +            SDL_free(mime_data->data);
   3.223 +        }
   3.224 +        mime_data->data = buffer;
   3.225 +        mime_data->length = length;
   3.226 +    }
   3.227 +
   3.228 +    return status;
   3.229 +}
   3.230 +
   3.231 +static void
   3.232 +mime_data_list_free(struct wl_list *list)
   3.233 +{
   3.234 +    SDL_MimeDataList *mime_data = NULL; 
   3.235 +    SDL_MimeDataList *next = NULL;
   3.236 +
   3.237 +    wl_list_for_each_safe(mime_data, next, list, link) {
   3.238 +        if (mime_data->data != NULL) {
   3.239 +            SDL_free(mime_data->data);
   3.240 +        }        
   3.241 +        if (mime_data->mime_type != NULL) {
   3.242 +            SDL_free(mime_data->mime_type);
   3.243 +        }
   3.244 +        SDL_free(mime_data);       
   3.245 +    } 
   3.246 +}
   3.247 +
   3.248 +ssize_t 
   3.249 +Wayland_data_source_send(SDL_WaylandDataSource *source,  
   3.250 +                         const char *mime_type, int fd)
   3.251 +{
   3.252 +    size_t written_bytes = 0;
   3.253 +    ssize_t status = 0;
   3.254 +    SDL_MimeDataList *mime_data = NULL;
   3.255 + 
   3.256 +    mime_type = Wayland_convert_mime_type(mime_type);
   3.257 +    mime_data = mime_data_list_find(&source->mimes,
   3.258 +                                                      mime_type);
   3.259 +
   3.260 +    if (mime_data == NULL || mime_data->data == NULL) {
   3.261 +        status = SDL_SetError("Invalid mime type");
   3.262 +        close(fd);
   3.263 +    } else {
   3.264 +        while (write_pipe(fd, mime_data->data, mime_data->length,
   3.265 +                          &written_bytes) > 0);
   3.266 +        close(fd);
   3.267 +        status = written_bytes;
   3.268 +    }
   3.269 +    return status;
   3.270 +}
   3.271 +
   3.272 +int Wayland_data_source_add_data(SDL_WaylandDataSource *source,
   3.273 +                                 const char *mime_type,
   3.274 +                                 const void *buffer,
   3.275 +                                 size_t length) 
   3.276 +{
   3.277 +    int status = 0;
   3.278 +    if (length > 0) {
   3.279 +        void *internal_buffer = SDL_malloc(length);
   3.280 +        if (internal_buffer == NULL) {
   3.281 +            status = SDL_OutOfMemory();
   3.282 +        } else {
   3.283 +            SDL_memcpy(internal_buffer, buffer, length);
   3.284 +            status = mime_data_list_add(&source->mimes, mime_type, 
   3.285 +                                        internal_buffer, length);
   3.286 +        }
   3.287 +    }
   3.288 +    return status;
   3.289 +}
   3.290 +
   3.291 +SDL_bool 
   3.292 +Wayland_data_source_has_mime(SDL_WaylandDataSource *source,
   3.293 +                             const char *mime_type)
   3.294 +{
   3.295 +    SDL_bool found = SDL_FALSE;
   3.296 +
   3.297 +    if (source != NULL) {
   3.298 +        found = mime_data_list_find(&source->mimes, mime_type) != NULL;
   3.299 +    }
   3.300 +    return found;
   3.301 +}
   3.302 +
   3.303 +void* 
   3.304 +Wayland_data_source_get_data(SDL_WaylandDataSource *source,
   3.305 +                             size_t *length, const char* mime_type,
   3.306 +                             SDL_bool null_terminate)
   3.307 +{
   3.308 +    SDL_MimeDataList *mime_data = NULL;
   3.309 +    void *buffer = NULL;
   3.310 +    *length = 0;
   3.311 +
   3.312 +    if (source == NULL) {
   3.313 +        SDL_SetError("Invalid data source");
   3.314 +    } else {
   3.315 +        mime_data = mime_data_list_find(&source->mimes, mime_type);
   3.316 +        if (mime_data != NULL && mime_data->length > 0) {
   3.317 +            buffer = SDL_malloc(mime_data->length);
   3.318 +            if (buffer == NULL) {
   3.319 +                *length = SDL_OutOfMemory();
   3.320 +            } else {
   3.321 +                *length = mime_data->length;
   3.322 +                SDL_memcpy(buffer, mime_data->data, mime_data->length);
   3.323 +            }
   3.324 +       }
   3.325 +    }
   3.326 +
   3.327 +    return buffer;
   3.328 +}
   3.329 +
   3.330 +void
   3.331 +Wayland_data_source_destroy(SDL_WaylandDataSource *source)
   3.332 +{
   3.333 +    if (source != NULL) {
   3.334 +        wl_data_source_destroy(source->source);
   3.335 +        mime_data_list_free(&source->mimes);
   3.336 +        SDL_free(source);
   3.337 +    }
   3.338 +}
   3.339 +
   3.340 +void* 
   3.341 +Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
   3.342 +                           size_t *length, const char* mime_type,
   3.343 +                           SDL_bool null_terminate)
   3.344 +{
   3.345 +    SDL_WaylandDataDevice *data_device = NULL;
   3.346 + 
   3.347 +    int pipefd[2];
   3.348 +    void *buffer = NULL;
   3.349 +    *length = 0;
   3.350 +
   3.351 +    if (offer == NULL) {
   3.352 +        SDL_SetError("Invalid data offer");
   3.353 +    } else if (pipe2(pipefd, O_CLOEXEC|O_NONBLOCK) == -1) {
   3.354 +        SDL_SetError("Could not read pipe");
   3.355 +    } else if ((data_device = offer->data_device) == NULL) {
   3.356 +        SDL_SetError("Data device not initialized");
   3.357 +    } else {
   3.358 +        wl_data_offer_receive(offer->offer, mime_type, pipefd[1]);
   3.359 +
   3.360 +        /* TODO: Needs pump and flush? */
   3.361 +        WAYLAND_wl_display_flush(data_device->video_data->display);
   3.362 +
   3.363 +        close(pipefd[1]);
   3.364 +        
   3.365 +        while (read_pipe(pipefd[0], &buffer, length, null_terminate) > 0);
   3.366 +        close(pipefd[0]);
   3.367 +    }
   3.368 +    return buffer;
   3.369 +}
   3.370 +
   3.371 +int 
   3.372 +Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
   3.373 +                            const char* mime_type)
   3.374 +{
   3.375 +    return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
   3.376 +}
   3.377 +
   3.378 +
   3.379 +SDL_bool 
   3.380 +Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
   3.381 +                            const char *mime_type)
   3.382 +{
   3.383 +    SDL_bool found = SDL_FALSE;
   3.384 +
   3.385 +    if (offer != NULL) {
   3.386 +        found = mime_data_list_find(&offer->mimes, mime_type) != NULL;
   3.387 +    }
   3.388 +    return found;
   3.389 +}
   3.390 +
   3.391 +void
   3.392 +Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer)
   3.393 +{
   3.394 +    if (offer != NULL) {
   3.395 +        wl_data_offer_destroy(offer->offer);
   3.396 +        mime_data_list_free(&offer->mimes);
   3.397 +        SDL_free(offer);
   3.398 +    }
   3.399 +}
   3.400 +
   3.401 +int
   3.402 +Wayland_data_device_clear_selection(SDL_WaylandDataDevice *data_device)
   3.403 +{
   3.404 +    int status = 0;
   3.405 +
   3.406 +    if (data_device == NULL || data_device->data_device == NULL) {
   3.407 +        status = SDL_SetError("Invalid Data Device");
   3.408 +    } else if (data_device->selection_source != 0) {
   3.409 +        wl_data_device_set_selection(data_device->data_device, NULL, 0);
   3.410 +        data_device->selection_source = NULL;
   3.411 +    }
   3.412 +    return status;
   3.413 +}
   3.414 +
   3.415 +int
   3.416 +Wayland_data_device_set_selection(SDL_WaylandDataDevice *data_device,
   3.417 +                                  SDL_WaylandDataSource *source)
   3.418 +{
   3.419 +    int status = 0;
   3.420 +    size_t num_offers = 0;
   3.421 +    size_t index = 0;
   3.422 +
   3.423 +    if (data_device == NULL) {
   3.424 +        status = SDL_SetError("Invalid Data Device");
   3.425 +    } else if (source == NULL) {
   3.426 +        status = SDL_SetError("Invalid source");
   3.427 +    } else {
   3.428 +        SDL_MimeDataList *mime_data = NULL;
   3.429 +
   3.430 +        wl_list_for_each(mime_data, &(source->mimes), link) {
   3.431 +            wl_data_source_offer(source->source,
   3.432 +                                 mime_data->mime_type); 
   3.433 +
   3.434 +            /* TODO - Improve system for multiple mime types to same data */
   3.435 +            for (index = 0; index < MIME_LIST_SIZE; ++index) {
   3.436 +                if (strcmp(mime_conversion_list[index][1], mime_data->mime_type) == 0) {
   3.437 +                    wl_data_source_offer(source->source,
   3.438 +                                         mime_conversion_list[index][0]);
   3.439 +               }
   3.440 +            }
   3.441 +            /* */
   3.442 + 
   3.443 +            ++num_offers;
   3.444 +        } 
   3.445 +
   3.446 +        if (num_offers == 0) {
   3.447 +            Wayland_data_device_clear_selection(data_device);
   3.448 +            status = SDL_SetError("No mime data");
   3.449 +        } else {
   3.450 +            /* Only set if there is a valid serial if not set it later */
   3.451 +            if (data_device->selection_serial != 0) {
   3.452 +                wl_data_device_set_selection(data_device->data_device,
   3.453 +                                             source->source,
   3.454 +                                             data_device->selection_serial); 
   3.455 +            }
   3.456 +            data_device->selection_source = source;
   3.457 +        }
   3.458 +    }
   3.459 +
   3.460 +    return status;
   3.461 +}
   3.462 +
   3.463 +int
   3.464 +Wayland_data_device_set_serial(SDL_WaylandDataDevice *data_device,
   3.465 +                               uint32_t serial)
   3.466 +{
   3.467 +    int status = -1;
   3.468 +    if (data_device != NULL) {
   3.469 +        status = 0;
   3.470 +
   3.471 +        /* If there was no serial and there is a pending selection set it now. */
   3.472 +        if (data_device->selection_serial == 0
   3.473 +            && data_device->selection_source != NULL) {
   3.474 +            wl_data_device_set_selection(data_device->data_device,
   3.475 +                                         data_device->selection_source->source,
   3.476 +                                         serial); 
   3.477 +        }
   3.478 +
   3.479 +        data_device->selection_serial = serial;
   3.480 +    }
   3.481 +
   3.482 +    return status; 
   3.483 +}
   3.484 +
   3.485 +#endif /* SDL_VIDEO_DRIVER_WAYLAND */
   3.486 +
   3.487 +/* vi: set ts=4 sw=4 expandtab: */
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/video/wayland/SDL_waylanddatamanager.h	Sun Nov 06 08:34:27 2016 -0800
     4.3 @@ -0,0 +1,105 @@
     4.4 +/*
     4.5 +  Simple DirectMedia Layer
     4.6 +  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     4.7 +
     4.8 +  This software is provided 'as-is', without any express or implied
     4.9 +  warranty.  In no event will the authors be held liable for any damages
    4.10 +  arising from the use of this software.
    4.11 +
    4.12 +  Permission is granted to anyone to use this software for any purpose,
    4.13 +  including commercial applications, and to alter it and redistribute it
    4.14 +  freely, subject to the following restrictions:
    4.15 +
    4.16 +  1. The origin of this software must not be misrepresented; you must not
    4.17 +     claim that you wrote the original software. If you use this software
    4.18 +     in a product, an acknowledgment in the product documentation would be
    4.19 +     appreciated but is not required.
    4.20 +  2. Altered source versions must be plainly marked as such, and must not be
    4.21 +     misrepresented as being the original software.
    4.22 +  3. This notice may not be removed or altered from any source distribution.
    4.23 +*/
    4.24 +
    4.25 +#include "../../SDL_internal.h"
    4.26 +
    4.27 +#ifndef _SDL_waylanddatamanager_h
    4.28 +#define _SDL_waylanddatamanager_h
    4.29 +
    4.30 +#include "SDL_waylandvideo.h"
    4.31 +#include "SDL_waylandwindow.h"
    4.32 +
    4.33 +#define TEXT_MIME "text/plain;charset=utf-8"
    4.34 +#define FILE_MIME "text/uri-list"
    4.35 +
    4.36 +typedef struct {
    4.37 +    char *mime_type;
    4.38 +    void *data;
    4.39 +    size_t length;
    4.40 +    struct wl_list link;
    4.41 +} SDL_MimeDataList;
    4.42 +
    4.43 +typedef struct {
    4.44 +    struct wl_data_source *source;
    4.45 +    struct wl_list mimes;
    4.46 +} SDL_WaylandDataSource;
    4.47 +
    4.48 +typedef struct {
    4.49 +    struct wl_data_offer *offer;
    4.50 +    struct wl_list mimes;
    4.51 +    void *data_device;
    4.52 +} SDL_WaylandDataOffer;
    4.53 +
    4.54 +typedef struct {
    4.55 +    struct wl_data_device *data_device;
    4.56 +    SDL_VideoData *video_data;
    4.57 +
    4.58 +    /* Drag and Drop */
    4.59 +    uint32_t drag_serial;
    4.60 +    SDL_WaylandDataOffer *drag_offer;
    4.61 +    SDL_WaylandDataOffer *selection_offer;
    4.62 +
    4.63 +    /* Clipboard */
    4.64 +    uint32_t selection_serial;
    4.65 +    SDL_WaylandDataSource *selection_source;
    4.66 +} SDL_WaylandDataDevice;
    4.67 +
    4.68 +extern const char* Wayland_convert_mime_type(const char *mime_type);
    4.69 +
    4.70 +/* Wayland Data Source - (Sending) */
    4.71 +extern SDL_WaylandDataSource* Wayland_data_source_create(_THIS);
    4.72 +extern ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source, 
    4.73 +                                        const char *mime_type, int fd);
    4.74 +extern int Wayland_data_source_add_data(SDL_WaylandDataSource *source,
    4.75 +                                        const char *mime_type, 
    4.76 +                                        const void *buffer, 
    4.77 +                                        size_t length);
    4.78 +extern SDL_bool Wayland_data_source_has_mime(SDL_WaylandDataSource *source,
    4.79 +                                             const char *mime_type);
    4.80 +extern void* Wayland_data_source_get_data(SDL_WaylandDataSource *source,
    4.81 +                                          size_t *length,
    4.82 +                                          const char *mime_type,
    4.83 +                                          SDL_bool null_terminate);
    4.84 +extern void Wayland_data_source_destroy(SDL_WaylandDataSource *source);
    4.85 +
    4.86 +/* Wayland Data Offer - (Receiving) */
    4.87 +extern void* Wayland_data_offer_receive(SDL_WaylandDataOffer *offer,
    4.88 +                                        size_t *length,
    4.89 +                                        const char *mime_type,
    4.90 +                                        SDL_bool null_terminate);
    4.91 +extern SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer,
    4.92 +                                            const char *mime_type);
    4.93 +extern int Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer,
    4.94 +                                       const char *mime_type);
    4.95 +extern void Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer);
    4.96 +
    4.97 +/* Clipboard */
    4.98 +extern int Wayland_data_device_clear_selection(SDL_WaylandDataDevice *device);
    4.99 +extern int Wayland_data_device_set_selection(SDL_WaylandDataDevice *device,
   4.100 +                                             SDL_WaylandDataSource *source);
   4.101 +extern int Wayland_data_device_set_serial(SDL_WaylandDataDevice *device,
   4.102 +                                          uint32_t serial);
   4.103 +#endif /* _SDL_waylanddatamanager_h */
   4.104 +
   4.105 +/* vi: set ts=4 sw=4 expandtab: */
   4.106 +
   4.107 +
   4.108 +
     5.1 --- a/src/video/wayland/SDL_waylanddyn.h	Sat Nov 05 21:23:17 2016 +0100
     5.2 +++ b/src/video/wayland/SDL_waylanddyn.h	Sun Nov 06 08:34:27 2016 -0800
     5.3 @@ -91,6 +91,10 @@
     5.4  #define wl_output_interface (*WAYLAND_wl_output_interface)
     5.5  #define wl_shell_interface (*WAYLAND_wl_shell_interface)
     5.6  #define wl_shm_interface (*WAYLAND_wl_shm_interface)
     5.7 +#define wl_data_device_interface (*WAYLAND_wl_data_device_interface)
     5.8 +#define wl_data_offer_interface (*WAYLAND_wl_data_offer_interface)
     5.9 +#define wl_data_source_interface (*WAYLAND_wl_data_source_interface)
    5.10 +#define wl_data_device_manager_interface (*WAYLAND_wl_data_device_manager_interface)
    5.11  
    5.12  #endif /* SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC */
    5.13  
     6.1 --- a/src/video/wayland/SDL_waylandevents.c	Sat Nov 05 21:23:17 2016 +0100
     6.2 +++ b/src/video/wayland/SDL_waylandevents.c	Sun Nov 06 08:34:27 2016 -0800
     6.3 @@ -52,6 +52,7 @@
     6.4      struct wl_seat *seat;
     6.5      struct wl_pointer *pointer;
     6.6      struct wl_keyboard *keyboard;
     6.7 +    SDL_WaylandDataDevice *data_device;
     6.8      struct zwp_relative_pointer_v1 *relative_pointer;
     6.9      SDL_WindowData *pointer_focus;
    6.10      SDL_WindowData *keyboard_focus;
    6.11 @@ -208,6 +209,8 @@
    6.12              default:
    6.13                  return;
    6.14          }
    6.15 +            
    6.16 +        Wayland_data_device_set_serial(input->data_device, serial); 
    6.17  
    6.18          SDL_SendMouseButton(window->sdlwindow, 0,
    6.19                              state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
    6.20 @@ -373,6 +376,9 @@
    6.21  
    6.22          if (size > 0) {
    6.23              text[size] = 0;
    6.24 +
    6.25 +            Wayland_data_device_set_serial(input->data_device, serial);
    6.26 +
    6.27              SDL_SendKeyboardText(text);
    6.28          }
    6.29      }
    6.30 @@ -430,10 +436,245 @@
    6.31      seat_handle_capabilities,
    6.32  };
    6.33  
    6.34 +static void
    6.35 +data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
    6.36 +                          const char *mime_type)
    6.37 +{
    6.38 +}
    6.39 +
    6.40 +static void
    6.41 +data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
    6.42 +                        const char *mime_type, int32_t fd)
    6.43 +{
    6.44 +    Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
    6.45 +}
    6.46 +                       
    6.47 +static void
    6.48 +data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
    6.49 +{
    6.50 +    Wayland_data_source_destroy(data);
    6.51 +}
    6.52 +                       
    6.53 +static void
    6.54 +data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
    6.55 +{
    6.56 +}
    6.57 +
    6.58 +static void
    6.59 +data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
    6.60 +{
    6.61 +}
    6.62 +
    6.63 +static void
    6.64 +data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
    6.65 +                          uint32_t dnd_action)
    6.66 +{
    6.67 +}
    6.68 +
    6.69 +static const struct wl_data_source_listener data_source_listener = {
    6.70 +    data_source_handle_target,
    6.71 +    data_source_handle_send,
    6.72 +    data_source_handle_cancelled,
    6.73 +    data_source_handle_dnd_drop_performed, // Version 3
    6.74 +    data_source_handle_dnd_finished,       // Version 3
    6.75 +    data_source_handle_action,             // Version 3
    6.76 +};
    6.77 +
    6.78 +SDL_WaylandDataSource*
    6.79 +Wayland_data_source_create(_THIS)
    6.80 +{
    6.81 +    SDL_WaylandDataSource *data_source = NULL;
    6.82 +    SDL_VideoData *driver_data = NULL;
    6.83 +    struct wl_data_source *id = NULL;
    6.84 +
    6.85 +    if (_this == NULL || _this->driverdata == NULL) {
    6.86 +        SDL_SetError("Video driver uninitialized");
    6.87 +    } else {
    6.88 +        driver_data = _this->driverdata;
    6.89 +
    6.90 +        if (driver_data->data_device_manager != NULL) {
    6.91 +            id = wl_data_device_manager_create_data_source(
    6.92 +                     driver_data->data_device_manager);
    6.93 +        }
    6.94 +
    6.95 +        if (id == NULL) { 
    6.96 +            SDL_SetError("Wayland unable to create data source");
    6.97 +        } else {
    6.98 +            data_source = SDL_calloc(1, sizeof *data_source);
    6.99 +            if (data_source == NULL) {
   6.100 +                SDL_OutOfMemory();
   6.101 +                wl_data_source_destroy(id);
   6.102 +            } else {
   6.103 +                WAYLAND_wl_list_init(&(data_source->mimes));
   6.104 +                data_source->source = id;
   6.105 +                wl_data_source_set_user_data(id, data_source);
   6.106 +                wl_data_source_add_listener(id, &data_source_listener,
   6.107 +                                            data_source);
   6.108 +            }
   6.109 +        }
   6.110 +    }
   6.111 +    return data_source;
   6.112 +}
   6.113 +
   6.114 +static void
   6.115 +data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
   6.116 +                        const char *mime_type)
   6.117 +{
   6.118 +    SDL_WaylandDataOffer *offer = data;
   6.119 +    Wayland_data_offer_add_mime(offer, mime_type);
   6.120 +}
   6.121 +
   6.122 +static void
   6.123 +data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
   6.124 +                                 uint32_t source_actions)
   6.125 +{
   6.126 +}
   6.127 +
   6.128 +static void
   6.129 +data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
   6.130 +                          uint32_t dnd_action)
   6.131 +{
   6.132 +}
   6.133 +
   6.134 +static const struct wl_data_offer_listener data_offer_listener = {
   6.135 +    data_offer_handle_offer,
   6.136 +    data_offer_handle_source_actions, // Version 3
   6.137 +    data_offer_handle_actions,        // Version 3
   6.138 +};
   6.139 +
   6.140 +static void
   6.141 +data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
   6.142 +			                  struct wl_data_offer *id)
   6.143 +{
   6.144 +    SDL_WaylandDataOffer *data_offer = NULL;
   6.145 +
   6.146 +    data_offer = SDL_calloc(1, sizeof *data_offer);
   6.147 +    if (data_offer == NULL) {
   6.148 +        SDL_OutOfMemory();
   6.149 +    } else {
   6.150 +        data_offer->offer = id;
   6.151 +        data_offer->data_device = data;
   6.152 +        WAYLAND_wl_list_init(&(data_offer->mimes));
   6.153 +        wl_data_offer_set_user_data(id, data_offer);
   6.154 +        wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
   6.155 +    }
   6.156 +}
   6.157 +
   6.158 +static void
   6.159 +data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
   6.160 +		                 uint32_t serial, struct wl_surface *surface,
   6.161 +                         wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
   6.162 +{
   6.163 +    SDL_WaylandDataDevice *data_device = data;
   6.164 +    SDL_bool has_mime = SDL_FALSE;
   6.165 +    uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; 
   6.166 +        
   6.167 +    data_device->drag_serial = serial;
   6.168 +
   6.169 +    if (id != NULL) {
   6.170 +        data_device->drag_offer = wl_data_offer_get_user_data(id);
   6.171 +
   6.172 +        /* TODO: SDL Support more mime types */
   6.173 +        has_mime = Wayland_data_offer_has_mime(
   6.174 +            data_device->drag_offer, FILE_MIME);
   6.175 +
   6.176 +        /* If drag_mime is NULL this will decline the offer */
   6.177 +        wl_data_offer_accept(id, serial,
   6.178 +                             (has_mime == SDL_TRUE) ? FILE_MIME : NULL);
   6.179 +
   6.180 +        /* SDL only supports "copy" style drag and drop */
   6.181 +        if (has_mime == SDL_TRUE) {
   6.182 +            dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
   6.183 +        }
   6.184 +        wl_data_offer_set_actions(data_device->drag_offer->offer,
   6.185 +                                  dnd_action, dnd_action);
   6.186 +    }
   6.187 +}
   6.188 +
   6.189 +static void
   6.190 +data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
   6.191 +{
   6.192 +    SDL_WaylandDataDevice *data_device = data;
   6.193 +    SDL_WaylandDataOffer *offer = NULL;
   6.194 +
   6.195 +    if (data_device->selection_offer != NULL) {
   6.196 +        data_device->selection_offer = NULL;
   6.197 +        Wayland_data_offer_destroy(offer);
   6.198 +    }
   6.199 +}
   6.200 +
   6.201 +static void
   6.202 +data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
   6.203 +		                  uint32_t time, wl_fixed_t x, wl_fixed_t y)
   6.204 +{
   6.205 +}
   6.206 +
   6.207 +static void
   6.208 +data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
   6.209 +{
   6.210 +    SDL_WaylandDataDevice *data_device = data;
   6.211 +    void *buffer = NULL;
   6.212 +    size_t length = 0;
   6.213 +
   6.214 +    const char *current_uri = NULL;
   6.215 +    const char *last_char = NULL;
   6.216 +    char *current_char = NULL;
   6.217 +    
   6.218 +    if (data_device->drag_offer != NULL) {
   6.219 +        /* TODO: SDL Support more mime types */
   6.220 +        buffer = Wayland_data_offer_receive(data_device->drag_offer,
   6.221 +                                            &length, FILE_MIME, SDL_FALSE);
   6.222 +
   6.223 +        /* uri-list */
   6.224 +        current_uri = (const char *)buffer;
   6.225 +        last_char = (const char *)buffer + length;
   6.226 +        for (current_char = buffer; current_char < last_char; ++current_char) {
   6.227 +            if (*current_char == '\n' || *current_char == 0) {
   6.228 +                if (*current_uri != 0 && *current_uri != '#') {
   6.229 +                    *current_char = 0;
   6.230 +                    SDL_SendDropFile(NULL, current_uri);
   6.231 +                }
   6.232 +                current_uri = (const char *)current_char + 1;
   6.233 +            }
   6.234 +        }
   6.235 +
   6.236 +        SDL_free(buffer);
   6.237 +    }
   6.238 +}
   6.239 +
   6.240 +static void
   6.241 +data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
   6.242 +			                 struct wl_data_offer *id)
   6.243 +{    
   6.244 +    SDL_WaylandDataDevice *data_device = data;
   6.245 +    SDL_WaylandDataOffer *offer = NULL;
   6.246 +
   6.247 +    if (id != NULL) {
   6.248 +        offer = wl_data_offer_get_user_data(id);
   6.249 +    }
   6.250 +
   6.251 +    if (data_device->selection_offer != offer) {
   6.252 +        Wayland_data_offer_destroy(data_device->selection_offer);
   6.253 +        data_device->selection_offer = offer;
   6.254 +    }
   6.255 +
   6.256 +    SDL_SendClipboardUpdate();
   6.257 +}
   6.258 +
   6.259 +static const struct wl_data_device_listener data_device_listener = {
   6.260 +    data_device_handle_data_offer,
   6.261 +    data_device_handle_enter,
   6.262 +    data_device_handle_leave,
   6.263 +    data_device_handle_motion,
   6.264 +    data_device_handle_drop,
   6.265 +    data_device_handle_selection
   6.266 +};
   6.267 +
   6.268  void
   6.269  Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
   6.270  {
   6.271      struct SDL_WaylandInput *input;
   6.272 +    SDL_WaylandDataDevice *data_device = NULL;
   6.273  
   6.274      input = SDL_calloc(1, sizeof *input);
   6.275      if (input == NULL)
   6.276 @@ -444,6 +685,27 @@
   6.277      input->sx_w = wl_fixed_from_int(0);
   6.278      input->sy_w = wl_fixed_from_int(0);
   6.279      d->input = input;
   6.280 +    
   6.281 +    if (d->data_device_manager != NULL) {
   6.282 +        data_device = SDL_calloc(1, sizeof *data_device);
   6.283 +        if (data_device == NULL) {
   6.284 +            return;
   6.285 +        }
   6.286 +
   6.287 +        data_device->data_device = wl_data_device_manager_get_data_device(
   6.288 +            d->data_device_manager, input->seat
   6.289 +        );
   6.290 +        data_device->video_data = d;
   6.291 +
   6.292 +        if (data_device->data_device == NULL) {
   6.293 +            SDL_free(data_device);
   6.294 +        } else {
   6.295 +            wl_data_device_set_user_data(data_device->data_device, data_device);
   6.296 +            wl_data_device_add_listener(data_device->data_device,
   6.297 +                                        &data_device_listener, data_device);
   6.298 +            input->data_device = data_device;
   6.299 +        }
   6.300 +    }
   6.301  
   6.302      wl_seat_add_listener(input->seat, &seat_listener, input);
   6.303      wl_seat_set_user_data(input->seat, input);
   6.304 @@ -458,6 +720,20 @@
   6.305      if (!input)
   6.306          return;
   6.307  
   6.308 +    if (input->data_device != NULL) {
   6.309 +        Wayland_data_device_clear_selection(input->data_device);
   6.310 +        if (input->data_device->selection_offer != NULL) {
   6.311 +            Wayland_data_offer_destroy(input->data_device->selection_offer);
   6.312 +        }
   6.313 +        if (input->data_device->drag_offer != NULL) {
   6.314 +            Wayland_data_offer_destroy(input->data_device->drag_offer);
   6.315 +        }
   6.316 +        if (input->data_device->data_device != NULL) {
   6.317 +            wl_data_device_release(input->data_device->data_device);
   6.318 +        }
   6.319 +        SDL_free(input->data_device);
   6.320 +    }
   6.321 +
   6.322      if (input->keyboard)
   6.323          wl_keyboard_destroy(input->keyboard);
   6.324  
   6.325 @@ -477,6 +753,15 @@
   6.326      d->input = NULL;
   6.327  }
   6.328  
   6.329 +SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input)
   6.330 +{
   6.331 +    if (input == NULL) {
   6.332 +        return NULL;
   6.333 +    }
   6.334 +
   6.335 +    return input->data_device;
   6.336 +}
   6.337 +
   6.338  void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
   6.339  {
   6.340      d->relative_pointer_manager =
     7.1 --- a/src/video/wayland/SDL_waylandevents_c.h	Sat Nov 05 21:23:17 2016 +0100
     7.2 +++ b/src/video/wayland/SDL_waylandevents_c.h	Sun Nov 06 08:34:27 2016 -0800
     7.3 @@ -26,12 +26,17 @@
     7.4  
     7.5  #include "SDL_waylandvideo.h"
     7.6  #include "SDL_waylandwindow.h"
     7.7 +#include "SDL_waylanddatamanager.h"
     7.8 +
     7.9 +struct SDL_WaylandInput;
    7.10  
    7.11  extern void Wayland_PumpEvents(_THIS);
    7.12  
    7.13  extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id);
    7.14  extern void Wayland_display_destroy_input(SDL_VideoData *d);
    7.15  
    7.16 +extern SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input);
    7.17 +
    7.18  extern void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id);
    7.19  extern void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d);
    7.20  
     8.1 --- a/src/video/wayland/SDL_waylandsym.h	Sat Nov 05 21:23:17 2016 +0100
     8.2 +++ b/src/video/wayland/SDL_waylandsym.h	Sun Nov 06 08:34:27 2016 -0800
     8.3 @@ -83,6 +83,10 @@
     8.4  SDL_WAYLAND_INTERFACE(wl_output_interface)
     8.5  SDL_WAYLAND_INTERFACE(wl_shell_interface)
     8.6  SDL_WAYLAND_INTERFACE(wl_shm_interface)
     8.7 +SDL_WAYLAND_INTERFACE(wl_data_device_interface)
     8.8 +SDL_WAYLAND_INTERFACE(wl_data_source_interface)
     8.9 +SDL_WAYLAND_INTERFACE(wl_data_offer_interface)
    8.10 +SDL_WAYLAND_INTERFACE(wl_data_device_manager_interface)
    8.11  
    8.12  SDL_WAYLAND_MODULE(WAYLAND_EGL)
    8.13  SDL_WAYLAND_SYM(struct wl_egl_window *, wl_egl_window_create, (struct wl_surface *, int, int))
     9.1 --- a/src/video/wayland/SDL_waylandvideo.c	Sat Nov 05 21:23:17 2016 +0100
     9.2 +++ b/src/video/wayland/SDL_waylandvideo.c	Sun Nov 06 08:34:27 2016 -0800
     9.3 @@ -34,6 +34,7 @@
     9.4  #include "SDL_waylandopengles.h"
     9.5  #include "SDL_waylandmouse.h"
     9.6  #include "SDL_waylandtouch.h"
     9.7 +#include "SDL_waylandclipboard.h"
     9.8  
     9.9  #include <sys/types.h>
    9.10  #include <unistd.h>
    9.11 @@ -176,6 +177,10 @@
    9.12      device->DestroyWindow = Wayland_DestroyWindow;
    9.13      device->SetWindowHitTest = Wayland_SetWindowHitTest;
    9.14  
    9.15 +    device->SetClipboardText = Wayland_SetClipboardText;
    9.16 +    device->GetClipboardText = Wayland_GetClipboardText;
    9.17 +    device->HasClipboardText = Wayland_HasClipboardText;
    9.18 +
    9.19      device->free = Wayland_DeleteDevice;
    9.20  
    9.21      return device;
    9.22 @@ -312,6 +317,8 @@
    9.23          Wayland_display_add_relative_pointer_manager(d, id);
    9.24      } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
    9.25          Wayland_display_add_pointer_constraints(d, id);
    9.26 +    } else if (strcmp(interface, "wl_data_device_manager") == 0) {
    9.27 +        d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, 3);
    9.28  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
    9.29      } else if (strcmp(interface, "qt_touch_extension") == 0) {
    9.30          Wayland_touch_create(d, id);
    10.1 --- a/src/video/wayland/SDL_waylandvideo.h	Sat Nov 05 21:23:17 2016 +0100
    10.2 +++ b/src/video/wayland/SDL_waylandvideo.h	Sun Nov 06 08:34:27 2016 -0800
    10.3 @@ -46,6 +46,7 @@
    10.4      struct wl_shell *shell;
    10.5      struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
    10.6      struct zwp_pointer_constraints_v1 *pointer_constraints;
    10.7 +    struct wl_data_device_manager *data_device_manager;
    10.8  
    10.9      EGLDisplay edpy;
   10.10      EGLContext context;