Atlas - SDL_rpimouse.c

Home / ext / SDL / src / video / raspberry Lines: 1 | Size: 10173 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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, (int)mouse->x - curdata->hot_x, (int)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 315
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.