SDL  2.0
SDL_waylandmouse.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 #ifndef _GNU_SOURCE
27 #define _GNU_SOURCE
28 #endif
29 
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <limits.h>
37 
38 #include "../SDL_sysvideo.h"
39 
40 #include "SDL_mouse.h"
41 #include "../../events/SDL_mouse_c.h"
42 #include "SDL_waylandvideo.h"
43 #include "SDL_waylandevents_c.h"
44 
45 #include "SDL_waylanddyn.h"
46 #include "wayland-cursor.h"
47 
48 #include "SDL_assert.h"
49 
50 
51 typedef struct {
52  struct wl_buffer *buffer;
53  struct wl_surface *surface;
54 
55  int hot_x, hot_y;
56  int w, h;
57 
58  /* Either a preloaded cursor, or one we created ourselves */
59  struct wl_cursor *cursor;
60  void *shm_data;
61 } Wayland_CursorData;
62 
63 static int
64 wayland_create_tmp_file(off_t size)
65 {
66  static const char template[] = "/sdl-shared-XXXXXX";
67  char *xdg_path;
68  char tmp_path[PATH_MAX];
69  int fd;
70 
71  xdg_path = SDL_getenv("XDG_RUNTIME_DIR");
72  if (!xdg_path) {
73  errno = ENOENT;
74  return -1;
75  }
76 
77  SDL_strlcpy(tmp_path, xdg_path, PATH_MAX);
78  SDL_strlcat(tmp_path, template, PATH_MAX);
79 
80  fd = mkostemp(tmp_path, O_CLOEXEC);
81  if (fd < 0)
82  return -1;
83 
84  if (ftruncate(fd, size) < 0) {
85  close(fd);
86  return -1;
87  }
88 
89  return fd;
90 }
91 
92 static void
93 mouse_buffer_release(void *data, struct wl_buffer *buffer)
94 {
95 }
96 
97 static const struct wl_buffer_listener mouse_buffer_listener = {
98  mouse_buffer_release
99 };
100 
101 static int
102 create_buffer_from_shm(Wayland_CursorData *d,
103  int width,
104  int height,
106 {
109  struct wl_shm_pool *shm_pool;
110 
111  int stride = width * 4;
112  int size = stride * height;
113 
114  int shm_fd;
115 
116  shm_fd = wayland_create_tmp_file(size);
117  if (shm_fd < 0)
118  {
119  fprintf(stderr, "creating mouse cursor buffer failed!\n");
120  return -1;
121  }
122 
123  d->shm_data = mmap(NULL,
124  size,
125  PROT_READ | PROT_WRITE,
126  MAP_SHARED,
127  shm_fd,
128  0);
129  if (d->shm_data == MAP_FAILED) {
130  d->shm_data = NULL;
131  fprintf (stderr, "mmap () failed\n");
132  close (shm_fd);
133  }
134 
135  shm_pool = wl_shm_create_pool(data->shm, shm_fd, size);
136  d->buffer = wl_shm_pool_create_buffer(shm_pool,
137  0,
138  width,
139  height,
140  stride,
141  format);
142  wl_buffer_add_listener(d->buffer,
143  &mouse_buffer_listener,
144  d);
145 
146  wl_shm_pool_destroy (shm_pool);
147  close (shm_fd);
148 
149  return 0;
150 }
151 
152 static SDL_Cursor *
153 Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
154 {
156 
157  cursor = calloc(1, sizeof (*cursor));
158  if (cursor) {
160  SDL_VideoData *wd = (SDL_VideoData *) vd->driverdata;
161  Wayland_CursorData *data = calloc (1, sizeof (Wayland_CursorData));
162  cursor->driverdata = (void *) data;
163 
164  /* Assume ARGB8888 */
166  SDL_assert(surface->pitch == surface->w * 4);
167 
168  /* Allocate shared memory buffer for this cursor */
169  if (create_buffer_from_shm (data,
170  surface->w,
171  surface->h,
172  WL_SHM_FORMAT_XRGB8888) < 0)
173  {
174  free (cursor->driverdata);
175  free (cursor);
176  return NULL;
177  }
178 
179  SDL_memcpy(data->shm_data,
180  surface->pixels,
181  surface->h * surface->pitch);
182 
183  data->surface = wl_compositor_create_surface(wd->compositor);
184  wl_surface_set_user_data(data->surface, NULL);
185 
186  data->hot_x = hot_x;
187  data->hot_y = hot_y;
188  data->w = surface->w;
189  data->h = surface->h;
190  }
191 
192  return cursor;
193 }
194 
195 static SDL_Cursor *
196 CreateCursorFromWlCursor(SDL_VideoData *d, struct wl_cursor *wlcursor)
197 {
199 
200  cursor = calloc(1, sizeof (*cursor));
201  if (cursor) {
202  Wayland_CursorData *data = calloc (1, sizeof (Wayland_CursorData));
203  cursor->driverdata = (void *) data;
204 
205  data->buffer = WAYLAND_wl_cursor_image_get_buffer(wlcursor->images[0]);
206  data->surface = wl_compositor_create_surface(d->compositor);
207  wl_surface_set_user_data(data->surface, NULL);
208  data->hot_x = wlcursor->images[0]->hotspot_x;
209  data->hot_y = wlcursor->images[0]->hotspot_y;
210  data->w = wlcursor->images[0]->width;
211  data->h = wlcursor->images[0]->height;
212  data->cursor= wlcursor;
213  } else {
214  SDL_OutOfMemory ();
215  }
216 
217  return cursor;
218 }
219 
220 static SDL_Cursor *
221 Wayland_CreateDefaultCursor()
222 {
224  SDL_VideoData *data = device->driverdata;
225 
226  return CreateCursorFromWlCursor (data,
227  WAYLAND_wl_cursor_theme_get_cursor(data->cursor_theme,
228  "left_ptr"));
229 }
230 
231 static SDL_Cursor *
232 Wayland_CreateSystemCursor(SDL_SystemCursor id)
233 {
235  SDL_VideoData *d = vd->driverdata;
236 
237  struct wl_cursor *cursor = NULL;
238 
239  switch(id)
240  {
241  default:
242  SDL_assert(0);
243  return NULL;
245  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
246  break;
248  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "xterm");
249  break;
251  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "watch");
252  break;
254  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
255  break;
257  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "watch");
258  break;
260  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
261  break;
263  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
264  break;
266  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
267  break;
269  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
270  break;
272  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
273  break;
275  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "xterm");
276  break;
278  cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
279  break;
280  }
281 
282  return CreateCursorFromWlCursor(d, cursor);
283 }
284 
285 static void
286 Wayland_FreeCursor(SDL_Cursor *cursor)
287 {
288  Wayland_CursorData *d;
289 
290  if (!cursor)
291  return;
292 
293  d = cursor->driverdata;
294 
295  /* Probably not a cursor we own */
296  if (!d)
297  return;
298 
299  if (d->buffer && !d->cursor)
300  wl_buffer_destroy(d->buffer);
301 
302  if (d->surface)
303  wl_surface_destroy(d->surface);
304 
305  /* Not sure what's meant to happen to shm_data */
306  free (cursor->driverdata);
307  SDL_free(cursor);
308 }
309 
310 static int
311 Wayland_ShowCursor(SDL_Cursor *cursor)
312 {
314  SDL_VideoData *d = vd->driverdata;
315 
316  struct wl_pointer *pointer = d->pointer;
317 
318  if (!pointer)
319  return -1;
320 
321  if (cursor)
322  {
323  Wayland_CursorData *data = cursor->driverdata;
324 
325  wl_surface_attach(data->surface, data->buffer, 0, 0);
326  wl_surface_damage(data->surface, 0, 0, data->w, data->h);
327  wl_surface_commit(data->surface);
328  wl_pointer_set_cursor (pointer, 0,
329  data->surface,
330  data->hot_x,
331  data->hot_y);
332  }
333  else
334  {
335  wl_pointer_set_cursor (pointer, 0,
336  NULL,
337  0,
338  0);
339  }
340 
341  return 0;
342 }
343 
344 static void
345 Wayland_WarpMouse(SDL_Window *window, int x, int y)
346 {
347  SDL_Unsupported();
348 }
349 
350 static int
351 Wayland_WarpMouseGlobal(int x, int y)
352 {
353  return SDL_Unsupported();
354 }
355 
356 static int
357 Wayland_SetRelativeMouseMode(SDL_bool enabled)
358 {
359  return SDL_Unsupported();
360 }
361 
362 void
363 Wayland_InitMouse(void)
364 {
365  SDL_Mouse *mouse = SDL_GetMouse();
366 
367  mouse->CreateCursor = Wayland_CreateCursor;
368  mouse->CreateSystemCursor = Wayland_CreateSystemCursor;
369  mouse->ShowCursor = Wayland_ShowCursor;
370  mouse->FreeCursor = Wayland_FreeCursor;
371  mouse->WarpMouse = Wayland_WarpMouse;
372  mouse->WarpMouseGlobal = Wayland_WarpMouseGlobal;
373  mouse->SetRelativeMouseMode = Wayland_SetRelativeMouseMode;
374 
375  SDL_SetDefaultCursor(Wayland_CreateDefaultCursor());
376 }
377 
378 void
379 Wayland_FiniMouse(void)
380 {
381  /* This effectively assumes that nobody else
382  * touches SDL_Mouse which is effectively
383  * a singleton */
384 
385  SDL_Mouse *mouse = SDL_GetMouse();
386 
387  /* Free the current cursor if not the same pointer as
388  * the default cursor */
389  if (mouse->def_cursor != mouse->cur_cursor)
390  Wayland_FreeCursor (mouse->cur_cursor);
391 
392  Wayland_FreeCursor (mouse->def_cursor);
393  mouse->def_cursor = NULL;
394  mouse->cur_cursor = NULL;
395 
396  mouse->CreateCursor = NULL;
397  mouse->CreateSystemCursor = NULL;
398  mouse->ShowCursor = NULL;
399  mouse->FreeCursor = NULL;
400  mouse->WarpMouse = NULL;
401  mouse->SetRelativeMouseMode = NULL;
402 }
403 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
#define SDL_strlcpy
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1565
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:66
int(* ShowCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:52
#define SDL_strlcat
GLint GLint GLsizei width
Definition: SDL_opengl.h:1565
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
int(* SetRelativeMouseMode)(SDL_bool enabled)
Definition: SDL_mouse_c.h:67
SDL_Window * window
SDL_EventEntry * free
Definition: SDL_events.c:81
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
struct wl_cursor_theme * cursor_theme
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1565
#define calloc
Definition: SDL_malloc.c:642
GLsizeiptr size
GLsizei const void * pointer
SDL_bool
Definition: SDL_stdinc.h:126
SDL_Cursor *(* CreateCursor)(SDL_Surface *surface, int hot_x, int hot_y)
Definition: SDL_mouse_c.h:46
#define SDL_memcpy
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
void * pixels
Definition: SDL_surface.h:75
void SDL_free(void *mem)
SDL_SystemCursor
Cursor types for SDL_CreateSystemCursor.
Definition: SDL_mouse.h:46
SDL_Cursor * cursor
Definition: testwm2.c:40
void SDL_SetDefaultCursor(SDL_Cursor *cursor)
Definition: SDL_mouse.c:55
int(* WarpMouseGlobal)(int x, int y)
Definition: SDL_mouse_c.h:64
GLenum GLenum GLsizei const GLuint GLboolean enabled
#define SDL_getenv
void(* FreeCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:58
struct wl_pointer * pointer
#define SDL_assert(condition)
Definition: SDL_assert.h:167
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
unsigned int uint32_t
SDL_PixelFormat * format
Definition: SDL_surface.h:72
struct wl_compositor * compositor
The type used to identify a window.
Definition: SDL_sysvideo.h:71
GLsizei stride
GLuint buffer
void(* WarpMouse)(SDL_Window *window, int x, int y)
Definition: SDL_mouse_c.h:61
SDL_VideoDevice * SDL_GetVideoDevice(void)
Definition: SDL_video.c:573
GLubyte GLubyte GLubyte GLubyte w
SDL_Cursor * cur_cursor
Definition: SDL_mouse_c.h:93
SDL_Cursor *(* CreateSystemCursor)(SDL_SystemCursor id)
Definition: SDL_mouse_c.h:49
void * driverdata
Definition: SDL_mouse_c.h:33
struct wl_shm * shm
#define SDL_Unsupported()
Definition: SDL_error.h:53
GLfloat GLfloat GLfloat GLfloat h
SDL_Cursor * def_cursor
Definition: SDL_mouse_c.h:92