src/video/raspberry/SDL_rpimouse.c
author Gabriel Jacobo <gabomdq@gmail.com>
Sat, 28 Sep 2013 13:28:19 -0300
changeset 7753 e4c38f17bfad
child 8093 b43765095a6f
permissions -rw-r--r--
Raspberry Pi support (also unified UDEV and EVDEV support)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_config.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 
    52 static SDL_Cursor *
    53 RPI_CreateDefaultCursor(void)
    54 {
    55     return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
    56 }
    57 
    58 /* Create a cursor from a surface */
    59 static SDL_Cursor *
    60 RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
    61 {
    62     RPI_CursorData *curdata;
    63     SDL_Cursor *cursor;
    64     int ret;
    65     VC_RECT_T dst_rect;
    66     Uint32 dummy;
    67         
    68     SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
    69     SDL_assert(surface->pitch == surface->w * 4);
    70     
    71     cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
    72     curdata = (RPI_CursorData *) SDL_calloc(1, sizeof(*curdata));
    73 
    74     curdata->hot_x = hot_x;
    75     curdata->hot_y = hot_y;
    76     curdata->w = surface->w;
    77     curdata->h = surface->h;
    78     
    79     /* This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess */
    80     curdata->resource = vc_dispmanx_resource_create( VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy );
    81     SDL_assert(curdata->resource);
    82     vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
    83     /* A note from Weston: 
    84      * vc_dispmanx_resource_write_data() ignores ifmt,
    85      * rect.x, rect.width, and uses stride only for computing
    86      * the size of the transfer as rect.height * stride.
    87      * Therefore we can only write rows starting at x=0.
    88      */
    89     ret = vc_dispmanx_resource_write_data( curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect );
    90     SDL_assert ( ret == DISPMANX_SUCCESS );
    91     
    92     cursor->driverdata = curdata;
    93     
    94     return cursor;
    95 
    96 }
    97 
    98 /* Show the specified cursor, or hide if cursor is NULL */
    99 static int
   100 RPI_ShowCursor(SDL_Cursor * cursor)
   101 {
   102     int ret;
   103     DISPMANX_UPDATE_HANDLE_T update;
   104     RPI_CursorData *curdata;
   105     VC_RECT_T src_rect, dst_rect;
   106     SDL_Mouse *mouse;
   107     SDL_VideoDisplay *display;
   108     SDL_DisplayData *data;
   109     VC_DISPMANX_ALPHA_T alpha = {  DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/,  0 /* mask */ };
   110     
   111     mouse = SDL_GetMouse();
   112     if (mouse == NULL) {
   113         return -1;
   114     }
   115     
   116     if (cursor == NULL) {
   117         /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */
   118 
   119         if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
   120             curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
   121             if (curdata->element > DISPMANX_NO_HANDLE) {
   122                 update = vc_dispmanx_update_start( 10 );
   123                 SDL_assert( update );
   124                 ret = vc_dispmanx_element_remove( update, curdata->element );
   125                 SDL_assert( ret == DISPMANX_SUCCESS );
   126                 ret = vc_dispmanx_update_submit_sync( update );
   127                 SDL_assert( ret == DISPMANX_SUCCESS );
   128                 curdata->element = DISPMANX_NO_HANDLE;
   129             }
   130         }
   131         return 0;
   132     }
   133     
   134     curdata = (RPI_CursorData *) cursor->driverdata;
   135     if (curdata == NULL) {
   136         return -1;
   137     }
   138     
   139     if (mouse->focus == NULL) {
   140         return -1;
   141     }
   142     
   143     display = SDL_GetDisplayForWindow(mouse->focus);
   144     if (display == NULL) {
   145         return -1;
   146     }
   147     
   148     data = (SDL_DisplayData*) display->driverdata;
   149     if (data == NULL) {
   150         return -1;
   151     }
   152     
   153     if (curdata->element == DISPMANX_NO_HANDLE) {
   154         vc_dispmanx_rect_set( &src_rect, 0, 0, curdata->w << 16, curdata->h << 16 );
   155         vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
   156         
   157         update = vc_dispmanx_update_start( 10 );
   158         SDL_assert( update );
   159 
   160         curdata->element = vc_dispmanx_element_add( update,
   161                                                     data->dispman_display,
   162                                                     SDL_RPI_MOUSELAYER, // layer
   163                                                     &dst_rect,
   164                                                     curdata->resource,
   165                                                     &src_rect,
   166                                                     DISPMANX_PROTECTION_NONE,
   167                                                     &alpha,
   168                                                     DISPMANX_NO_HANDLE, // clamp
   169                                                     VC_IMAGE_ROT0 );
   170         SDL_assert( curdata->element > DISPMANX_NO_HANDLE);
   171         ret = vc_dispmanx_update_submit_sync( update );
   172         SDL_assert( ret == DISPMANX_SUCCESS );
   173     }
   174     
   175     return 0;
   176 }
   177 
   178 /* Free a window manager cursor */
   179 static void
   180 RPI_FreeCursor(SDL_Cursor * cursor)
   181 {
   182     int ret;
   183     DISPMANX_UPDATE_HANDLE_T update;
   184     RPI_CursorData *curdata;
   185     
   186     if (cursor != NULL) {
   187         curdata = (RPI_CursorData *) cursor->driverdata;
   188         
   189         if (curdata != NULL) {
   190             if (curdata->element != DISPMANX_NO_HANDLE) {
   191                 update = vc_dispmanx_update_start( 10 );
   192                 SDL_assert( update );
   193                 ret = vc_dispmanx_element_remove( update, curdata->element );
   194                 SDL_assert( ret == DISPMANX_SUCCESS );
   195                 ret = vc_dispmanx_update_submit_sync( update );
   196                 SDL_assert( ret == DISPMANX_SUCCESS );
   197             }
   198             
   199             if (curdata->resource != DISPMANX_NO_HANDLE) {
   200                 ret = vc_dispmanx_resource_delete( curdata->resource );
   201                 SDL_assert( ret == DISPMANX_SUCCESS );
   202             }
   203         
   204             SDL_free(cursor->driverdata);
   205         }
   206         SDL_free(cursor);
   207     }
   208 }
   209 
   210 /* Warp the mouse to (x,y) */
   211 static void
   212 RPI_WarpMouse(SDL_Window * window, int x, int y)
   213 {
   214     RPI_CursorData *curdata;
   215     DISPMANX_UPDATE_HANDLE_T update;
   216     int ret;
   217     VC_RECT_T dst_rect;
   218     SDL_Mouse *mouse = SDL_GetMouse();
   219     
   220     if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
   221         curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
   222         if (curdata->element != DISPMANX_NO_HANDLE) {
   223             update = vc_dispmanx_update_start( 10 );
   224             SDL_assert( update );
   225             vc_dispmanx_rect_set( &dst_rect, x, y, curdata->w, curdata->h);
   226             ret = vc_dispmanx_element_change_attributes(
   227                 update,
   228                 curdata->element,
   229                 ELEMENT_CHANGE_DEST_RECT,
   230                 0,
   231                 0,
   232                 &dst_rect,
   233                 NULL,
   234                 DISPMANX_NO_HANDLE,
   235                 DISPMANX_NO_ROTATE);
   236             SDL_assert( ret == DISPMANX_SUCCESS );
   237             /* Submit asynchronously, otherwise the peformance suffers a lot */
   238             ret = vc_dispmanx_update_submit( update, 0, NULL );
   239             SDL_assert( ret == DISPMANX_SUCCESS );
   240         }
   241     }    
   242 }
   243 
   244 void
   245 RPI_InitMouse(_THIS)
   246 {
   247     /* FIXME: Using UDEV it should be possible to scan all mice 
   248      * but there's no point in doing so as there's no multimice support...yet!
   249      */
   250     SDL_Mouse *mouse = SDL_GetMouse();
   251 
   252     mouse->CreateCursor = RPI_CreateCursor;
   253     mouse->ShowCursor = RPI_ShowCursor;
   254     mouse->MoveCursor = RPI_MoveCursor;
   255     mouse->FreeCursor = RPI_FreeCursor;
   256     mouse->WarpMouse = RPI_WarpMouse;
   257 
   258     SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
   259 }
   260 
   261 void
   262 RPI_QuitMouse(_THIS)
   263 {
   264     
   265 }
   266 
   267 /* This is called when a mouse motion event occurs */
   268 static void
   269 RPI_MoveCursor(SDL_Cursor * cursor)
   270 {
   271     SDL_Mouse *mouse = SDL_GetMouse();
   272     RPI_WarpMouse(mouse->focus, mouse->x, mouse->y);
   273 }
   274 
   275 #endif /* SDL_VIDEO_DRIVER_RPI */
   276 
   277 /* vi: set ts=4 sw=4 expandtab: */