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