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