src/video/raspberry/SDL_rpimouse.c
author Sam Lantinga
Sat, 02 Jan 2016 10:10:34 -0800
changeset 9998 f67cf37e9cd4
parent 9808 64c8ca7fcf16
child 10101 075d70623646
permissions -rw-r--r--
Updated copyright to 2016
gabomdq@7753
     1
/*
gabomdq@7753
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
gabomdq@7753
     4
gabomdq@7753
     5
  This software is provided 'as-is', without any express or implied
gabomdq@7753
     6
  warranty.  In no event will the authors be held liable for any damages
gabomdq@7753
     7
  arising from the use of this software.
gabomdq@7753
     8
gabomdq@7753
     9
  Permission is granted to anyone to use this software for any purpose,
gabomdq@7753
    10
  including commercial applications, and to alter it and redistribute it
gabomdq@7753
    11
  freely, subject to the following restrictions:
gabomdq@7753
    12
gabomdq@7753
    13
  1. The origin of this software must not be misrepresented; you must not
gabomdq@7753
    14
     claim that you wrote the original software. If you use this software
gabomdq@7753
    15
     in a product, an acknowledgment in the product documentation would be
gabomdq@7753
    16
     appreciated but is not required.
gabomdq@7753
    17
  2. Altered source versions must be plainly marked as such, and must not be
gabomdq@7753
    18
     misrepresented as being the original software.
gabomdq@7753
    19
  3. This notice may not be removed or altered from any source distribution.
gabomdq@7753
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
gabomdq@7753
    22
gabomdq@7753
    23
#if SDL_VIDEO_DRIVER_RPI
gabomdq@7753
    24
gabomdq@7753
    25
#include "SDL_assert.h"
gabomdq@7753
    26
#include "SDL_surface.h"
gabomdq@7753
    27
gabomdq@7753
    28
#include "SDL_rpivideo.h"
gabomdq@7753
    29
#include "SDL_rpimouse.h"
gabomdq@7753
    30
gabomdq@7753
    31
#include "../SDL_sysvideo.h"
gabomdq@7753
    32
#include "../../events/SDL_mouse_c.h"
gabomdq@7753
    33
#include "../../events/default_cursor.h"
gabomdq@7753
    34
gabomdq@7753
    35
/* Copied from vc_vchi_dispmanx.h which is bugged and tries to include a non existing file */
gabomdq@7753
    36
/* Attributes changes flag mask */
gabomdq@7753
    37
#define ELEMENT_CHANGE_LAYER          (1<<0)
gabomdq@7753
    38
#define ELEMENT_CHANGE_OPACITY        (1<<1)
gabomdq@7753
    39
#define ELEMENT_CHANGE_DEST_RECT      (1<<2)
gabomdq@7753
    40
#define ELEMENT_CHANGE_SRC_RECT       (1<<3)
gabomdq@7753
    41
#define ELEMENT_CHANGE_MASK_RESOURCE  (1<<4)
gabomdq@7753
    42
#define ELEMENT_CHANGE_TRANSFORM      (1<<5)
gabomdq@7753
    43
/* End copied from vc_vchi_dispmanx.h */
gabomdq@7753
    44
gabomdq@7753
    45
static SDL_Cursor *RPI_CreateDefaultCursor(void);
gabomdq@7753
    46
static SDL_Cursor *RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
gabomdq@7753
    47
static int RPI_ShowCursor(SDL_Cursor * cursor);
gabomdq@7753
    48
static void RPI_MoveCursor(SDL_Cursor * cursor);
gabomdq@7753
    49
static void RPI_FreeCursor(SDL_Cursor * cursor);
gabomdq@7753
    50
static void RPI_WarpMouse(SDL_Window * window, int x, int y);
icculus@9808
    51
static int RPI_WarpMouseGlobal(int x, int y);
gabomdq@7753
    52
gabomdq@7753
    53
static SDL_Cursor *
gabomdq@7753
    54
RPI_CreateDefaultCursor(void)
gabomdq@7753
    55
{
gabomdq@7753
    56
    return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
gabomdq@7753
    57
}
gabomdq@7753
    58
gabomdq@7753
    59
/* Create a cursor from a surface */
gabomdq@7753
    60
static SDL_Cursor *
gabomdq@7753
    61
RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
gabomdq@7753
    62
{
gabomdq@7753
    63
    RPI_CursorData *curdata;
gabomdq@7753
    64
    SDL_Cursor *cursor;
gabomdq@7753
    65
    int ret;
gabomdq@7753
    66
    VC_RECT_T dst_rect;
gabomdq@7753
    67
    Uint32 dummy;
gabomdq@7753
    68
        
gabomdq@7753
    69
    SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
gabomdq@7753
    70
    SDL_assert(surface->pitch == surface->w * 4);
gabomdq@7753
    71
    
gabomdq@7753
    72
    cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
gabomdq@7753
    73
    curdata = (RPI_CursorData *) SDL_calloc(1, sizeof(*curdata));
gabomdq@7753
    74
gabomdq@7753
    75
    curdata->hot_x = hot_x;
gabomdq@7753
    76
    curdata->hot_y = hot_y;
gabomdq@7753
    77
    curdata->w = surface->w;
gabomdq@7753
    78
    curdata->h = surface->h;
gabomdq@7753
    79
    
gabomdq@7753
    80
    /* This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess */
gabomdq@7753
    81
    curdata->resource = vc_dispmanx_resource_create( VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy );
gabomdq@7753
    82
    SDL_assert(curdata->resource);
gabomdq@7753
    83
    vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
gabomdq@7753
    84
    /* A note from Weston: 
gabomdq@7753
    85
     * vc_dispmanx_resource_write_data() ignores ifmt,
gabomdq@7753
    86
     * rect.x, rect.width, and uses stride only for computing
gabomdq@7753
    87
     * the size of the transfer as rect.height * stride.
gabomdq@7753
    88
     * Therefore we can only write rows starting at x=0.
gabomdq@7753
    89
     */
gabomdq@7753
    90
    ret = vc_dispmanx_resource_write_data( curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect );
gabomdq@7753
    91
    SDL_assert ( ret == DISPMANX_SUCCESS );
gabomdq@7753
    92
    
gabomdq@7753
    93
    cursor->driverdata = curdata;
gabomdq@7753
    94
    
gabomdq@7753
    95
    return cursor;
gabomdq@7753
    96
gabomdq@7753
    97
}
gabomdq@7753
    98
gabomdq@7753
    99
/* Show the specified cursor, or hide if cursor is NULL */
gabomdq@7753
   100
static int
gabomdq@7753
   101
RPI_ShowCursor(SDL_Cursor * cursor)
gabomdq@7753
   102
{
gabomdq@7753
   103
    int ret;
gabomdq@7753
   104
    DISPMANX_UPDATE_HANDLE_T update;
gabomdq@7753
   105
    RPI_CursorData *curdata;
gabomdq@7753
   106
    VC_RECT_T src_rect, dst_rect;
gabomdq@7753
   107
    SDL_Mouse *mouse;
gabomdq@7753
   108
    SDL_VideoDisplay *display;
gabomdq@7753
   109
    SDL_DisplayData *data;
gabomdq@7753
   110
    VC_DISPMANX_ALPHA_T alpha = {  DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/,  0 /* mask */ };
gabomdq@7753
   111
    
gabomdq@7753
   112
    mouse = SDL_GetMouse();
gabomdq@7753
   113
    if (mouse == NULL) {
gabomdq@7753
   114
        return -1;
gabomdq@7753
   115
    }
gabomdq@7753
   116
    
gabomdq@7753
   117
    if (cursor == NULL) {
gabomdq@7753
   118
        /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */
gabomdq@7753
   119
gabomdq@7753
   120
        if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
gabomdq@7753
   121
            curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
gabomdq@7753
   122
            if (curdata->element > DISPMANX_NO_HANDLE) {
gabomdq@7753
   123
                update = vc_dispmanx_update_start( 10 );
gabomdq@7753
   124
                SDL_assert( update );
gabomdq@7753
   125
                ret = vc_dispmanx_element_remove( update, curdata->element );
gabomdq@7753
   126
                SDL_assert( ret == DISPMANX_SUCCESS );
gabomdq@7753
   127
                ret = vc_dispmanx_update_submit_sync( update );
gabomdq@7753
   128
                SDL_assert( ret == DISPMANX_SUCCESS );
gabomdq@7753
   129
                curdata->element = DISPMANX_NO_HANDLE;
gabomdq@7753
   130
            }
gabomdq@7753
   131
        }
gabomdq@7753
   132
        return 0;
gabomdq@7753
   133
    }
gabomdq@7753
   134
    
gabomdq@7753
   135
    curdata = (RPI_CursorData *) cursor->driverdata;
gabomdq@7753
   136
    if (curdata == NULL) {
gabomdq@7753
   137
        return -1;
gabomdq@7753
   138
    }
gabomdq@7753
   139
    
gabomdq@7753
   140
    if (mouse->focus == NULL) {
gabomdq@7753
   141
        return -1;
gabomdq@7753
   142
    }
gabomdq@7753
   143
    
