cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_mouse.c (22199B)


      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/* General mouse handling code for SDL */
     24
     25#include "SDL_assert.h"
     26#include "SDL_hints.h"
     27#include "SDL_timer.h"
     28#include "SDL_events.h"
     29#include "SDL_events_c.h"
     30#include "default_cursor.h"
     31#include "../video/SDL_sysvideo.h"
     32
     33/* #define DEBUG_MOUSE */
     34
     35/* The mouse state */
     36static SDL_Mouse SDL_mouse;
     37static Uint32 SDL_double_click_time = 500;
     38static int SDL_double_click_radius = 1;
     39
     40static int
     41SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
     42
     43/* Public functions */
     44int
     45SDL_MouseInit(void)
     46{
     47    SDL_Mouse *mouse = SDL_GetMouse();
     48
     49    mouse->cursor_shown = SDL_TRUE;
     50
     51    return (0);
     52}
     53
     54void
     55SDL_SetDefaultCursor(SDL_Cursor * cursor)
     56{
     57    SDL_Mouse *mouse = SDL_GetMouse();
     58
     59    mouse->def_cursor = cursor;
     60    if (!mouse->cur_cursor) {
     61        SDL_SetCursor(cursor);
     62    }
     63}
     64
     65SDL_Mouse *
     66SDL_GetMouse(void)
     67{
     68    return &SDL_mouse;
     69}
     70
     71void
     72SDL_SetDoubleClickTime(Uint32 interval)
     73{
     74    SDL_double_click_time = interval;
     75}
     76
     77SDL_Window *
     78SDL_GetMouseFocus(void)
     79{
     80    SDL_Mouse *mouse = SDL_GetMouse();
     81
     82    return mouse->focus;
     83}
     84
     85void
     86SDL_ResetMouse(void)
     87{
     88    SDL_Mouse *mouse = SDL_GetMouse();
     89    Uint8 i;
     90
     91#ifdef DEBUG_MOUSE
     92    printf("Resetting mouse\n");
     93#endif
     94    for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
     95        if (mouse->buttonstate & SDL_BUTTON(i)) {
     96            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
     97        }
     98    }
     99    SDL_assert(mouse->buttonstate == 0);
    100}
    101
    102void
    103SDL_SetMouseFocus(SDL_Window * window)
    104{
    105    SDL_Mouse *mouse = SDL_GetMouse();
    106
    107    if (mouse->focus == window) {
    108        return;
    109    }
    110
    111    /* Actually, this ends up being a bad idea, because most operating
    112       systems have an implicit grab when you press the mouse button down
    113       so you can drag things out of the window and then get the mouse up
    114       when it happens.  So, #if 0...
    115    */
    116#if 0
    117    if (mouse->focus && !window) {
    118        /* We won't get anymore mouse messages, so reset mouse state */
    119        SDL_ResetMouse();
    120    }
    121#endif
    122
    123    /* See if the current window has lost focus */
    124    if (mouse->focus) {
    125        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
    126    }
    127
    128    mouse->focus = window;
    129
    130    if (mouse->focus) {
    131        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
    132    }
    133
    134    /* Update cursor visibility */
    135    SDL_SetCursor(NULL);
    136}
    137
    138/* Check to see if we need to synthesize focus events */
    139static SDL_bool
    140SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
    141{
    142    SDL_Mouse *mouse = SDL_GetMouse();
    143    SDL_bool inWindow = SDL_TRUE;
    144
    145    if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
    146        int w, h;
    147        SDL_GetWindowSize(window, &w, &h);
    148        if (x < 0 || y < 0 || x >= w || y >= h) {
    149            inWindow = SDL_FALSE;
    150        }
    151    }
    152
    153/* Linux doesn't give you mouse events outside your window unless you grab
    154   the pointer.
    155
    156   Windows doesn't give you mouse events outside your window unless you call
    157   SetCapture().
    158
    159   Both of these are slightly scary changes, so for now we'll punt and if the
    160   mouse leaves the window you'll lose mouse focus and reset button state.
    161*/
    162#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
    163    if (!inWindow && !buttonstate) {
    164#else
    165    if (!inWindow) {
    166#endif
    167        if (window == mouse->focus) {
    168#ifdef DEBUG_MOUSE
    169            printf("Mouse left window, synthesizing move & focus lost event\n");
    170#endif
    171            SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
    172            SDL_SetMouseFocus(NULL);
    173        }
    174        return SDL_FALSE;
    175    }
    176
    177    if (window != mouse->focus) {
    178#ifdef DEBUG_MOUSE
    179         printf("Mouse entered window, synthesizing focus gain & move event\n");
    180#endif
    181         SDL_SetMouseFocus(window);
    182         SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
    183    }
    184    return SDL_TRUE;
    185}
    186
    187int
    188SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
    189{
    190    if (window && !relative) {
    191        SDL_Mouse *mouse = SDL_GetMouse();
    192        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
    193            return 0;
    194        }
    195    }
    196
    197    return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
    198}
    199
    200static int
    201SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
    202{
    203    SDL_Mouse *mouse = SDL_GetMouse();
    204    int posted;
    205    int xrel;
    206    int yrel;
    207
    208    if (mouse->relative_mode_warp) {
    209        int center_x = 0, center_y = 0;
    210        SDL_GetWindowSize(window, &center_x, &center_y);
    211        center_x /= 2;
    212        center_y /= 2;
    213        if (x == center_x && y == center_y) {
    214            mouse->last_x = center_x;
    215            mouse->last_y = center_y;
    216            return 0;
    217        }
    218        SDL_WarpMouseInWindow(window, center_x, center_y);
    219    }
    220
    221    if (relative) {
    222        xrel = x;
    223        yrel = y;
    224        x = (mouse->last_x + xrel);
    225        y = (mouse->last_y + yrel);
    226    } else {
    227        xrel = x - mouse->last_x;
    228        yrel = y - mouse->last_y;
    229    }
    230
    231    /* Drop events that don't change state */
    232    if (!xrel && !yrel) {
    233#ifdef DEBUG_MOUSE
    234        printf("Mouse event didn't change state - dropped!\n");
    235#endif
    236        return 0;
    237    }
    238
    239    /* Update internal mouse coordinates */
    240    if (!mouse->relative_mode) {
    241        mouse->x = x;
    242        mouse->y = y;
    243    } else {
    244        mouse->x += xrel;
    245        mouse->y += yrel;
    246    }
    247
    248    /* make sure that the pointers find themselves inside the windows,
    249       unless we have the mouse captured. */
    250    if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
    251        int x_max = 0, y_max = 0;
    252
    253        // !!! FIXME: shouldn't this be (window) instead of (mouse->focus)?
    254        SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
    255        --x_max;
    256        --y_max;
    257
    258        if (mouse->x > x_max) {
    259            mouse->x = x_max;
    260        }
    261        if (mouse->x < 0) {
    262            mouse->x = 0;
    263        }
    264
    265        if (mouse->y > y_max) {
    266            mouse->y = y_max;
    267        }
    268        if (mouse->y < 0) {
    269            mouse->y = 0;
    270        }
    271    }
    272
    273    mouse->xdelta += xrel;
    274    mouse->ydelta += yrel;
    275
    276    /* Move the mouse cursor, if needed */
    277    if (mouse->cursor_shown && !mouse->relative_mode &&
    278        mouse->MoveCursor && mouse->cur_cursor) {
    279        mouse->MoveCursor(mouse->cur_cursor);
    280    }
    281
    282    /* Post the event, if desired */
    283    posted = 0;
    284    if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
    285        SDL_Event event;
    286        event.motion.type = SDL_MOUSEMOTION;
    287        event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
    288        event.motion.which = mouseID;
    289        event.motion.state = mouse->buttonstate;
    290        event.motion.x = mouse->x;
    291        event.motion.y = mouse->y;
    292        event.motion.xrel = xrel;
    293        event.motion.yrel = yrel;
    294        posted = (SDL_PushEvent(&event) > 0);
    295    }
    296    /* Use unclamped values if we're getting events outside the window */
    297    mouse->last_x = x;
    298    mouse->last_y = y;
    299    return posted;
    300}
    301
    302static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
    303{
    304    if (button >= mouse->num_clickstates) {
    305        int i, count = button + 1;
    306        mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
    307        if (!mouse->clickstate) {
    308            return NULL;
    309        }
    310
    311        for (i = mouse->num_clickstates; i < count; ++i) {
    312            SDL_zero(mouse->clickstate[i]);
    313        }
    314        mouse->num_clickstates = count;
    315    }
    316    return &mouse->clickstate[button];
    317}
    318
    319int
    320SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
    321{
    322    SDL_Mouse *mouse = SDL_GetMouse();
    323    int posted;
    324    Uint32 type;
    325    Uint32 buttonstate = mouse->buttonstate;
    326    SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
    327    Uint8 click_count;
    328
    329    /* Figure out which event to perform */
    330    switch (state) {
    331    case SDL_PRESSED:
    332        type = SDL_MOUSEBUTTONDOWN;
    333        buttonstate |= SDL_BUTTON(button);
    334        break;
    335    case SDL_RELEASED:
    336        type = SDL_MOUSEBUTTONUP;
    337        buttonstate &= ~SDL_BUTTON(button);
    338        break;
    339    default:
    340        /* Invalid state -- bail */
    341        return 0;
    342    }
    343
    344    /* We do this after calculating buttonstate so button presses gain focus */
    345    if (window && state == SDL_PRESSED) {
    346        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
    347    }
    348
    349    if (buttonstate == mouse->buttonstate) {
    350        /* Ignore this event, no state change */
    351        return 0;
    352    }
    353    mouse->buttonstate = buttonstate;
    354
    355    if (clickstate) {
    356        if (state == SDL_PRESSED) {
    357            Uint32 now = SDL_GetTicks();
    358
    359            if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
    360                SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
    361                SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
    362                clickstate->click_count = 0;
    363            }
    364            clickstate->last_timestamp = now;
    365            clickstate->last_x = mouse->x;
    366            clickstate->last_y = mouse->y;
    367            if (clickstate->click_count < 255) {
    368                ++clickstate->click_count;
    369            }
    370        }
    371        click_count = clickstate->click_count;
    372    } else {
    373        click_count = 1;
    374    }
    375
    376    /* Post the event, if desired */
    377    posted = 0;
    378    if (SDL_GetEventState(type) == SDL_ENABLE) {
    379        SDL_Event event;
    380        event.type = type;
    381        event.button.windowID = mouse->focus ? mouse->focus->id : 0;
    382        event.button.which = mouseID;
    383        event.button.state = state;
    384        event.button.button = button;
    385        event.button.clicks = click_count;
    386        event.button.x = mouse->x;
    387        event.button.y = mouse->y;
    388        posted = (SDL_PushEvent(&event) > 0);
    389    }
    390
    391    /* We do this after dispatching event so button releases can lose focus */
    392    if (window && state == SDL_RELEASED) {
    393        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
    394    }
    395
    396    return posted;
    397}
    398
    399int
    400SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y)
    401{
    402    SDL_Mouse *mouse = SDL_GetMouse();
    403    int posted;
    404
    405    if (window) {
    406        SDL_SetMouseFocus(window);
    407    }
    408
    409    if (!x && !y) {
    410        return 0;
    411    }
    412
    413    /* Post the event, if desired */
    414    posted = 0;
    415    if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
    416        SDL_Event event;
    417        event.type = SDL_MOUSEWHEEL;
    418        event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
    419        event.wheel.which = mouseID;
    420        event.wheel.x = x;
    421        event.wheel.y = y;
    422        posted = (SDL_PushEvent(&event) > 0);
    423    }
    424    return posted;
    425}
    426
    427void
    428SDL_MouseQuit(void)
    429{
    430    SDL_Cursor *cursor, *next;
    431    SDL_Mouse *mouse = SDL_GetMouse();
    432
    433    if (mouse->CaptureMouse) {
    434        SDL_CaptureMouse(SDL_FALSE);
    435    }
    436    SDL_SetRelativeMouseMode(SDL_FALSE);
    437    SDL_ShowCursor(1);
    438
    439    cursor = mouse->cursors;
    440    while (cursor) {
    441        next = cursor->next;
    442        SDL_FreeCursor(cursor);
    443        cursor = next;
    444    }
    445
    446    if (mouse->def_cursor && mouse->FreeCursor) {
    447        mouse->FreeCursor(mouse->def_cursor);
    448    }
    449
    450    if (mouse->clickstate) {
    451        SDL_free(mouse->clickstate);
    452    }
    453
    454    SDL_zerop(mouse);
    455}
    456
    457Uint32
    458SDL_GetMouseState(int *x, int *y)
    459{
    460    SDL_Mouse *mouse = SDL_GetMouse();
    461
    462    if (x) {
    463        *x = mouse->x;
    464    }
    465    if (y) {
    466        *y = mouse->y;
    467    }
    468    return mouse->buttonstate;
    469}
    470
    471Uint32
    472SDL_GetRelativeMouseState(int *x, int *y)
    473{
    474    SDL_Mouse *mouse = SDL_GetMouse();
    475
    476    if (x) {
    477        *x = mouse->xdelta;
    478    }
    479    if (y) {
    480        *y = mouse->ydelta;
    481    }
    482    mouse->xdelta = 0;
    483    mouse->ydelta = 0;
    484    return mouse->buttonstate;
    485}
    486
    487Uint32
    488SDL_GetGlobalMouseState(int *x, int *y)
    489{
    490    SDL_Mouse *mouse = SDL_GetMouse();
    491    int tmpx, tmpy;
    492
    493    /* make sure these are never NULL for the backend implementations... */
    494    if (!x) {
    495        x = &tmpx;
    496    }
    497    if (!y) {
    498        y = &tmpy;
    499    }
    500
    501    *x = *y = 0;
    502
    503    if (!mouse->GetGlobalMouseState) {
    504        SDL_assert(0 && "This should really be implemented for every target.");
    505        return 0;
    506    }
    507
    508    return mouse->GetGlobalMouseState(x, y);
    509}
    510
    511void
    512SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
    513{
    514    SDL_Mouse *mouse = SDL_GetMouse();
    515
    516    if (window == NULL) {
    517        window = mouse->focus;
    518    }
    519
    520    if (window == NULL) {
    521        return;
    522    }
    523
    524    if (mouse->WarpMouse) {
    525        mouse->WarpMouse(window, x, y);
    526    } else {
    527        SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
    528    }
    529}
    530
    531void
    532SDL_WarpMouseGlobal(int x, int y)
    533{
    534    SDL_Mouse *mouse = SDL_GetMouse();
    535
    536    if (mouse->WarpMouseGlobal) {
    537        mouse->WarpMouseGlobal(x, y);
    538    }
    539}
    540
    541static SDL_bool
    542ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
    543{
    544    const char *hint;
    545
    546    if (!mouse->SetRelativeMouseMode) {
    547        return SDL_TRUE;
    548    }
    549
    550    hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
    551    if (hint) {
    552        if (*hint == '0') {
    553            return SDL_FALSE;
    554        } else {
    555            return SDL_TRUE;
    556        }
    557    }
    558    return SDL_FALSE;
    559}
    560
    561int
    562SDL_SetRelativeMouseMode(SDL_bool enabled)
    563{
    564    SDL_Mouse *mouse = SDL_GetMouse();
    565    SDL_Window *focusWindow = SDL_GetKeyboardFocus();
    566
    567    if (enabled == mouse->relative_mode) {
    568        return 0;
    569    }
    570
    571    if (enabled && focusWindow) {
    572        /* Center it in the focused window to prevent clicks from going through
    573         * to background windows.
    574         */
    575        SDL_SetMouseFocus(focusWindow);
    576        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
    577    }
    578
    579    /* Set the relative mode */
    580    if (!enabled && mouse->relative_mode_warp) {
    581        mouse->relative_mode_warp = SDL_FALSE;
    582    } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
    583        mouse->relative_mode_warp = SDL_TRUE;
    584    } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
    585        if (enabled) {
    586            /* Fall back to warp mode if native relative mode failed */
    587            mouse->relative_mode_warp = SDL_TRUE;
    588        }
    589    }
    590    mouse->relative_mode = enabled;
    591
    592    if (mouse->focus) {
    593        SDL_UpdateWindowGrab(mouse->focus);
    594
    595        /* Put the cursor back to where the application expects it */
    596        if (!enabled) {
    597            SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
    598        }
    599    }
    600
    601    /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
    602    SDL_FlushEvent(SDL_MOUSEMOTION);
    603
    604    /* Update cursor visibility */
    605    SDL_SetCursor(NULL);
    606
    607    return 0;
    608}
    609
    610SDL_bool
    611SDL_GetRelativeMouseMode()
    612{
    613    SDL_Mouse *mouse = SDL_GetMouse();
    614
    615    return mouse->relative_mode;
    616}
    617
    618int
    619SDL_CaptureMouse(SDL_bool enabled)
    620{
    621    SDL_Mouse *mouse = SDL_GetMouse();
    622    SDL_Window *focusWindow;
    623    SDL_bool isCaptured;
    624
    625    if (!mouse->CaptureMouse) {
    626        return SDL_Unsupported();
    627    }
    628
    629    focusWindow = SDL_GetKeyboardFocus();
    630
    631    isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
    632    if (isCaptured == enabled) {
    633        return 0;  /* already done! */
    634    }
    635
    636    if (enabled) {
    637        if (!focusWindow) {
    638            return SDL_SetError("No window has focus");
    639        } else if (mouse->CaptureMouse(focusWindow) == -1) {
    640            return -1;  /* CaptureMouse() should call SetError */
    641        }
    642        focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
    643    } else {
    644        if (mouse->CaptureMouse(NULL) == -1) {
    645            return -1;  /* CaptureMouse() should call SetError */
    646        }
    647        focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
    648    }
    649
    650    return 0;
    651}
    652
    653SDL_Cursor *
    654SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
    655                 int w, int h, int hot_x, int hot_y)
    656{
    657    SDL_Surface *surface;
    658    SDL_Cursor *cursor;
    659    int x, y;
    660    Uint32 *pixel;
    661    Uint8 datab = 0, maskb = 0;
    662    const Uint32 black = 0xFF000000;
    663    const Uint32 white = 0xFFFFFFFF;
    664    const Uint32 transparent = 0x00000000;
    665
    666    /* Make sure the width is a multiple of 8 */
    667    w = ((w + 7) & ~7);
    668
    669    /* Create the surface from a bitmap */
    670    surface = SDL_CreateRGBSurface(0, w, h, 32,
    671                                   0x00FF0000,
    672                                   0x0000FF00,
    673                                   0x000000FF,
    674                                   0xFF000000);
    675    if (!surface) {
    676        return NULL;
    677    }
    678    for (y = 0; y < h; ++y) {
    679        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
    680        for (x = 0; x < w; ++x) {
    681            if ((x % 8) == 0) {
    682                datab = *data++;
    683                maskb = *mask++;
    684            }
    685            if (maskb & 0x80) {
    686                *pixel++ = (datab & 0x80) ? black : white;
    687            } else {
    688                *pixel++ = (datab & 0x80) ? black : transparent;
    689            }
    690            datab <<= 1;
    691            maskb <<= 1;
    692        }
    693    }
    694
    695    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
    696
    697    SDL_FreeSurface(surface);
    698
    699    return cursor;
    700}
    701
    702SDL_Cursor *
    703SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
    704{
    705    SDL_Mouse *mouse = SDL_GetMouse();
    706    SDL_Surface *temp = NULL;
    707    SDL_Cursor *cursor;
    708
    709    if (!surface) {
    710        SDL_SetError("Passed NULL cursor surface");
    711        return NULL;
    712    }
    713
    714    if (!mouse->CreateCursor) {
    715        SDL_SetError("Cursors are not currently supported");
    716        return NULL;
    717    }
    718
    719    /* Sanity check the hot spot */
    720    if ((hot_x < 0) || (hot_y < 0) ||
    721        (hot_x >= surface->w) || (hot_y >= surface->h)) {
    722        SDL_SetError("Cursor hot spot doesn't lie within cursor");
    723        return NULL;
    724    }
    725
    726    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
    727        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
    728        if (!temp) {
    729            return NULL;
    730        }
    731        surface = temp;
    732    }
    733
    734    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
    735    if (cursor) {
    736        cursor->next = mouse->cursors;
    737        mouse->cursors = cursor;
    738    }
    739
    740    SDL_FreeSurface(temp);
    741
    742    return cursor;
    743}
    744
    745SDL_Cursor *
    746SDL_CreateSystemCursor(SDL_SystemCursor id)
    747{
    748    SDL_Mouse *mouse = SDL_GetMouse();
    749    SDL_Cursor *cursor;
    750
    751    if (!mouse->CreateSystemCursor) {
    752        SDL_SetError("CreateSystemCursor is not currently supported");
    753        return NULL;
    754    }
    755
    756    cursor = mouse->CreateSystemCursor(id);
    757    if (cursor) {
    758        cursor->next = mouse->cursors;
    759        mouse->cursors = cursor;
    760    }
    761
    762    return cursor;
    763}
    764
    765/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
    766   if this is desired for any reason.  This is used when setting
    767   the video mode and when the SDL window gains the mouse focus.
    768 */
    769void
    770SDL_SetCursor(SDL_Cursor * cursor)
    771{
    772    SDL_Mouse *mouse = SDL_GetMouse();
    773
    774    /* Set the new cursor */
    775    if (cursor) {
    776        /* Make sure the cursor is still valid for this mouse */
    777        if (cursor != mouse->def_cursor) {
    778            SDL_Cursor *found;
    779            for (found = mouse->cursors; found; found = found->next) {
    780                if (found == cursor) {
    781                    break;
    782                }
    783            }
    784            if (!found) {
    785                SDL_SetError("Cursor not associated with the current mouse");
    786                return;
    787            }
    788        }
    789        mouse->cur_cursor = cursor;
    790    } else {
    791        if (mouse->focus) {
    792            cursor = mouse->cur_cursor;
    793        } else {
    794            cursor = mouse->def_cursor;
    795        }
    796    }
    797
    798    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
    799        if (mouse->ShowCursor) {
    800            mouse->ShowCursor(cursor);
    801        }
    802    } else {
    803        if (mouse->ShowCursor) {
    804            mouse->ShowCursor(NULL);
    805        }
    806    }
    807}
    808
    809SDL_Cursor *
    810SDL_GetCursor(void)
    811{
    812    SDL_Mouse *mouse = SDL_GetMouse();
    813
    814    if (!mouse) {
    815        return NULL;
    816    }
    817    return mouse->cur_cursor;
    818}
    819
    820SDL_Cursor *
    821SDL_GetDefaultCursor(void)
    822{
    823    SDL_Mouse *mouse = SDL_GetMouse();
    824
    825    if (!mouse) {
    826        return NULL;
    827    }
    828    return mouse->def_cursor;
    829}
    830
    831void
    832SDL_FreeCursor(SDL_Cursor * cursor)
    833{
    834    SDL_Mouse *mouse = SDL_GetMouse();
    835    SDL_Cursor *curr, *prev;
    836
    837    if (!cursor) {
    838        return;
    839    }
    840
    841    if (cursor == mouse->def_cursor) {
    842        return;
    843    }
    844    if (cursor == mouse->cur_cursor) {
    845        SDL_SetCursor(mouse->def_cursor);
    846    }
    847
    848    for (prev = NULL, curr = mouse->cursors; curr;
    849         prev = curr, curr = curr->next) {
    850        if (curr == cursor) {
    851            if (prev) {
    852                prev->next = curr->next;
    853            } else {
    854                mouse->cursors = curr->next;
    855            }
    856
    857            if (mouse->FreeCursor) {
    858                mouse->FreeCursor(curr);
    859            }
    860            return;
    861        }
    862    }
    863}
    864
    865int
    866SDL_ShowCursor(int toggle)
    867{
    868    SDL_Mouse *mouse = SDL_GetMouse();
    869    SDL_bool shown;
    870
    871    if (!mouse) {
    872        return 0;
    873    }
    874
    875    shown = mouse->cursor_shown;
    876    if (toggle >= 0) {
    877        if (toggle) {
    878            mouse->cursor_shown = SDL_TRUE;
    879        } else {
    880            mouse->cursor_shown = SDL_FALSE;
    881        }
    882        if (mouse->cursor_shown != shown) {
    883            SDL_SetCursor(NULL);
    884        }
    885    }
    886    return shown;
    887}
    888
    889/* vi: set ts=4 sw=4 expandtab: */