SDL  2.0
SDL_rpimouse.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 #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 
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) {
81  SDL_free(cursor);
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, 0, 0, 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 
222  SDL_free(cursor->driverdata);
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  curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
251  if (curdata->element == DISPMANX_NO_HANDLE) {
252  return 0;
253  }
254 
255  update = vc_dispmanx_update_start(10);
256  if (!update) {
257  return 0;
258  }
259 
260  src_rect.x = 0;
261  src_rect.y = 0;
262  src_rect.width = curdata->w << 16;
263  src_rect.height = curdata->h << 16;
264  dst_rect.x = x;
265  dst_rect.y = y;
266  dst_rect.width = curdata->w;
267  dst_rect.height = curdata->h;
268 
269  ret = vc_dispmanx_element_change_attributes(
270  update,
271  curdata->element,
272  0,
273  0,
274  0,
275  &dst_rect,
276  &src_rect,
277  DISPMANX_NO_HANDLE,
278  DISPMANX_NO_ROTATE);
279  if (ret != DISPMANX_SUCCESS) {
280  return SDL_SetError("vc_dispmanx_element_change_attributes() failed");
281  }
282 
283  /* Submit asynchronously, otherwise the peformance suffers a lot */
284  ret = vc_dispmanx_update_submit(update, 0, NULL);
285  if (ret != DISPMANX_SUCCESS) {
286  return SDL_SetError("vc_dispmanx_update_submit() failed");
287  }
288  return 0;
289 }
290 
291 void
293 {
294  /* FIXME: Using UDEV it should be possible to scan all mice
295  * but there's no point in doing so as there's no multimice support...yet!
296  */
297  SDL_Mouse *mouse = SDL_GetMouse();
298 
299  mouse->CreateCursor = RPI_CreateCursor;
300  mouse->ShowCursor = RPI_ShowCursor;
301  mouse->MoveCursor = RPI_MoveCursor;
302  mouse->FreeCursor = RPI_FreeCursor;
303  mouse->WarpMouse = RPI_WarpMouse;
304  mouse->WarpMouseGlobal = RPI_WarpMouseGlobal;
305 
306  SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
307 }
308 
309 void
311 {
312 
313 }
314 
315 /* This is called when a mouse motion event occurs */
316 static void
317 RPI_MoveCursor(SDL_Cursor * cursor)
318 {
319  SDL_Mouse *mouse = SDL_GetMouse();
320  RPI_WarpMouse(mouse->focus, mouse->x, mouse->y);
321 }
322 
323 #endif /* SDL_VIDEO_DRIVER_RPI */
324 
325 /* vi: set ts=4 sw=4 expandtab: */
#define DEFAULT_CWIDTH
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:66
int(* ShowCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:52
#define SDL_RPI_MOUSELAYER
Definition: SDL_rpivideo.h:54
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
SDL_Window * focus
Definition: SDL_mouse_c.h:77
static SDL_Window * window
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
#define SDL_GetHint
#define DEFAULT_CHOTY
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:159
#define DEFAULT_CHOTX
GLfloat GLfloat GLfloat alpha
SDL_Cursor *(* CreateCursor)(SDL_Surface *surface, int hot_x, int hot_y)
Definition: SDL_mouse_c.h:46
void * SDL_calloc(size_t nmemb, size_t size)
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
void * pixels
Definition: SDL_surface.h:75
GLenum GLuint GLint GLint layer
#define _THIS
void SDL_free(void *mem)
DISPMANX_DISPLAY_HANDLE_T dispman_display
Definition: SDL_rpivideo.h:41
#define DEFAULT_CHEIGHT
void SDL_SetDefaultCursor(SDL_Cursor *cursor)
Definition: SDL_mouse.c:55
#define SDL_atoi
int(* WarpMouseGlobal)(int x, int y)
Definition: SDL_mouse_c.h:64
SDL_Cursor * cursor
void(* FreeCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:58
#define SDL_assert(condition)
Definition: SDL_assert.h:167
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
unsigned int uint32_t
SDL_PixelFormat * format
Definition: SDL_surface.h:72
#define SDL_SetError
static const unsigned char default_cmask[]
#define SDL_HINT_RPI_VIDEO_LAYER
Tell SDL which Dispmanx layer to use on a Raspberry PI.
Definition: SDL_hints.h:708
#define SDL_CreateCursor
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1058
The type used to identify a window.
Definition: SDL_sysvideo.h:71
void RPI_QuitMouse(_THIS)
void(* WarpMouse)(SDL_Window *window, int x, int y)
Definition: SDL_mouse_c.h:61
static const unsigned char default_cdata[]
SDL_Cursor * cur_cursor
Definition: SDL_mouse_c.h:93
void(* MoveCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:55
void * driverdata
Definition: SDL_mouse_c.h:33
void RPI_InitMouse(_THIS)