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