summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c')
-rw-r--r--contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c
new file mode 100644
index 0000000..925b734
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/raspberry/SDL_rpimouse.c
@@ -0,0 +1,314 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_DRIVER_RPI
24
25#include "SDL_rpivideo.h"
26#include "SDL_rpimouse.h"
27
28#include "../SDL_sysvideo.h"
29#include "../../events/SDL_mouse_c.h"
30#include "../../events/default_cursor.h"
31
32// Copied from vc_vchi_dispmanx.h which is bugged and tries to include a non existing file
33// Attributes changes flag mask
34#define ELEMENT_CHANGE_LAYER (1 << 0)
35#define ELEMENT_CHANGE_OPACITY (1 << 1)
36#define ELEMENT_CHANGE_DEST_RECT (1 << 2)
37#define ELEMENT_CHANGE_SRC_RECT (1 << 3)
38#define ELEMENT_CHANGE_MASK_RESOURCE (1 << 4)
39#define ELEMENT_CHANGE_TRANSFORM (1 << 5)
40// End copied from vc_vchi_dispmanx.h
41
42static SDL_Cursor *RPI_CreateDefaultCursor(void);
43static SDL_Cursor *RPI_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y);
44static bool RPI_ShowCursor(SDL_Cursor *cursor);
45static bool RPI_MoveCursor(SDL_Cursor *cursor);
46static void RPI_FreeCursor(SDL_Cursor *cursor);
47
48static SDL_Cursor *global_cursor;
49
50static SDL_Cursor *RPI_CreateDefaultCursor(void)
51{
52 return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
53}
54
55// Create a cursor from a surface
56static SDL_Cursor *RPI_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
57{
58 int rc;
59 SDL_CursorData *curdata;
60 SDL_Cursor *cursor;
61 VC_RECT_T dst_rect;
62 Uint32 dummy;
63
64 SDL_assert(surface->format == SDL_PIXELFORMAT_ARGB8888);
65 SDL_assert(surface->pitch == surface->w * 4);
66
67 cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
68 if (!cursor) {
69 return NULL;
70 }
71 curdata = (SDL_CursorData *)SDL_calloc(1, sizeof(*curdata));
72 if (!curdata) {
73 SDL_free(cursor);
74 return NULL;
75 }
76
77 curdata->hot_x = hot_x;
78 curdata->hot_y = hot_y;
79 curdata->w = surface->w;
80 curdata->h = surface->h;
81
82 // This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess
83 curdata->resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy);
84 SDL_assert(curdata->resource);
85 vc_dispmanx_rect_set(&dst_rect, 0, 0, curdata->w, curdata->h);
86 /* A note from Weston:
87 * vc_dispmanx_resource_write_data() ignores ifmt,
88 * rect.x, rect.width, and uses stride only for computing
89 * the size of the transfer as rect.height * stride.
90 * Therefore we can only write rows starting at x=0.
91 */
92 rc = vc_dispmanx_resource_write_data(curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect);
93 SDL_assert(rc == DISPMANX_SUCCESS);
94
95 cursor->internal = curdata;
96
97 return cursor;
98}
99
100// Show the specified cursor, or hide if cursor is NULL
101static bool RPI_ShowCursor(SDL_Cursor *cursor)
102{
103 int rc;
104 DISPMANX_UPDATE_HANDLE_T update;
105 SDL_CursorData *curdata;
106 VC_RECT_T src_rect, dst_rect;
107 SDL_Mouse *mouse = SDL_GetMouse();
108 SDL_DisplayData *data;
109 VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */, 255 /*opacity 0->255*/, 0 /* mask */ };
110 uint32_t layer = SDL_RPI_MOUSELAYER;
111 const char *hint;
112
113 if (cursor != global_cursor) {
114 if (global_cursor) {
115 curdata = global_cursor->internal;
116 if (curdata && curdata->element > DISPMANX_NO_HANDLE) {
117 update = vc_dispmanx_update_start(0);
118 SDL_assert(update);
119 rc = vc_dispmanx_element_remove(update, curdata->element);
120 SDL_assert(rc == DISPMANX_SUCCESS);
121 rc = vc_dispmanx_update_submit_sync(update);
122 SDL_assert(rc == DISPMANX_SUCCESS);
123 curdata->element = DISPMANX_NO_HANDLE;
124 }
125 }
126 global_cursor = cursor;
127 }
128
129 if (!cursor) {
130 return true;
131 }
132
133 curdata = cursor->internal;
134 if (!curdata) {
135 return false;
136 }
137
138 if (!mouse->focus) {
139 return false;
140 }
141
142 data = SDL_GetDisplayDriverDataForWindow(mouse->focus);
143 if (!data) {
144 return false;
145 }
146
147 if (curdata->element == DISPMANX_NO_HANDLE) {
148 vc_dispmanx_rect_set(&src_rect, 0, 0, curdata->w << 16, curdata->h << 16);
149 vc_dispmanx_rect_set(&dst_rect, mouse->x - curdata->hot_x, mouse->y - curdata->hot_y, curdata->w, curdata->h);
150
151 update = vc_dispmanx_update_start(0);
152 SDL_assert(update);
153
154 hint = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER);
155 if (hint) {
156 layer = SDL_atoi(hint) + 1;
157 }
158
159 curdata->element = vc_dispmanx_element_add(update,
160 data->dispman_display,
161 layer,
162 &dst_rect,
163 curdata->resource,
164 &src_rect,
165 DISPMANX_PROTECTION_NONE,
166 &alpha,
167 DISPMANX_NO_HANDLE, // clamp
168 DISPMANX_NO_ROTATE);
169 SDL_assert(curdata->element > DISPMANX_NO_HANDLE);
170 rc = vc_dispmanx_update_submit_sync(update);
171 SDL_assert(rc == DISPMANX_SUCCESS);
172 }
173
174 return true;
175}
176
177// Free a window manager cursor
178static void RPI_FreeCursor(SDL_Cursor *cursor)
179{
180 int rc;
181 DISPMANX_UPDATE_HANDLE_T update;
182 SDL_CursorData *curdata;
183
184 if (cursor) {
185 curdata = cursor->internal;
186
187 if (curdata) {
188 if (curdata->element != DISPMANX_NO_HANDLE) {
189 update = vc_dispmanx_update_start(0);
190 SDL_assert(update);
191 rc = vc_dispmanx_element_remove(update, curdata->element);
192 SDL_assert(rc == DISPMANX_SUCCESS);
193 rc = vc_dispmanx_update_submit_sync(update);
194 SDL_assert(rc == DISPMANX_SUCCESS);
195 }
196
197 if (curdata->resource != DISPMANX_NO_HANDLE) {
198 rc = vc_dispmanx_resource_delete(curdata->resource);
199 SDL_assert(rc == DISPMANX_SUCCESS);
200 }
201
202 SDL_free(cursor->internal);
203 }
204 SDL_free(cursor);
205 if (cursor == global_cursor) {
206 global_cursor = NULL;
207 }
208 }
209}
210
211static bool RPI_WarpMouseGlobalGraphically(float x, float y)
212{
213 int rc;
214 SDL_CursorData *curdata;
215 DISPMANX_UPDATE_HANDLE_T update;
216 VC_RECT_T dst_rect;
217 VC_RECT_T src_rect;
218 SDL_Mouse *mouse = SDL_GetMouse();
219
220 if (!mouse || !mouse->cur_cursor || !mouse->cur_cursor->internal) {
221 return true;
222 }
223
224 curdata = mouse->cur_cursor->internal;
225 if (curdata->element == DISPMANX_NO_HANDLE) {
226 return true;
227 }
228
229 update = vc_dispmanx_update_start(0);
230 if (!update) {
231 return true;
232 }
233
234 src_rect.x = 0;
235 src_rect.y = 0;
236 src_rect.width = curdata->w << 16;
237 src_rect.height = curdata->h << 16;
238 dst_rect.x = (int)x - curdata->hot_x;
239 dst_rect.y = (int)y - curdata->hot_y;
240 dst_rect.width = curdata->w;
241 dst_rect.height = curdata->h;
242
243 rc = vc_dispmanx_element_change_attributes(
244 update,
245 curdata->element,
246 0,
247 0,
248 0,
249 &dst_rect,
250 &src_rect,
251 DISPMANX_NO_HANDLE,
252 DISPMANX_NO_ROTATE);
253 if (rc != DISPMANX_SUCCESS) {
254 return SDL_SetError("vc_dispmanx_element_change_attributes() failed");
255 }
256
257 // Submit asynchronously, otherwise the performance suffers a lot
258 rc = vc_dispmanx_update_submit(update, 0, NULL);
259 if (rc != DISPMANX_SUCCESS) {
260 return SDL_SetError("vc_dispmanx_update_submit() failed");
261 }
262 return true;
263}
264
265static bool RPI_WarpMouseGlobal(float x, float y)
266{
267 SDL_Mouse *mouse = SDL_GetMouse();
268
269 if (!mouse || !mouse->cur_cursor || !mouse->cur_cursor->internal) {
270 return true;
271 }
272
273 // Update internal mouse position.
274 SDL_SendMouseMotion(0, mouse->focus, SDL_GLOBAL_MOUSE_ID, false, x, y);
275
276 return RPI_WarpMouseGlobalGraphically(x, y);
277}
278
279static bool RPI_WarpMouse(SDL_Window *window, float x, float y)
280{
281 return RPI_WarpMouseGlobal(x, y);
282}
283
284void RPI_InitMouse(SDL_VideoDevice *_this)
285{
286 /* FIXME: Using UDEV it should be possible to scan all mice
287 * but there's no point in doing so as there's no multimice support...yet!
288 */
289 SDL_Mouse *mouse = SDL_GetMouse();
290
291 mouse->CreateCursor = RPI_CreateCursor;
292 mouse->ShowCursor = RPI_ShowCursor;
293 mouse->MoveCursor = RPI_MoveCursor;
294 mouse->FreeCursor = RPI_FreeCursor;
295 mouse->WarpMouse = RPI_WarpMouse;
296 mouse->WarpMouseGlobal = RPI_WarpMouseGlobal;
297
298 SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
299}
300
301void RPI_QuitMouse(SDL_VideoDevice *_this)
302{
303}
304
305// This is called when a mouse motion event occurs
306static bool RPI_MoveCursor(SDL_Cursor *cursor)
307{
308 SDL_Mouse *mouse = SDL_GetMouse();
309 /* We must NOT call SDL_SendMouseMotion() on the next call or we will enter recursivity,
310 * so we create a version of WarpMouseGlobal without it. */
311 return RPI_WarpMouseGlobalGraphically(mouse->x, mouse->y);
312}
313
314#endif // SDL_VIDEO_DRIVER_RPI