SDL  2.0
SDL_rpimouse.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 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_RPI
24 
25 #include "SDL_assert.h"
26 #include "SDL_surface.h"
27 #include "SDL_hints.h"
28 
29 #include "SDL_rpivideo.h"
30 #include "SDL_rpimouse.h"
31 
32 #include "../SDL_sysvideo.h"
33 #include "../../events/SDL_mouse_c.h"
34 #include "../../events/default_cursor.h"
35 
36 /* Copied from vc_vchi_dispmanx.h which is bugged and tries to include a non existing file */
37 /* Attributes changes flag mask */
38 #define ELEMENT_CHANGE_LAYER (1<<0)
39 #define ELEMENT_CHANGE_OPACITY (1<<1)
40 #define ELEMENT_CHANGE_DEST_RECT (1<<2)
41 #define ELEMENT_CHANGE_SRC_RECT (1<<3)
42 #define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
43 #define ELEMENT_CHANGE_TRANSFORM (1<<5)
44 /* End copied from vc_vchi_dispmanx.h */
45 
46 static SDL_Cursor *RPI_CreateDefaultCursor(void);
47 static SDL_Cursor *RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
48 static int RPI_ShowCursor(SDL_Cursor * cursor);
49 static void RPI_MoveCursor(SDL_Cursor * cursor);
50 static void RPI_FreeCursor(SDL_Cursor * cursor);
51 static void RPI_WarpMouse(SDL_Window * window, int x, int y);
52 static int RPI_WarpMouseGlobal(int x, int y);
53 
54 static SDL_Cursor *
55 RPI_CreateDefaultCursor(void)
56 {
58 }
59 
60 /* Create a cursor from a surface */
61 static SDL_Cursor *
62 RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
63 {
64  RPI_CursorData *curdata;
66  int ret;
67  VC_RECT_T dst_rect;
68  Uint32 dummy;
69 
70  SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
71  SDL_assert(surface->pitch == surface->w * 4);
72 
73  cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
74  if (cursor == NULL) {
76  return NULL;
77  }
78  curdata = (RPI_CursorData *) SDL_calloc(1, sizeof(*curdata));
79  if (curdata == NULL) {
82  return NULL;
83  }
84 
85  curdata->hot_x = hot_x;
86  curdata->hot_y = hot_y;
87  curdata->w = surface->w;
88  curdata->h = surface->h;
89 
90  /* This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess */
91  curdata->resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy);
92  SDL_assert(curdata->resource);
93  vc_dispmanx_rect_set(&dst_rect, 0, 0, curdata->w, curdata->h);
94  /* A note from Weston:
95  * vc_dispmanx_resource_write_data() ignores ifmt,
96  * rect.x, rect.width, and uses stride only for computing
97  * the size of the transfer as rect.height * stride.
98  * Therefore we can only write rows starting at x=0.
99  */
100  ret = vc_dispmanx_resource_write_data(curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect);
101  SDL_assert (ret == DISPMANX_SUCCESS);
102 
103  cursor->driverdata = curdata;
104 
105  return cursor;
106 
107 }
108 
109 /* Show the specified cursor, or hide if cursor is NULL */
110 static int
111 RPI_ShowCursor(SDL_Cursor * cursor)
112 {
113  int ret;
114  DISPMANX_UPDATE_HANDLE_T update;
115  RPI_CursorData *curdata;
116  VC_RECT_T src_rect, dst_rect;
117  SDL_Mouse *mouse;
118  SDL_VideoDisplay *display;
120  VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/, 0 /* mask */ };
122  const char *env;
123 
124  mouse = SDL_GetMouse();
125  if (mouse == NULL) {
126  return -1;
127  }
128 
129  if (cursor == NULL) {
130  /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */
131 
132  if (mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
133  curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
134  if (curdata->element > DISPMANX_NO_HANDLE) {
135  update = vc_dispmanx_update_start(10);
136  SDL_assert(update);
137  ret = vc_dispmanx_element_remove(update, curdata->element);
138  SDL_assert(ret == DISPMANX_SUCCESS);
139  ret = vc_dispmanx_update_submit_sync(update);
140  SDL_assert(ret == DISPMANX_SUCCESS);
141  curdata->element = DISPMANX_NO_HANDLE;
142  }
143  }
144  return 0;
145  }
146 
147  curdata = (RPI_CursorData *) cursor->driverdata;
148  if (curdata == NULL) {
149  return -1;
150  }
151 
152  if (mouse->focus == NULL) {
153  return -1;
154  }
155 
156  display = SDL_GetDisplayForWindow(mouse->focus);
157  if (display == NULL) {
158  return -1;
159  }
160 
161  data = (SDL_DisplayData*) display->driverdata;
162  if (data == NULL) {
163  return -1;
164  }
165 
166  if (curdata->element == DISPMANX_NO_HANDLE) {
167  vc_dispmanx_rect_set(&src_rect, 0, 0, curdata->w << 16, curdata->h << 16);
168  vc_dispmanx_rect_set(&dst_rect, mouse->x, mouse->y, curdata->w, curdata->h);
169 
170  update = vc_dispmanx_update_start(10);
171  SDL_assert(update);
172 
174  if (env) {
175  layer = SDL_atoi(env) + 1;
176  }
177 
178  curdata->element = vc_dispmanx_element_add(update,
179  data->dispman_display,
180  layer,
181  &dst_rect,
182  curdata->resource,
183  &src_rect,
184  DISPMANX_PROTECTION_NONE,
185  &alpha,
186  DISPMANX_NO_HANDLE, // clamp
187  VC_IMAGE_ROT0);
188  SDL_assert(curdata->element > DISPMANX_NO_HANDLE);
189  ret = vc_dispmanx_update_submit_sync(update);
190  SDL_assert(ret == DISPMANX_SUCCESS);
191  }
192 
193  return 0;
194 }
195 
196 /* Free a window manager cursor */
197 static void
198 RPI_FreeCursor(SDL_Cursor * cursor)
199 {
200  int ret;
201  DISPMANX_UPDATE_HANDLE_T update;
202  RPI_CursorData *curdata;
203 
204  if (cursor != NULL) {
205  curdata = (RPI_CursorData *) cursor->driverdata;
206 
207  if (curdata != NULL) {
208  if (curdata->element != DISPMANX_NO_HANDLE) {
209  update = vc_dispmanx_update_start(10);
210  SDL_assert(update);
211  ret = vc_dispmanx_element_remove(update, curdata->element);
212  SDL_assert(ret == DISPMANX_SUCCESS);
213  ret = vc_dispmanx_update_submit_sync(update);
214  SDL_assert(ret == DISPMANX_SUCCESS);
215  }
216 
217  if (curdata->resource != DISPMANX_NO_HANDLE) {
218  ret = vc_dispmanx_resource_delete(curdata->resource);
219  SDL_assert(ret == DISPMANX_SUCCESS);
220  }
221 
223  }
224  SDL_free(cursor);
225  }
226 }
227 
228 /* Warp the mouse to (x,y) */
229 static void
230 RPI_WarpMouse(SDL_Window * window, int x, int y)
231 {
232  RPI_WarpMouseGlobal(x, y);
233 }
234 
235 /* Warp the mouse to (x,y) */
236 static int
237 RPI_WarpMouseGlobal(int x, int y)
238 {
239  RPI_CursorData *curdata;
240  DISPMANX_UPDATE_HANDLE_T update;
241  int ret;
242  VC_RECT_T dst_rect;
243  VC_RECT_T src_rect;
244  SDL_Mouse *mouse = SDL_GetMouse();
245 
246  if (mouse == NULL || mouse->cur_cursor == NULL || mouse->cur_cursor->driverdata == NULL) {
247  return 0;
248  }
249 
250  /* Update internal mouse position. */
251  SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x, y);
252 
253  curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
254  if (curdata->element == DISPMANX_NO_HANDLE) {
255  return 0;
256  }
257 
258  update = vc_dispmanx_update_start(10);
259  if (!update) {
260  return 0;
261  }
262 
263  src_rect.x = 0;
264  src_rect.y = 0;
265  src_rect.width = curdata->w << 16;
266  src_rect.height = curdata->h << 16;
267  dst_rect.x = x;
268  dst_rect.y = y;
269  dst_rect.width = curdata->w;
270  dst_rect.height = curdata->h;
271 
272  ret = vc_dispmanx_element_change_attributes(
273  update,
274  curdata->element,
275  0,
276  0,
277  0,
278  &dst_rect,
279  &src_rect,
280  DISPMANX_NO_HANDLE,
281  DISPMANX_NO_ROTATE);
282  if (ret != DISPMANX_SUCCESS) {
283  return SDL_SetError("vc_dispmanx_element_change_attributes() failed");
284  }
285 
286  /* Submit asynchronously, otherwise the peformance suffers a lot */
287  ret = vc_dispmanx_update_submit(update, 0, NULL);
288  if (ret != DISPMANX_SUCCESS) {
289  return SDL_SetError("vc_dispmanx_update_submit() failed");
290  }
291  return 0;
292 }
293 
294 /* Warp the mouse to (x,y) */
295 static int
296 RPI_WarpMouseGlobalGraphicOnly(int x, int y)
297 {
298  RPI_CursorData *curdata;
299  DISPMANX_UPDATE_HANDLE_T update;
300  int ret;
301  VC_RECT_T dst_rect;
302  VC_RECT_T src_rect;
303  SDL_Mouse *mouse = SDL_GetMouse();
304 
305  if (mouse == NULL || mouse->cur_cursor == NULL || mouse->cur_cursor->driverdata == NULL) {
306  return 0;
307  }
308 
309  curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
310  if (curdata->element == DISPMANX_NO_HANDLE) {
311  return 0;
312  }
313 
314  update = vc_dispmanx_update_start(10);
315  if (!update) {
316  return 0;
317  }
318 
319  src_rect.x = 0;
320  src_rect.y = 0;
321  src_rect.width = curdata->w << 16;
322  src_rect.height = curdata->h << 16;
323  dst_rect.x = x;
324  dst_rect.y = y;
325  dst_rect.width = curdata->w;
326  dst_rect.height = curdata->h;
327 
328  ret = vc_dispmanx_element_change_attributes(
329  update,
330  curdata->element,
331  0,
332  0,
333  0,
334  &dst_rect,
335  &src_rect,
336  DISPMANX_NO_HANDLE,
337  DISPMANX_NO_ROTATE);
338  if (ret != DISPMANX_SUCCESS) {
339  return SDL_SetError("vc_dispmanx_element_change_attributes() failed");
340  }
341 
342  /* Submit asynchronously, otherwise the peformance suffers a lot */
343  ret = vc_dispmanx_update_submit(update, 0, NULL);
344  if (ret != DISPMANX_SUCCESS) {
345  return SDL_SetError("vc_dispmanx_update_submit() failed");
346  }
347  return 0;
348 }
349 
350 void
352 {
353  /* FIXME: Using UDEV it should be possible to scan all mice
354  * but there's no point in doing so as there's no multimice support...yet!
355  */
356  SDL_Mouse *mouse = SDL_GetMouse();
357 
358  mouse->CreateCursor = RPI_CreateCursor;
359  mouse->ShowCursor = RPI_ShowCursor;
360  mouse->MoveCursor = RPI_MoveCursor;
361  mouse->FreeCursor = RPI_FreeCursor;
362  mouse->WarpMouse = RPI_WarpMouse;
363  mouse->WarpMouseGlobal = RPI_WarpMouseGlobal;
364 
365  SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
366 }
367 
368 void
370 {
371 
372 }
373 
374 /* This is called when a mouse motion event occurs */
375 static void
376 RPI_MoveCursor(SDL_Cursor * cursor)
377 {
378  SDL_Mouse *mouse = SDL_GetMouse();
379  /* We must NOT call SDL_SendMouseMotion() on the next call or we will enter recursivity,
380  * so we create a version of WarpMouseGlobal without it. */
381  RPI_WarpMouseGlobalGraphicOnly(mouse->x, mouse->y);
382 }
383 
384 #endif /* SDL_VIDEO_DRIVER_RPI */
385 
386 /* vi: set ts=4 sw=4 expandtab: */
SDL_GetMouse
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:144
SDL_PIXELFORMAT_ARGB8888
@ SDL_PIXELFORMAT_ARGB8888
Definition: SDL_pixels.h:248
SDL_Mouse::WarpMouseGlobal
int(* WarpMouseGlobal)(int x, int y)
Definition: SDL_mouse_c.h:64
SDL_Surface
A collection of pixels used in software blitting.
Definition: SDL_surface.h:70
SDL_Cursor
Definition: SDL_mouse_c.h:31
DEFAULT_CHOTY
#define DEFAULT_CHOTY
Definition: default_cursor.h:28
NULL
#define NULL
Definition: begin_code.h:164
surface
EGLSurface surface
Definition: eglext.h:248
layer
GLenum GLuint GLint GLint layer
Definition: SDL_opengl_glext.h:1186
SDL_surface.h
SDL_GetDisplayForWindow
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1092
default_cmask
static const unsigned char default_cmask[]
Definition: default_cursor.h:54
SDL_Mouse::y
int y
Definition: SDL_mouse_c.h:79
RPI_InitMouse
void RPI_InitMouse(_THIS)
SDL_rpivideo.h
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_GetHint
#define SDL_GetHint
Definition: SDL_dynapi_overrides.h:191
SDL_Cursor::driverdata
void * driverdata
Definition: SDL_mouse_c.h:33
DEFAULT_CWIDTH
#define DEFAULT_CWIDTH
Definition: default_cursor.h:25
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_Window
The type used to identify a window.
Definition: SDL_sysvideo.h:74
alpha
GLfloat GLfloat GLfloat alpha
Definition: SDL_opengl_glext.h:412
SDL_Mouse::MoveCursor
void(* MoveCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:55
x
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
SDL_Mouse::WarpMouse
void(* WarpMouse)(SDL_Window *window, int x, int y)
Definition: SDL_mouse_c.h:61
window
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
DEFAULT_CHEIGHT
#define DEFAULT_CHEIGHT
Definition: default_cursor.h:26
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_SendMouseMotion
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:263
SDL_assert.h
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_Mouse
Definition: SDL_mouse_c.h:44
hot_x
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:57
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_Mouse::focus
SDL_Window * focus
Definition: SDL_mouse_c.h:77
SDL_VideoDisplay::driverdata
void * driverdata
Definition: SDL_sysvideo.h:139
SDL_DisplayData
Definition: SDL_cocoamodes.h:27
cursor
SDL_Cursor * cursor
Definition: testwm2.c:40
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_Mouse::ShowCursor
int(* ShowCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:52
y
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
SDL_SetDefaultCursor
void SDL_SetDefaultCursor(SDL_Cursor *cursor)
Definition: SDL_mouse.c:133
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_atoi
#define SDL_atoi
Definition: SDL_dynapi_overrides.h:410
SDL_CreateCursor
#define SDL_CreateCursor
Definition: SDL_dynapi_overrides.h:251
uint32_t
unsigned int uint32_t
Definition: SDL_config_windows.h:63
SDL_Mouse::x
int x
Definition: SDL_mouse_c.h:78
SDL_VideoDisplay
Definition: SDL_sysvideo.h:126
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_hints.h
SDL_HINT_RPI_VIDEO_LAYER
#define SDL_HINT_RPI_VIDEO_LAYER
Tell SDL which Dispmanx layer to use on a Raspberry PI.
Definition: SDL_hints.h:956
DEFAULT_CHOTX
#define DEFAULT_CHOTX
Definition: default_cursor.h:27
default_cdata
static const unsigned char default_cdata[]
Definition: default_cursor.h:35
SDL_Mouse::FreeCursor
void(* FreeCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:58
SDL_Mouse::CreateCursor
SDL_Cursor *(* CreateCursor)(SDL_Surface *surface, int hot_x, int hot_y)
Definition: SDL_mouse_c.h:46
SDL_Mouse::mouseID
SDL_MouseID mouseID
Definition: SDL_mouse_c.h:76
SDL_rpimouse.h
SDL_Mouse::cur_cursor
SDL_Cursor * cur_cursor
Definition: SDL_mouse_c.h:103
RPI_QuitMouse
void RPI_QuitMouse(_THIS)
SDL_RPI_MOUSELAYER
#define SDL_RPI_MOUSELAYER
Definition: SDL_rpivideo.h:60