change SDL 1.2 to SDL 2.0
[platform/upstream/SDL.git] / src / video / wayland / SDL_waylandmouse.c
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,
105                        uint32_t format)
106 {
107     SDL_VideoDevice *vd = SDL_GetVideoDevice();
108     SDL_VideoData *data = (SDL_VideoData *) vd->driverdata;
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 {
155     SDL_Cursor *cursor;
156
157     cursor = calloc(1, sizeof (*cursor));
158     if (cursor) {
159         SDL_VideoDevice *vd = SDL_GetVideoDevice ();
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 */
165         SDL_assert(surface->format->format == SDL_PIXELFORMAT_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 {
198     SDL_Cursor *cursor;
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 {
223     SDL_VideoDevice *device = SDL_GetVideoDevice();
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 {
234     SDL_VideoDevice *vd = SDL_GetVideoDevice();
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;
244     case SDL_SYSTEM_CURSOR_ARROW:
245         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
246         break;
247     case SDL_SYSTEM_CURSOR_IBEAM:
248         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "xterm");
249         break;
250     case SDL_SYSTEM_CURSOR_WAIT:
251         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "watch");
252         break;
253     case SDL_SYSTEM_CURSOR_CROSSHAIR:
254         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
255         break;
256     case SDL_SYSTEM_CURSOR_WAITARROW:
257         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "watch");
258         break;
259     case SDL_SYSTEM_CURSOR_SIZENWSE:
260         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
261         break;
262     case SDL_SYSTEM_CURSOR_SIZENESW:
263         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
264         break;
265     case SDL_SYSTEM_CURSOR_SIZEWE:
266         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
267         break;
268     case SDL_SYSTEM_CURSOR_SIZENS:
269         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
270         break;
271     case SDL_SYSTEM_CURSOR_SIZEALL:
272         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "hand1");
273         break;
274     case SDL_SYSTEM_CURSOR_NO:
275         cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "xterm");
276         break;
277     case SDL_SYSTEM_CURSOR_HAND:
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 {
313     SDL_VideoDevice *vd = SDL_GetVideoDevice();
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 */