gabomdq@7753
   144
    display = SDL_GetDisplayForWindow(mouse->focus);
gabomdq@7753
   145
    if (display == NULL) {
gabomdq@7753
   146
        return -1;
gabomdq@7753
   147
    }
gabomdq@7753
   148
    
gabomdq@7753
   149
    data = (SDL_DisplayData*) display->driverdata;
gabomdq@7753
   150
    if (data == NULL) {
gabomdq@7753
   151
        return -1;
gabomdq@7753
   152
    }
gabomdq@7753
   153
    
gabomdq@7753
   154
    if (curdata->element == DISPMANX_NO_HANDLE) {
gabomdq@7753
   155
        vc_dispmanx_rect_set( &src_rect, 0, 0, curdata->w << 16, curdata->h << 16 );
gabomdq@7753
   156
        vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
gabomdq@7753
   157
        
gabomdq@7753
   158
        update = vc_dispmanx_update_start( 10 );
gabomdq@7753
   159
        SDL_assert( update );
gabomdq@7753
   160
gabomdq@7753
   161
        curdata->element = vc_dispmanx_element_add( update,
gabomdq@7753
   162
                                                    data->dispman_display,
gabomdq@7753
   163
                                                    SDL_RPI_MOUSELAYER, // layer
gabomdq@7753
   164
                                                    &dst_rect,
gabomdq@7753
   165
                                                    curdata->resource,
gabomdq@7753
   166
                                                    &src_rect,
gabomdq@7753
   167
                                                    DISPMANX_PROTECTION_NONE,
gabomdq@7753
   168
                                                    &alpha,
gabomdq@7753
   169
                                                    DISPMANX_NO_HANDLE, // clamp
gabomdq@7753
   170
                                                    VC_IMAGE_ROT0 );
gabomdq@7753
   171
        SDL_assert( curdata->element > DISPMANX_NO_HANDLE);
gabomdq@7753
   172
        ret = vc_dispmanx_update_submit_sync( update );
gabomdq@7753
   173
        SDL_assert( ret == DISPMANX_SUCCESS );
gabomdq@7753
   174
    }
gabomdq@7753
   175
    
gabomdq@7753
   176
    return 0;
gabomdq@7753
   177
}
gabomdq@7753
   178
gabomdq@7753
   179
/* Free a window manager cursor */
gabomdq@7753
   180
static void
gabomdq@7753
   181
RPI_FreeCursor(SDL_Cursor * cursor)
gabomdq@7753
   182
{
gabomdq@7753
   183
    int ret;
gabomdq@7753
   184
    DISPMANX_UPDATE_HANDLE_T update;
gabomdq@7753
   185
    RPI_CursorData *curdata;
gabomdq@7753
   186
    
gabomdq@7753
   187
    if (cursor != NULL) {
gabomdq@7753
   188
        curdata = (RPI_CursorData *) cursor->driverdata;
gabomdq@7753
   189
        
gabomdq@7753
   190
        if (curdata != NULL) {
gabomdq@7753
   191
            if (curdata->element != DISPMANX_NO_HANDLE) {
gabomdq@7753
   192
                update = vc_dispmanx_update_start( 10 );
gabomdq@7753
   193
                SDL_assert( update );
gabomdq@7753
   194
                ret = vc_dispmanx_element_remove( update, curdata->element );
gabomdq@7753
   195
                SDL_assert( ret == DISPMANX_SUCCESS );
gabomdq@7753
   196
                ret = vc_dispmanx_update_submit_sync( update );
gabomdq@7753
   197
                SDL_assert( ret == DISPMANX_SUCCESS );
gabomdq@7753
   198
            }
gabomdq@7753
   199
            
gabomdq@7753
   200
            if (curdata->resource != DISPMANX_NO_HANDLE) {
gabomdq@7753
   201
                ret = vc_dispmanx_resource_delete( curdata->resource );
gabomdq@7753
   202
                SDL_assert( ret == DISPMANX_SUCCESS );
gabomdq@7753
   203
            }
gabomdq@7753
   204
        
gabomdq@7753
   205
            SDL_free(cursor->driverdata);
gabomdq@7753
   206
        }
gabomdq@7753
   207
        SDL_free(cursor);
gabomdq@7753
   208
    }
gabomdq@7753
   209
}
gabomdq@7753
   210
gabomdq@7753
   211
/* Warp the mouse to (x,y) */
gabomdq@7753
   212
static void
gabomdq@7753
   213
RPI_WarpMouse(SDL_Window * window, int x, int y)
gabomdq@7753
   214
{
slouken@8815
   215
    RPI_WarpMouseGlobal(x, y);
slouken@8815
   216
}
slouken@8815
   217
