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 
28 #include "SDL_rpivideo.h"
29 #include "SDL_rpimouse.h"
30 
31 #include "../SDL_sysvideo.h"
32 #include "../../events/SDL_mouse_c.h"
33 #include "../../events/default_cursor.h"
34 
35 /* Copied from vc_vchi_dispmanx.h which is bugged and tries to include a non existing file */
36 /* Attributes changes flag mask */
37 #define ELEMENT_CHANGE_LAYER (1<<0)
38 #define ELEMENT_CHANGE_OPACITY (1<<1)
39 #define ELEMENT_CHANGE_DEST_RECT (1<<2)
40 #define ELEMENT_CHANGE_SRC_RECT (1<<3)
41 #define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
42 #define ELEMENT_CHANGE_TRANSFORM (1<<5)
43 /* End copied from vc_vchi_dispmanx.h */
44 
45 static SDL_Cursor *RPI_CreateDefaultCursor(void);
46 static SDL_Cursor *RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
47 static int RPI_ShowCursor(SDL_Cursor * cursor);
48 static void RPI_MoveCursor(SDL_Cursor * cursor);
49 static void RPI_FreeCursor(SDL_Cursor * cursor);
50 static void RPI_WarpMouse(SDL_Window * window, int x, int y);
51 static int RPI_WarpMouseGlobal(int x, int y);
52 
53 static SDL_Cursor *
54 RPI_CreateDefaultCursor(void)
55 {
57 }
58 
59 /* Create a cursor from a surface */
60 static SDL_Cursor *
61 RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
62 {
63  RPI_CursorData *curdata;
65  int ret;
66  VC_RECT_T dst_rect;
67  Uint32 dummy;
68 
70  SDL_assert(surface->pitch == surface->w * 4);
71 
72  cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
73  curdata = (RPI_CursorData *) SDL_calloc(1, sizeof(*curdata));
74 
75  curdata->hot_x = hot_x;
76  curdata->hot_y = hot_y;
77  curdata->w = surface->w;
78  curdata->h = surface->h;
79 
80  /* This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess */
81  curdata->resource = vc_dispmanx_resource_create( VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy );
82  SDL_assert(curdata->resource);
83  vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
84  /* A note from Weston:
85  * vc_dispmanx_resource_write_data() ignores ifmt,
86  * rect.x, rect.width, and uses stride only for computing
87  * the size of the transfer as rect.height * stride.
88  * Therefore we can only write rows starting at x=0.
89  */
90  ret = vc_dispmanx_resource_write_data( curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect );
91  SDL_assert ( ret == DISPMANX_SUCCESS );
92 
93  cursor->driverdata = curdata;
94 
95  return cursor;
96 
97 }
98 
99 /* Show the specified cursor, or hide if cursor is NULL */
100 static int
101 RPI_ShowCursor(SDL_Cursor * cursor)
102 {
103  int ret;
104  DISPMANX_UPDATE_HANDLE_T update;
105  RPI_CursorData *curdata;
106  VC_RECT_T src_rect, dst_rect;
107  SDL_Mouse *mouse;
108  SDL_VideoDisplay *display;
110  VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/, 0 /* mask */ };
111 
112  mouse = SDL_GetMouse();
113  if (mouse == NULL) {
114  return -1;
115  }
116 
117  if (cursor == NULL) {
118  /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */
119 
120  if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
121  curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
122  if (curdata->element > DISPMANX_NO_HANDLE) {
123  update = vc_dispmanx_update_start( 10 );
124  SDL_assert( update );
125  ret = vc_dispmanx_element_remove( update, curdata->element );
126  SDL_assert( ret == DISPMANX_SUCCESS );
127  ret = vc_dispmanx_update_submit_sync( update );
128  SDL_assert( ret == DISPMANX_SUCCESS );
129  curdata->element = DISPMANX_NO_HANDLE;
130  }
131  }
132  return 0;
133  }
134 
135  curdata = (RPI_CursorData *) cursor->driverdata;
136  if (curdata == NULL) {
137  return -1;
138  }
139 
140  if (mouse->focus == NULL) {
141  return -1;
142  }
143 
144  display = SDL_GetDisplayForWindow(mouse->focus);
145  if (display == NULL) {
146  return -1;
147  }
148 
149  data = (SDL_DisplayData*) display->driverdata;
150  if (data == NULL) {
151  return -1;
152  }
153 
154  if (curdata->element == DISPMANX_NO_HANDLE) {
155  vc_dispmanx_rect_set( &src_rect, 0, 0, curdata->w << 16, curdata->h << 16 );
156  vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
157 
158  update = vc_dispmanx_update_start( 10 );
159  SDL_assert( update );
160 
161  curdata->element = vc_dispmanx_element_add( update,
162  data->dispman_display,
163  SDL_RPI_MOUSELAYER, // layer
164  &dst_rect,
165  curdata->resource,
166  &src_rect,
167  DISPMANX_PROTECTION_NONE,
168  &alpha,
169  DISPMANX_NO_HANDLE, // clamp
170  VC_IMAGE_ROT0 );
171  SDL_assert( curdata->element > DISPMANX_NO_HANDLE);
172  ret = vc_dispmanx_update_submit_sync( update );
173  SDL_assert( ret == DISPMANX_SUCCESS );
174  }
175 
176  return 0;
177 }
178 
179 /* Free a window manager cursor */
180 static void
181 RPI_FreeCursor(SDL_Cursor * cursor)
182 {
183  int ret;
184  DISPMANX_UPDATE_HANDLE_T update;
185  RPI_CursorData *curdata;
186 
187  if (cursor != NULL) {
188  curdata = (RPI_CursorData *) cursor->driverdata;
189 
190  if (curdata != NULL) {
191  if (curdata->element != DISPMANX_NO_HANDLE) {
192  update = vc_dispmanx_update_start( 10 );
193  SDL_assert( update );
194  ret = vc_dispmanx_element_remove( update, curdata->element );
195  SDL_assert( ret == DISPMANX_SUCCESS );
196  ret = vc_dispmanx_update_submit_sync( update );
197  SDL_assert( ret == DISPMANX_SUCCESS );
198  }
199 
200  if (curdata->resource != DISPMANX_NO_HANDLE) {
201  ret = vc_dispmanx_resource_delete( curdata->resource );
202  SDL_assert( ret == DISPMANX_SUCCESS );
203  }
204 
205  SDL_free(cursor->driverdata);
206  }
207  SDL_free(cursor);
208  }
209 }
210 
211 /* Warp the mouse to (x,y) */
212 static void
213 RPI_WarpMouse(SDL_Window * window, int x, int y)
214 {
215  RPI_WarpMouseGlobal(x, y);
216 }
217 
218 /* Warp the mouse to (x,y) */
219 static int
220 RPI_WarpMouseGlobal(int x, int y)
221 {
222  RPI_CursorData *curdata;
223  DISPMANX_UPDATE_HANDLE_T update;
224  VC_RECT_T dst_rect;
225  SDL_Mouse *mouse = SDL_GetMouse();
226 
227  if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
228  curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
229  if (curdata->element != DISPMANX_NO_HANDLE) {
230  int ret;
231  update = vc_dispmanx_update_start( 10 );
232  SDL_assert( update );
233  vc_dispmanx_rect_set( &dst_rect, x, y, curdata->w, curdata->h);
234  ret = vc_dispmanx_element_change_attributes(
235  update,
236  curdata->element,
237  ELEMENT_CHANGE_DEST_RECT,
238  0,
239  0,
240  &dst_rect,
241  NULL,
242  DISPMANX_NO_HANDLE,
243  DISPMANX_NO_ROTATE);
244  SDL_assert( ret == DISPMANX_SUCCESS );
245  /* Submit asynchronously, otherwise the peformance suffers a lot */
246  ret = vc_dispmanx_update_submit( update, 0, NULL );
247  SDL_assert( ret == DISPMANX_SUCCESS );
248  return (ret == DISPMANX_SUCCESS) ? 0 : -1;
249  }
250  }
251 
252  return -1; /* !!! FIXME: this should SDL_SetError() somewhere. */
253 }
254 
255 void
257 {
258  /* FIXME: Using UDEV it should be possible to scan all mice
259  * but there's no point in doing so as there's no multimice support...yet!
260  */
261  SDL_Mouse *mouse = SDL_GetMouse();
262 
263  mouse->CreateCursor = RPI_CreateCursor;
264  mouse->ShowCursor = RPI_ShowCursor;
265  mouse->MoveCursor = RPI_MoveCursor;
266  mouse->FreeCursor = RPI_FreeCursor;
267  mouse->WarpMouse = RPI_WarpMouse;
268  mouse->WarpMouseGlobal = RPI_WarpMouseGlobal;
269 
270  SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
271 }
272 
273 void
275 {
276 
277 }
278 
279 /* This is called when a mouse motion event occurs */
280 static void
281 RPI_MoveCursor(SDL_Cursor * cursor)
282 {
283  SDL_Mouse *mouse = SDL_GetMouse();
284  RPI_WarpMouse(mouse->focus, mouse->x, mouse->y);
285 }
286 
287 #endif /* SDL_VIDEO_DRIVER_RPI */
288 
289 /* 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
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
#define SDL_RPI_MOUSELAYER
Definition: SDL_rpivideo.h:54
SDL_Window * focus
Definition: SDL_mouse_c.h:77
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 DEFAULT_CHOTY
#define DEFAULT_CHOTX
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
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)
void * pixels
Definition: SDL_surface.h:75
#define _THIS
void SDL_free(void *mem)
DISPMANX_DISPLAY_HANDLE_T dispman_display
Definition: SDL_rpivideo.h:41
#define DEFAULT_CHEIGHT
SDL_Cursor * cursor
Definition: testwm2.c:40
void SDL_SetDefaultCursor(SDL_Cursor *cursor)
Definition: SDL_mouse.c:55
int(* WarpMouseGlobal)(int x, int y)
Definition: SDL_mouse_c.h:64
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
SDL_PixelFormat * format
Definition: SDL_surface.h:72
static const unsigned char default_cmask[]
#define SDL_CreateCursor
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1039
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)