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"
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 #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 
87 static ssize_t
88 read_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 
141 static 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 
148 const char*
149 Wayland_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 
165 static SDL_MimeDataList*
166 mime_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 
181 static int
182 mime_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 
221 static void
222 mime_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 
238 ssize_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 
281 SDL_bool
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 
293 void*
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) {
309  *length = SDL_OutOfMemory();
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 
320 void
322 {
323  if (source != NULL) {
325  mime_data_list_free(&source->mimes);
326  SDL_free(source);
327  }
328 }
329 
330 void*
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 
361 int
363  const char* mime_type)
364 {
365  return mime_data_list_add(&offer->mimes, mime_type, NULL, 0);
366 }
367 
368 
369 SDL_bool
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 
381 void
383 {
384  if (offer != NULL) {
386  mime_data_list_free(&offer->mimes);
387  SDL_free(offer);
388  }
389 }
390 
391 int
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 
405 int
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 
453 int
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: */
SDL_waylandvideo.h
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:167
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
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
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_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_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
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_WaylandDataDevice::selection_source
SDL_WaylandDataSource * selection_source
Definition: SDL_waylanddatamanager.h:62
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
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179