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
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: */
SDL_waylandvideo.h
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
SDL_WaylandDataDevice::data_device
struct wl_data_device * data_device
Definition: SDL_waylanddatamanager.h:52
Wayland_data_offer_receive
void * Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, size_t *length, const char *mime_type, SDL_bool null_terminate)
Wayland_data_source_get_data
void * Wayland_data_source_get_data(SDL_WaylandDataSource *source, size_t *length, const char *mime_type, SDL_bool null_terminate)
source
GLsizei GLsizei GLchar * source
Definition: SDL_opengl_glext.h:677
NULL
#define NULL
Definition: begin_code.h:164
wl_data_source_offer
static void wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type)
Definition: wayland-client-protocol.h:2279
SDL_MimeDataList::link
struct wl_list link
Definition: SDL_waylanddatamanager.h:37
SDL_realloc
#define SDL_realloc
Definition: SDL_dynapi_overrides.h:376
Wayland_data_source_destroy
void Wayland_data_source_destroy(SDL_WaylandDataSource *source)
wl_data_offer_destroy
static void wl_data_offer_destroy(struct wl_data_offer *wl_data_offer)
Definition: wayland-client-protocol.h:1988
Wayland_data_device_set_selection
int Wayland_data_device_set_selection(SDL_WaylandDataDevice *device, SDL_WaylandDataSource *source)
index
GLuint index
Definition: SDL_opengl_glext.h:660
length
GLuint GLsizei GLsizei * length
Definition: SDL_opengl_glext.h:669
Wayland_data_device_clear_selection
int Wayland_data_device_clear_selection(SDL_WaylandDataDevice *device)
SDL_WaylandDataOffer::mimes
struct wl_list mimes
Definition: SDL_waylanddatamanager.h:47
SDL_MimeDataList
Definition: SDL_waylanddatamanager.h:33
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
buffer
GLuint buffer
Definition: SDL_opengl_glext.h:533
Wayland_data_source_add_data
int Wayland_data_source_add_data(SDL_WaylandDataSource *source, const char *mime_type, const void *buffer, size_t length)
SDL_IOReady
int SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS)
Definition: SDL_poll.c:38
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_MimeDataList::mime_type
char * mime_type
Definition: SDL_waylanddatamanager.h:34
SDL_MimeDataList::length
size_t length
Definition: SDL_waylanddatamanager.h:36
SDL_assert.h
SDL_min
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_waylanddatamanager.h
Wayland_data_offer_has_mime
SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer, const char *mime_type)
Wayland_data_source_send
ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source, const char *mime_type, int fd)
wl_data_device_set_selection
static void wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial)
Definition: wayland-client-protocol.h:2564
SDL_WaylandDataOffer::offer
struct wl_data_offer * offer
Definition: SDL_waylanddatamanager.h:46
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_WaylandDataSource::source
struct wl_data_source * source
Definition: SDL_waylanddatamanager.h:41
SDL_MimeDataList::data
void * data
Definition: SDL_waylanddatamanager.h:35
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_VideoData::display
struct wl_display * display
Definition: SDL_waylandvideo.h:50
wl_data_source_destroy
static void wl_data_source_destroy(struct wl_data_source *wl_data_source)
Definition: wayland-client-protocol.h:2291
uint32_t
unsigned int uint32_t
Definition: SDL_config_windows.h:63
SDL_WaylandDataSource
Definition: SDL_waylanddatamanager.h:40
SDL_WaylandDataOffer
Definition: SDL_waylanddatamanager.h:45
SDL_waylanddyn.h
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
Wayland_data_device_set_serial
int Wayland_data_device_set_serial(SDL_WaylandDataDevice *device, uint32_t serial)
SDL_stdinc.h
Wayland_data_source_has_mime
SDL_bool Wayland_data_source_has_mime(SDL_WaylandDataSource *source, const char *mime_type)
Wayland_convert_mime_type
const char * Wayland_convert_mime_type(const char *mime_type)
Wayland_data_offer_add_mime
int Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer, const char *mime_type)
Wayland_data_offer_destroy
void Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer)
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_WaylandDataDevice::selection_source
SDL_WaylandDataSource * selection_source
Definition: SDL_waylanddatamanager.h:62
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_WaylandDataDevice
Definition: SDL_waylanddatamanager.h:51
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
fd
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
SDL_WaylandDataDevice::selection_serial
uint32_t selection_serial
Definition: SDL_waylanddatamanager.h:61
wl_data_offer_receive
static void wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd)
Definition: wayland-client-protocol.h:1976
TEXT_MIME
#define TEXT_MIME
Definition: SDL_waylanddatamanager.h:30
SDL_WaylandDataOffer::data_device
void * data_device
Definition: SDL_waylanddatamanager.h:48
SDL_WaylandDataDevice::video_data
SDL_VideoData * video_data
Definition: SDL_waylanddatamanager.h:53