slouken@8815
   218
/* Warp the mouse to (x,y) */
icculus@9807
   219
static int
slouken@8815
   220
RPI_WarpMouseGlobal(int x, int y)
slouken@8815
   221
{
gabomdq@7753
   222
    RPI_CursorData *curdata;
gabomdq@7753
   223
    DISPMANX_UPDATE_HANDLE_T update;
gabomdq@7753
   224
    VC_RECT_T dst_rect;
gabomdq@7753
   225
    SDL_Mouse *mouse = SDL_GetMouse();
gabomdq@7753
   226
    
gabomdq@7753
   227
    if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
gabomdq@7753
   228
        curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
gabomdq@7753
   229
        if (curdata->element != DISPMANX_NO_HANDLE) {
icculus@9807
   230
            int ret;
gabomdq@7753
   231
            update = vc_dispmanx_update_start( 10 );
gabomdq@7753
   232
            SDL_assert( update );
gabomdq@7753
   233
            vc_dispmanx_rect_set( &dst_rect, x, y, curdata->w, curdata->h);
gabomdq@7753
   234
            ret = vc_dispmanx_element_change_attributes(
gabomdq@7753
   235
                update,
gabomdq@7753
   236
                curdata->element,
gabomdq@7753
   237
                ELEMENT_CHANGE_DEST_RECT,
gabomdq@7753
   238
                0,
gabomdq@7753
   239
                0,
gabomdq@7753
   240
                &dst_rect,
gabomdq@7753
   241
                NULL,
gabomdq@7753
   242
                DISPMANX_NO_HANDLE,
gabomdq@7753
   243
                DISPMANX_NO_ROTATE);
gabomdq@7753
   244
            SDL_assert( ret == DISPMANX_SUCCESS );
gabomdq@7753
   245
            /* Submit asynchronously, otherwise the peformance suffers a lot */
gabomdq@7753
   246
            ret = vc_dispmanx_update_submit( update, 0, NULL );
gabomdq@7753
   247
            SDL_assert( ret == DISPMANX_SUCCESS );
icculus@9807
   248
            return (ret == DISPMANX_SUCCESS) ? 0 : -1;
gabomdq@7753
   249
        }
gabomdq@7753
   250
    }    
icculus@9807
   251
icculus@9807
   252
    return -1;  /* !!! FIXME: this should SDL_SetError() somewhere. */
gabomdq@7753
   253
}
gabomdq@7753
   254
gabomdq@7753
   255
void
gabomdq@7753
   256
RPI_InitMouse(_THIS)
gabomdq@7753
   257
{
gabomdq@7753
   258
    /* FIXME: Using UDEV it should be possible to scan all mice 
gabomdq@7753
   259
     * but there's no point in doing so as there's no multimice support...yet!
gabomdq@7753
   260
     */
gabomdq@7753
   261
    SDL_Mouse *mouse = SDL_GetMouse();
gabomdq@7753
   262
gabomdq@7753
   263
    mouse->CreateCursor = RPI_CreateCursor;
gabomdq@7753
   264
    mouse->ShowCursor = RPI_ShowCursor;
gabomdq@7753
   265
    mouse->MoveCursor = RPI_MoveCursor;
gabomdq@7753
   266
    mouse->FreeCursor = RPI_FreeCursor;
gabomdq@7753
   267
    mouse->WarpMouse = RPI_WarpMouse;
slouken@8815
   268
    mouse->WarpMouseGlobal = RPI_WarpMouseGlobal;
gabomdq@7753
   269
gabomdq@7753
   270
    SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
gabomdq@7753
   271
}
gabomdq@7753
   272
gabomdq@7753
   273
void
gabomdq@7753
   274
RPI_QuitMouse(_THIS)
gabomdq@7753
   275
{
gabomdq@7753
   276
    
gabomdq@7753
   277
}
gabomdq@7753
   278
gabomdq@7753
   279
/* This is called when a mouse motion event occurs */
gabomdq@7753
   280
static void
gabomdq@7753
   281
RPI_MoveCursor(SDL_Cursor * cursor)
gabomdq@7753
   282
{
gabomdq@7753
   283
    SDL_Mouse *mouse = SDL_GetMouse();
gabomdq@7753
   284
    RPI_WarpMouse(mouse->focus, mouse->x, mouse->y);
gabomdq@7753
   285
}
gabomdq@7753
   286
gabomdq@7753
   287
#endif /* SDL_VIDEO_DRIVER_RPI */
gabomdq@7753
   288
gabomdq@7753
   289
/* vi: set ts=4 sw=4 expandtab: */