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