SDL  2.0
SDL_kmsdrmmouse.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_KMSDRM
25 
26 #include "SDL_kmsdrmvideo.h"
27 #include "SDL_kmsdrmmouse.h"
28 #include "SDL_kmsdrmdyn.h"
29 
30 #include "../../events/SDL_mouse_c.h"
31 #include "../../events/default_cursor.h"
32 
33 static SDL_Cursor *KMSDRM_CreateDefaultCursor(void);
34 static SDL_Cursor *KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
35 static int KMSDRM_ShowCursor(SDL_Cursor * cursor);
36 static void KMSDRM_MoveCursor(SDL_Cursor * cursor);
37 static void KMSDRM_FreeCursor(SDL_Cursor * cursor);
38 static void KMSDRM_WarpMouse(SDL_Window * window, int x, int y);
39 static int KMSDRM_WarpMouseGlobal(int x, int y);
40 
41 static SDL_Cursor *
42 KMSDRM_CreateDefaultCursor(void)
43 {
45 }
46 
47 /* Create a cursor from a surface */
48 static SDL_Cursor *
49 KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
50 {
52  SDL_VideoData *vdata = ((SDL_VideoData *)dev->driverdata);
53  SDL_PixelFormat *pixlfmt = surface->format;
54  KMSDRM_CursorData *curdata;
56  int i, ret;
57  uint32_t bo_format, bo_stride;
58  char *buffer = NULL;
59  size_t bufsize;
60 
61  switch(pixlfmt->format) {
63  bo_format = GBM_FORMAT_RGB332;
64  break;
66  bo_format = GBM_FORMAT_ARGB4444;
67  break;
69  bo_format = GBM_FORMAT_RGBA4444;
70  break;
72  bo_format = GBM_FORMAT_ABGR4444;
73  break;
75  bo_format = GBM_FORMAT_BGRA4444;
76  break;
78  bo_format = GBM_FORMAT_ARGB1555;
79  break;
81  bo_format = GBM_FORMAT_RGBA5551;
82  break;
84  bo_format = GBM_FORMAT_ABGR1555;
85  break;
87  bo_format = GBM_FORMAT_BGRA5551;
88  break;
90  bo_format = GBM_FORMAT_RGB565;
91  break;
93  bo_format = GBM_FORMAT_BGR565;
94  break;
97  bo_format = GBM_FORMAT_RGB888;
98  break;
101  bo_format = GBM_FORMAT_BGR888;
102  break;
104  bo_format = GBM_FORMAT_RGBX8888;
105  break;
107  bo_format = GBM_FORMAT_BGRX8888;
108  break;
110  bo_format = GBM_FORMAT_ARGB8888;
111  break;
113  bo_format = GBM_FORMAT_RGBA8888;
114  break;
116  bo_format = GBM_FORMAT_ABGR8888;
117  break;
119  bo_format = GBM_FORMAT_BGRA8888;
120  break;
122  bo_format = GBM_FORMAT_ARGB2101010;
123  break;
124  default:
125  SDL_SetError("Unsupported pixel format for cursor");
126  return NULL;
127  }
128 
129  if (!KMSDRM_gbm_device_is_format_supported(vdata->gbm, bo_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)) {
130  SDL_SetError("Unsupported pixel format for cursor");
131  return NULL;
132  }
133 
134  cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
135  if (cursor == NULL) {
136  SDL_OutOfMemory();
137  return NULL;
138  }
139  curdata = (KMSDRM_CursorData *) SDL_calloc(1, sizeof(*curdata));
140  if (curdata == NULL) {
141  SDL_OutOfMemory();
142  SDL_free(cursor);
143  return NULL;
144  }
145 
146  curdata->hot_x = hot_x;
147  curdata->hot_y = hot_y;
148  curdata->w = surface->w;
149  curdata->h = surface->h;
150 
151  curdata->bo = KMSDRM_gbm_bo_create(vdata->gbm, surface->w, surface->h, bo_format,
152  GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
153  if (curdata->bo == NULL) {
154  SDL_SetError("Could not create GBM cursor BO");
155  goto cleanup;
156  }
157 
158  bo_stride = KMSDRM_gbm_bo_get_stride(curdata->bo);
159  bufsize = bo_stride * surface->h;
160 
161  if (surface->pitch != bo_stride) {
162  /* pitch doesn't match stride, must be copied to temp buffer */
163  buffer = SDL_malloc(bufsize);
164  if (buffer == NULL) {
165  SDL_OutOfMemory();
166  goto cleanup;
167  }
168 
169  if (SDL_MUSTLOCK(surface)) {
170  if (SDL_LockSurface(surface) < 0) {
171  /* Could not lock surface */
172  goto cleanup;
173  }
174  }
175 
176  /* Copy to temporary buffer */
177  for (i = 0; i < surface->h; i++) {
178  SDL_memcpy(buffer + (i * bo_stride),
179  ((char *)surface->pixels) + (i * surface->pitch),
180  surface->w * pixlfmt->BytesPerPixel);
181  }
182 
183  if (SDL_MUSTLOCK(surface)) {
184  SDL_UnlockSurface(surface);
185  }
186 
187  if (KMSDRM_gbm_bo_write(curdata->bo, buffer, bufsize)) {
188  SDL_SetError("Could not write to GBM cursor BO");
189  goto cleanup;
190  }
191 
192  /* Free temporary buffer */
193  SDL_free(buffer);
194  buffer = NULL;
195  } else {
196  /* surface matches BO format */
197  if (SDL_MUSTLOCK(surface)) {
198  if (SDL_LockSurface(surface) < 0) {
199  /* Could not lock surface */
200  goto cleanup;
201  }
202  }
203 
204  ret = KMSDRM_gbm_bo_write(curdata->bo, surface->pixels, bufsize);
205 
206  if (SDL_MUSTLOCK(surface)) {
207  SDL_UnlockSurface(surface);
208  }
209 
210  if (ret) {
211  SDL_SetError("Could not write to GBM cursor BO");
212  goto cleanup;
213  }
214  }
215 
216  cursor->driverdata = curdata;
217 
218  return cursor;
219 
220 cleanup:
221  if (buffer != NULL) {
222  SDL_free(buffer);
223  }
224  if (cursor != NULL) {
225  SDL_free(cursor);
226  }
227  if (curdata != NULL) {
228  if (curdata->bo != NULL) {
229  KMSDRM_gbm_bo_destroy(curdata->bo);
230  }
231  SDL_free(curdata);
232  }
233  return NULL;
234 }
235 
236 /* Show the specified cursor, or hide if cursor is NULL */
237 static int
238 KMSDRM_ShowCursor(SDL_Cursor * cursor)
239 {
241  SDL_VideoData *vdata = ((SDL_VideoData *)dev->driverdata);
242  SDL_Mouse *mouse;
243  KMSDRM_CursorData *curdata;
244  SDL_VideoDisplay *display = NULL;
245  SDL_DisplayData *ddata = NULL;
246  int ret;
248 
249  mouse = SDL_GetMouse();
250  if (mouse == NULL) {
251  return SDL_SetError("No mouse.");
252  }
253 
254  if (mouse->focus != NULL) {
255  display = SDL_GetDisplayForWindow(mouse->focus);
256  if (display != NULL) {
257  ddata = (SDL_DisplayData*) display->driverdata;
258  }
259  }
260 
261  if (cursor == NULL) {
262  /* Hide current cursor */
263  if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
264  curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
265 
266  if (curdata->crtc_id != 0) {
267  ret = KMSDRM_drmModeSetCursor(vdata->drm_fd, curdata->crtc_id, 0, 0, 0);
268  if (ret) {
269  SDL_SetError("Could not hide current cursor with drmModeSetCursor().");
270  return ret;
271  }
272  /* Mark previous cursor as not-displayed */
273  curdata->crtc_id = 0;
274 
275  return 0;
276  }
277  }
278  /* otherwise if possible, hide global cursor */
279  if (ddata != NULL && ddata->crtc_id != 0) {
280  ret = KMSDRM_drmModeSetCursor(vdata->drm_fd, ddata->crtc_id, 0, 0, 0);
281  if (ret) {
282  SDL_SetError("Could not hide display's cursor with drmModeSetCursor().");
283  return ret;
284  }
285  return 0;
286  }
287 
288  return SDL_SetError("Couldn't find cursor to hide.");
289  }
290  /* If cursor != NULL, show new cursor on display */
291  if (display == NULL) {
292  return SDL_SetError("Could not get display for mouse.");
293  }
294  if (ddata == NULL) {
295  return SDL_SetError("Could not get display driverdata.");
296  }
297 
298  curdata = (KMSDRM_CursorData *) cursor->driverdata;
299  if (curdata == NULL || curdata->bo == NULL) {
300  return SDL_SetError("Cursor not initialized properly.");
301  }
302 
303  bo_handle = KMSDRM_gbm_bo_get_handle(curdata->bo).u32;
304  if (curdata->hot_x == 0 && curdata->hot_y == 0) {
305  ret = KMSDRM_drmModeSetCursor(vdata->drm_fd, ddata->crtc_id, bo_handle,
306  curdata->w, curdata->h);
307  } else {
308  ret = KMSDRM_drmModeSetCursor2(vdata->drm_fd, ddata->crtc_id, bo_handle,
309  curdata->w, curdata->h,
310  curdata->hot_x, curdata->hot_y);
311  }
312  if (ret) {
313  SDL_SetError("drmModeSetCursor failed.");
314  return ret;
315  }
316 
317  curdata->crtc_id = ddata->crtc_id;
318 
319  return 0;
320 }
321 
322 /* Free a window manager cursor */
323 static void
324 KMSDRM_FreeCursor(SDL_Cursor * cursor)
325 {
326  KMSDRM_CursorData *curdata;
327  int drm_fd;
328 
329  if (cursor != NULL) {
330  curdata = (KMSDRM_CursorData *) cursor->driverdata;
331 
332  if (curdata != NULL) {
333  if (curdata->bo != NULL) {
334  if (curdata->crtc_id != 0) {
335  drm_fd = KMSDRM_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(curdata->bo));
336  /* Hide the cursor if previously shown on a CRTC */
337  KMSDRM_drmModeSetCursor(drm_fd, curdata->crtc_id, 0, 0, 0);
338  curdata->crtc_id = 0;
339  }
340  KMSDRM_gbm_bo_destroy(curdata->bo);
341  curdata->bo = NULL;
342  }
343  SDL_free(cursor->driverdata);
344  }
345  SDL_free(cursor);
346  }
347 }
348 
349 /* Warp the mouse to (x,y) */
350 static void
351 KMSDRM_WarpMouse(SDL_Window * window, int x, int y)
352 {
353  /* Only one global/fullscreen window is supported */
354  KMSDRM_WarpMouseGlobal(x, y);
355 }
356 
357 /* Warp the mouse to (x,y) */
358 static int
359 KMSDRM_WarpMouseGlobal(int x, int y)
360 {
361  KMSDRM_CursorData *curdata;
362  SDL_Mouse *mouse = SDL_GetMouse();
363 
364  if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
365  curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
366  if (curdata->bo != NULL) {
367  if (curdata->crtc_id != 0) {
368  int ret, drm_fd;
369  drm_fd = KMSDRM_gbm_device_get_fd(KMSDRM_gbm_bo_get_device(curdata->bo));
370  ret = KMSDRM_drmModeMoveCursor(drm_fd, curdata->crtc_id, x, y);
371 
372  if (ret) {
373  SDL_SetError("drmModeMoveCursor() failed.");
374  }
375 
376  return ret;
377  } else {
378  return SDL_SetError("Cursor is not currently shown.");
379  }
380  } else {
381  return SDL_SetError("Cursor not initialized properly.");
382  }
383  } else {
384  return SDL_SetError("No mouse or current cursor.");
385  }
386 }
387 
388 void
390 {
391  /* FIXME: Using UDEV it should be possible to scan all mice
392  * but there's no point in doing so as there's no multimice support...yet!
393  */
394  SDL_Mouse *mouse = SDL_GetMouse();
395 
396  mouse->CreateCursor = KMSDRM_CreateCursor;
397  mouse->ShowCursor = KMSDRM_ShowCursor;
398  mouse->MoveCursor = KMSDRM_MoveCursor;
399  mouse->FreeCursor = KMSDRM_FreeCursor;
400  mouse->WarpMouse = KMSDRM_WarpMouse;
401  mouse->WarpMouseGlobal = KMSDRM_WarpMouseGlobal;
402 
403  SDL_SetDefaultCursor(KMSDRM_CreateDefaultCursor());
404 }
405 
406 void
408 {
409  /* TODO: ? */
410 }
411 
412 /* This is called when a mouse motion event occurs */
413 static void
414 KMSDRM_MoveCursor(SDL_Cursor * cursor)
415 {
416  SDL_Mouse *mouse = SDL_GetMouse();
417  KMSDRM_WarpMouse(mouse->focus, mouse->x, mouse->y);
418 }
419 
420 #endif /* SDL_VIDEO_DRIVER_KMSDRM */
421 
422 /* vi: set ts=4 sw=4 expandtab: */
#define DEFAULT_CWIDTH
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:110
void KMSDRM_QuitMouse(_THIS)
#define SDL_UnlockSurface
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
Uint8 BytesPerPixel
Definition: SDL_pixels.h:318
SDL_Window * focus
Definition: SDL_mouse_c.h:77
void KMSDRM_InitMouse(_THIS)
EGLSurface surface
Definition: eglext.h:248
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
#define DEFAULT_CHOTY
#define DEFAULT_CHOTX
int(* WarpMouseGlobal)(int x, int y)
Definition: SDL_mouse_c.h:64
GLenum GLuint GLsizei bufsize
void(* MoveCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:55
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
void(* FreeCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:58
#define SDL_memcpy
void * SDL_calloc(size_t nmemb, size_t size)
SDL_Cursor *(* CreateCursor)(SDL_Surface *surface, int hot_x, int hot_y)
Definition: SDL_mouse_c.h:46
void * pixels
Definition: SDL_surface.h:75
#define _THIS
int(* ShowCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:52
void SDL_free(void *mem)
int uint32_t uint32_t uint32_t uint32_t uint32_t int drmModeModeInfoPtr mode int uint32_t uint32_t bo_handle
Definition: SDL_kmsdrmsym.h:55
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
#define DEFAULT_CHEIGHT
void SDL_SetDefaultCursor(SDL_Cursor *cursor)
Definition: SDL_mouse.c:99
SDL_Cursor * cursor
struct gbm_device * gbm
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
GLuint buffer
unsigned int uint32_t
SDL_PixelFormat * format
Definition: SDL_surface.h:72
#define SDL_SetError
#define SDL_LockSurface
static const unsigned char default_cmask[]
#define SDL_CreateCursor
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1073
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
#define SDL_MUSTLOCK(S)
Definition: SDL_surface.h:61
The type used to identify a window.
Definition: SDL_sysvideo.h:73
struct gbm_bo * bo
SDL_VideoDevice * SDL_GetVideoDevice(void)
Definition: SDL_video.c:586
#define SDL_malloc
static const unsigned char default_cdata[]
SDL_Cursor * cur_cursor
Definition: SDL_mouse_c.h:101
static void cleanup(void)
Definition: testfile.c:44
void * driverdata
Definition: SDL_mouse_c.h:33
void(* WarpMouse)(SDL_Window *window, int x, int y)
Definition: SDL_mouse_c.h:61
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