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