SDL_rpimouse.c (9737B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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 45static SDL_Cursor *RPI_CreateDefaultCursor(void); 46static SDL_Cursor *RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y); 47static int RPI_ShowCursor(SDL_Cursor * cursor); 48static void RPI_MoveCursor(SDL_Cursor * cursor); 49static void RPI_FreeCursor(SDL_Cursor * cursor); 50static void RPI_WarpMouse(SDL_Window * window, int x, int y); 51static void RPI_WarpMouseGlobal(int x, int y); 52 53static SDL_Cursor * 54RPI_CreateDefaultCursor(void) 55{ 56 return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY); 57} 58 59/* Create a cursor from a surface */ 60static SDL_Cursor * 61RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) 62{ 63 RPI_CursorData *curdata; 64 SDL_Cursor *cursor; 65 int ret; 66 VC_RECT_T dst_rect; 67 Uint32 dummy; 68 69 SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888); 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 */ 100static int 101RPI_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; 109 SDL_DisplayData *data; 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 */ 180static void 181RPI_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) */ 212static void 213RPI_WarpMouse(SDL_Window * window, int x, int y) 214{ 215 RPI_WarpMouseGlobal(x, y); 216} 217 218/* Warp the mouse to (x,y) */ 219static void 220RPI_WarpMouseGlobal(int x, int y) 221{ 222 RPI_CursorData *curdata; 223 DISPMANX_UPDATE_HANDLE_T update; 224 int ret; 225 VC_RECT_T dst_rect; 226 SDL_Mouse *mouse = SDL_GetMouse(); 227 228 if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) { 229 curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata; 230 if (curdata->element != DISPMANX_NO_HANDLE) { 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 } 249 } 250} 251 252void 253RPI_InitMouse(_THIS) 254{ 255 /* FIXME: Using UDEV it should be possible to scan all mice 256 * but there's no point in doing so as there's no multimice support...yet! 257 */ 258 SDL_Mouse *mouse = SDL_GetMouse(); 259 260 mouse->CreateCursor = RPI_CreateCursor; 261 mouse->ShowCursor = RPI_ShowCursor; 262 mouse->MoveCursor = RPI_MoveCursor; 263 mouse->FreeCursor = RPI_FreeCursor; 264 mouse->WarpMouse = RPI_WarpMouse; 265 mouse->WarpMouseGlobal = RPI_WarpMouseGlobal; 266 267 SDL_SetDefaultCursor(RPI_CreateDefaultCursor()); 268} 269 270void 271RPI_QuitMouse(_THIS) 272{ 273 274} 275 276/* This is called when a mouse motion event occurs */ 277static void 278RPI_MoveCursor(SDL_Cursor * cursor) 279{ 280 SDL_Mouse *mouse = SDL_GetMouse(); 281 RPI_WarpMouse(mouse->focus, mouse->x, mouse->y); 282} 283 284#endif /* SDL_VIDEO_DRIVER_RPI */ 285 286/* vi: set ts=4 sw=4 expandtab: */