src/events/SDL_mouse.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 08 Nov 2012 02:26:40 -0800
changeset 6666 018f8019ce36
parent 6302 b0ae93a5b8d6
child 6667 243bfb5c31d6
permissions -rw-r--r--
Reset the mouse button state when losing mouse focus.
Implemented mouse focus handling entirely using mouse motion events, with SetCapture() semantics, as long as the windowing system continues to provide mouse events.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
slouken@1402
    21
#include "SDL_config.h"
slouken@0
    22
slouken@0
    23
/* General mouse handling code for SDL */
slouken@0
    24
slouken@6666
    25
#include "SDL_assert.h"
slouken@0
    26
#include "SDL_events.h"
slouken@0
    27
#include "SDL_events_c.h"
slouken@1895
    28
#include "default_cursor.h"
slouken@3685
    29
#include "../video/SDL_sysvideo.h"
slouken@0
    30
slouken@6666
    31
/*#define DEBUG_MOUSE*/
slouken@0
    32
slouken@5371
    33
/* The mouse state */
slouken@4465
    34
static SDL_Mouse SDL_mouse;
slouken@0
    35
slouken@0
    36
slouken@0
    37
/* Public functions */
slouken@1895
    38
int
slouken@1895
    39
SDL_MouseInit(void)
slouken@0
    40
{
slouken@5376
    41
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5376
    42
slouken@5376
    43
    mouse->cursor_shown = SDL_TRUE;
slouken@5376
    44
slouken@1895
    45
    return (0);
slouken@1123
    46
}
slouken@0
    47
slouken@5405
    48
void
slouken@5405
    49
SDL_SetDefaultCursor(SDL_Cursor * cursor)
slouken@5405
    50
{
slouken@5405
    51
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5405
    52
slouken@5405
    53
    mouse->def_cursor = cursor;
slouken@5405
    54
    if (!mouse->cur_cursor) {
slouken@5405
    55
        SDL_SetCursor(cursor);
slouken@5405
    56
    }
slouken@5405
    57
}
slouken@5405
    58
slouken@5371
    59
SDL_Mouse *
slouken@5371
    60
SDL_GetMouse(void)
slouken@5371
    61
{
slouken@5371
    62
    return &SDL_mouse;
slouken@5371
    63
}
slouken@5371
    64
slouken@4465
    65
SDL_Window *
slouken@4465
    66
SDL_GetMouseFocus(void)
slouken@2710
    67
{
slouken@5371
    68
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@2940
    69
slouken@4465
    70
    return mouse->focus;
slouken@0
    71
}
slouken@0
    72
slouken@1895
    73
void
slouken@6666
    74
SDL_ResetMouse(void)
slouken@6666
    75
{
slouken@6666
    76
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6666
    77
    Uint8 i;
slouken@6666
    78
slouken@6666
    79
#ifdef DEBUG_MOUSE
slouken@6666
    80
    printf("Resetting mouse\n");
slouken@6666
    81
#endif
slouken@6666
    82
    for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
slouken@6666
    83
        if (mouse->buttonstate & SDL_BUTTON(i)) {
slouken@6666
    84
            SDL_SendMouseButton(mouse->focus, SDL_RELEASED, i);
slouken@6666
    85
        }
slouken@6666
    86
    }
slouken@6666
    87
    SDL_assert(mouse->buttonstate == 0);
slouken@6666
    88
}
slouken@6666
    89
slouken@6666
    90
void
slouken@4465
    91
SDL_SetMouseFocus(SDL_Window * window)
slouken@0
    92
{
slouken@5371
    93
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
    94
slouken@4465
    95
    if (mouse->focus == window) {
slouken@1895
    96
        return;
slouken@1895
    97
    }
slouken@1895
    98
slouken@6666
    99
    if (mouse->focus && !window) {
slouken@6666
   100
        /* We won't get anymore mouse messages, so reset mouse state */
slouken@6666
   101
        SDL_ResetMouse();
slouken@6666
   102
    }
slouken@6666
   103
slouken@1895
   104
    /* See if the current window has lost focus */
slouken@1895
   105
    if (mouse->focus) {
slouken@4465
   106
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
slouken@1895
   107
    }
slouken@1895
   108
slouken@3685
   109
    mouse->focus = window;
slouken@1895
   110
slouken@1895
   111
    if (mouse->focus) {
slouken@4465
   112
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
slouken@1895
   113
    }
slouken@6666
   114
slouken@6666
   115
    /* Update cursor visibility */
slouken@6666
   116
    SDL_SetCursor(NULL);
slouken@6666
   117
}
slouken@6666
   118
slouken@6666
   119
/* Check to see if we need to synthesize focus events */
slouken@6666
   120
static SDL_bool
slouken@6666
   121
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint8 buttonstate)
slouken@6666
   122
{
slouken@6666
   123
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6666
   124
    int w, h;
slouken@6666
   125
    SDL_bool inWindow;
slouken@6666
   126
slouken@6666
   127
    SDL_GetWindowSize(window, &w, &h);
slouken@6666
   128
    if (x < 0 || y < 0 || x >= w || y >= h) {
slouken@6666
   129
        inWindow = SDL_FALSE;
slouken@6666
   130
    } else {
slouken@6666
   131
        inWindow = SDL_TRUE;
slouken@6666
   132
    }
slouken@6666
   133
    if (!inWindow && !buttonstate) {
slouken@6666
   134
        if (window == mouse->focus) {
slouken@6666
   135
#ifdef DEBUG_MOUSE
slouken@6666
   136
            printf("Mouse left window, synthesizing focus lost event\n");
slouken@6666
   137
#endif
slouken@6666
   138
            SDL_SetMouseFocus(NULL);
slouken@6666
   139
        }
slouken@6666
   140
        return SDL_FALSE;
slouken@6666
   141
    }
slouken@6666
   142
slouken@6666
   143
    if (window != mouse->focus) {
slouken@6666
   144
        mouse->last_x = x;
slouken@6666
   145
        mouse->last_y = y;
slouken@6666
   146
slouken@6666
   147
#ifdef DEBUG_MOUSE
slouken@6666
   148
        printf("Mouse entered window, synthesizing focus gain event\n");
slouken@6666
   149
#endif
slouken@6666
   150
        SDL_SetMouseFocus(window);
slouken@6666
   151
    }
slouken@6666
   152
    return SDL_TRUE;
slouken@1895
   153
}
slouken@1895
   154
slouken@1895
   155
int
slouken@4484
   156
SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
slouken@1895
   157
{
slouken@5371
   158
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   159
    int posted;
slouken@1895
   160
    int xrel;
slouken@1895
   161
    int yrel;
slouken@2860
   162
    int x_max = 0, y_max = 0;
slouken@1895
   163
slouken@6666
   164
    if (window && !relative) {
slouken@6666
   165
        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
slouken@6666
   166
            return 0;
slouken@6666
   167
        }
slouken@4484
   168
    }
slouken@4484
   169
slouken@6666
   170
    /* relative motion is calculated regarding the system cursor last position */
slouken@2842
   171
    if (relative) {
slouken@2842
   172
        xrel = x;
slouken@2842
   173
        yrel = y;
slouken@2860
   174
        x = (mouse->last_x + x);
slouken@2860
   175
        y = (mouse->last_y + y);
slouken@2842
   176
    } else {
slouken@2860
   177
        xrel = x - mouse->last_x;
slouken@2860
   178
        yrel = y - mouse->last_y;
slouken@2842
   179
    }
slouken@2710
   180
slouken@1895
   181
    /* Drop events that don't change state */
slouken@1895
   182
    if (!xrel && !yrel) {
slouken@6666
   183
#ifdef DEBUG_MOUSE
slouken@1895
   184
        printf("Mouse event didn't change state - dropped!\n");
slouken@1895
   185
#endif
slouken@1895
   186
        return 0;
slouken@1895
   187
    }
slouken@1895
   188
slouken@2710
   189
    /* Update internal mouse coordinates */
slouken@2710
   190
    if (mouse->relative_mode == SDL_FALSE) {
slouken@1895
   191
        mouse->x = x;
slouken@1895
   192
        mouse->y = y;
slouken@2710
   193
    } else {
slouken@2860
   194
        mouse->x += xrel;
slouken@2860
   195
        mouse->y += yrel;
slouken@2860
   196
    }
slouken@2849
   197
slouken@2860
   198
    SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
slouken@5370
   199
    --x_max;
slouken@5370
   200
    --y_max;
slouken@2849
   201
slouken@2860
   202
    /* make sure that the pointers find themselves inside the windows */
slouken@5370
   203
    if (mouse->x > x_max) {
slouken@2860
   204
        mouse->x = x_max;
slouken@5370
   205
    }
slouken@5370
   206
    if (mouse->x < 0) {
slouken@2860
   207
        mouse->x = 0;
slouken@1895
   208
    }
slouken@2860
   209
slouken@5370
   210
    if (mouse->y > y_max) {
slouken@2860
   211
        mouse->y = y_max;
slouken@5370
   212
    }
slouken@5370
   213
    if (mouse->y < 0) {
slouken@2860
   214
        mouse->y = 0;
slouken@2860
   215
    }
slouken@2860
   216
slouken@1895
   217
    mouse->xdelta += xrel;
slouken@1895
   218
    mouse->ydelta += yrel;
slouken@1895
   219
slouken@4465
   220
#if 0 /* FIXME */
slouken@1895
   221
    /* Move the mouse cursor, if needed */
slouken@1895
   222
    if (mouse->cursor_shown && !mouse->relative_mode &&
slouken@1895
   223
        mouse->MoveCursor && mouse->cur_cursor) {
slouken@1895
   224
        mouse->MoveCursor(mouse->cur_cursor);
slouken@1895
   225
    }
slouken@4465
   226
#endif
slouken@1895
   227
slouken@1895
   228
    /* Post the event, if desired */
slouken@1895
   229
    posted = 0;
slouken@4465
   230
    if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
slouken@1895
   231
        SDL_Event event;
slouken@1895
   232
        event.motion.type = SDL_MOUSEMOTION;
slouken@4465
   233
        event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@1895
   234
        event.motion.state = mouse->buttonstate;
slouken@1895
   235
        event.motion.x = mouse->x;
slouken@1895
   236
        event.motion.y = mouse->y;
slouken@1895
   237
        event.motion.xrel = xrel;
slouken@1895
   238
        event.motion.yrel = yrel;
slouken@1895
   239
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   240
    }
slouken@6666
   241
    /* Use unclamped values if we're getting events outside the window */
slouken@6666
   242
    mouse->last_x = x;
slouken@6666
   243
    mouse->last_y = y;
slouken@1895
   244
    return posted;
slouken@1895
   245
}
slouken@1895
   246
slouken@1895
   247
int
slouken@4484
   248
SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
slouken@1895
   249
{
slouken@5371
   250
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   251
    int posted;
slouken@4429
   252
    Uint32 type;
slouken@6666
   253
    Uint8 buttonstate = mouse->buttonstate;
slouken@4484
   254
slouken@1895
   255
    /* Figure out which event to perform */
slouken@1895
   256
    switch (state) {
slouken@1895
   257
    case SDL_PRESSED:
slouken@1895
   258
        type = SDL_MOUSEBUTTONDOWN;
slouken@6666
   259
        buttonstate |= SDL_BUTTON(button);
slouken@1895
   260
        break;
slouken@1895
   261
    case SDL_RELEASED:
slouken@1895
   262
        type = SDL_MOUSEBUTTONUP;
slouken@6666
   263
        buttonstate &= ~SDL_BUTTON(button);
slouken@1895
   264
        break;
slouken@1895
   265
    default:
slouken@1895
   266
        /* Invalid state -- bail */
slouken@1895
   267
        return 0;
slouken@1895
   268
    }
slouken@1895
   269
slouken@6666
   270
    /* We do this after calculating buttonstate so button presses gain focus */
slouken@6666
   271
    if (window && state == SDL_PRESSED) {
slouken@6666
   272
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   273
    }
slouken@6666
   274
slouken@6666
   275
    if (buttonstate == mouse->buttonstate) {
slouken@6666
   276
        /* Ignore this event, no state change */
slouken@6666
   277
        return 0;
slouken@6666
   278
    }
slouken@6666
   279
    mouse->buttonstate = buttonstate;
slouken@6666
   280
slouken@1895
   281
    /* Post the event, if desired */
slouken@1895
   282
    posted = 0;
slouken@4429
   283
    if (SDL_GetEventState(type) == SDL_ENABLE) {
slouken@1895
   284
        SDL_Event event;
slouken@1895
   285
        event.type = type;
slouken@1895
   286
        event.button.state = state;
slouken@1895
   287
        event.button.button = button;
slouken@1895
   288
        event.button.x = mouse->x;
slouken@1895
   289
        event.button.y = mouse->y;
slouken@3689
   290
        event.button.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@1895
   291
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   292
    }
slouken@6666
   293
slouken@6666
   294
    /* We do this after dispatching event so button releases can lose focus */
slouken@6666
   295
    if (window && state == SDL_RELEASED) {
slouken@6666
   296
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   297
    }
slouken@6666
   298
slouken@1895
   299
    return posted;
slouken@1895
   300
}
slouken@1895
   301
slouken@1895
   302
int
slouken@4484
   303
SDL_SendMouseWheel(SDL_Window * window, int x, int y)
slouken@1895
   304
{
slouken@5371
   305
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   306
    int posted;
slouken@1895
   307
slouken@4484
   308
    if (window) {
slouken@4484
   309
        SDL_SetMouseFocus(window);
slouken@4484
   310
    }
slouken@4484
   311
slouken@4465
   312
    if (!x && !y) {
slouken@1895
   313
        return 0;
slouken@1895
   314
    }
slouken@1895
   315
slouken@1895
   316
    /* Post the event, if desired */
slouken@1895
   317
    posted = 0;
slouken@4429
   318
    if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
slouken@1895
   319
        SDL_Event event;
slouken@1895
   320
        event.type = SDL_MOUSEWHEEL;
slouken@4465
   321
        event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@2152
   322
        event.wheel.x = x;
slouken@2152
   323
        event.wheel.y = y;
slouken@1895
   324
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   325
    }
slouken@1895
   326
    return posted;
slouken@1895
   327
}
slouken@1895
   328
slouken@1895
   329
void
slouken@4465
   330
SDL_MouseQuit(void)
slouken@4465
   331
{
slouken@4465
   332
}
slouken@4465
   333
slouken@4465
   334
Uint8
slouken@4465
   335
SDL_GetMouseState(int *x, int *y)
slouken@4465
   336
{
slouken@5371
   337
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   338
slouken@4465
   339
    if (x) {
slouken@4465
   340
        *x = mouse->x;
slouken@4465
   341
    }
slouken@4465
   342
    if (y) {
slouken@4465
   343
        *y = mouse->y;
slouken@4465
   344
    }
slouken@4465
   345
    return mouse->buttonstate;
slouken@4465
   346
}
slouken@4465
   347
slouken@4465
   348
Uint8
slouken@4465
   349
SDL_GetRelativeMouseState(int *x, int *y)
slouken@4465
   350
{
slouken@5371
   351
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   352
slouken@4465
   353
    if (x) {
slouken@4465
   354
        *x = mouse->xdelta;
slouken@4465
   355
    }
slouken@4465
   356
    if (y) {
slouken@4465
   357
        *y = mouse->ydelta;
slouken@4465
   358
    }
slouken@4465
   359
    mouse->xdelta = 0;
slouken@4465
   360
    mouse->ydelta = 0;
slouken@4465
   361
    return mouse->buttonstate;
slouken@4465
   362
}
slouken@4465
   363
slouken@4465
   364
void
slouken@3685
   365
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
slouken@1895
   366
{
slouken@5371
   367
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   368
slouken@1895
   369
    if (mouse->WarpMouse) {
slouken@5371
   370
        mouse->WarpMouse(window, x, y);
slouken@1895
   371
    } else {
slouken@4484
   372
        SDL_SendMouseMotion(window, 0, x, y);
slouken@1895
   373
    }
slouken@1895
   374
}
slouken@1895
   375
slouken@4465
   376
int
slouken@4465
   377
SDL_SetRelativeMouseMode(SDL_bool enabled)
slouken@4465
   378
{
slouken@5371
   379
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   380
slouken@5406
   381
    if (enabled == mouse->relative_mode) {
slouken@5406
   382
        return 0;
slouken@5406
   383
    }
slouken@5406
   384
slouken@5406
   385
    if (!mouse->SetRelativeMouseMode) {
slouken@5406
   386
        SDL_Unsupported();
slouken@5406
   387
        return -1;
slouken@5406
   388
    }
slouken@5406
   389
slouken@5406
   390
    if (mouse->SetRelativeMouseMode(enabled) < 0) {
slouken@5406
   391
        return -1;
slouken@5406
   392
    }
slouken@4465
   393
slouken@4465
   394
    /* Set the relative mode */
slouken@4465
   395
    mouse->relative_mode = enabled;
slouken@4465
   396
ghostunderscore@6302
   397
    if (enabled) {
ghostunderscore@6302
   398
        /* Save the expected mouse position */
ghostunderscore@6302
   399
        mouse->original_x = mouse->x;
ghostunderscore@6302
   400
        mouse->original_y = mouse->y;
ghostunderscore@6302
   401
    } else if (mouse->focus) {
slouken@4465
   402
        /* Restore the expected mouse position */
ghostunderscore@6302
   403
        SDL_WarpMouseInWindow(mouse->focus, mouse->original_x, mouse->original_y);
slouken@4465
   404
    }
slouken@4465
   405
slouken@5406
   406
    /* Flush pending mouse motion */
slouken@5406
   407
    SDL_FlushEvent(SDL_MOUSEMOTION);
slouken@5406
   408
slouken@4465
   409
    /* Update cursor visibility */
slouken@4465
   410
    SDL_SetCursor(NULL);
slouken@4465
   411
slouken@4465
   412
    return 0;
slouken@4465
   413
}
slouken@4465
   414
slouken@4465
   415
SDL_bool
slouken@4465
   416
SDL_GetRelativeMouseMode()
slouken@4465
   417
{
slouken@5371
   418
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   419
slouken@4465
   420
    return mouse->relative_mode;
slouken@4465
   421
}
slouken@4465
   422
slouken@1895
   423
SDL_Cursor *
slouken@1895
   424
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
slouken@1895
   425
                 int w, int h, int hot_x, int hot_y)
slouken@1895
   426
{
slouken@1895
   427
    SDL_Surface *surface;
slouken@1895
   428
    SDL_Cursor *cursor;
slouken@1895
   429
    int x, y;
slouken@1895
   430
    Uint32 *pixel;
slouken@4465
   431
    Uint8 datab = 0, maskb = 0;
slouken@1895
   432
    const Uint32 black = 0xFF000000;
slouken@1895
   433
    const Uint32 white = 0xFFFFFFFF;
slouken@1895
   434
    const Uint32 transparent = 0x00000000;
slouken@1895
   435
slouken@1895
   436
    /* Make sure the width is a multiple of 8 */
slouken@1895
   437
    w = ((w + 7) & ~7);
slouken@1895
   438
slouken@1895
   439
    /* Create the surface from a bitmap */
slouken@5473
   440
    surface = SDL_CreateRGBSurface(0, w, h, 32,
slouken@5473
   441
                                   0x00FF0000,
slouken@5473
   442
                                   0x0000FF00,
slouken@5473
   443
                                   0x000000FF,
slouken@5473
   444
                                   0xFF000000);
slouken@1895
   445
    if (!surface) {
slouken@1895
   446
        return NULL;
slouken@1895
   447
    }
slouken@1895
   448
    for (y = 0; y < h; ++y) {
slouken@1895
   449
        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
slouken@1895
   450
        for (x = 0; x < w; ++x) {
slouken@1895
   451
            if ((x % 8) == 0) {
slouken@1895
   452
                datab = *data++;
slouken@1895
   453
                maskb = *mask++;
slouken@1895
   454
            }
slouken@1895
   455
            if (maskb & 0x80) {
slouken@1895
   456
                *pixel++ = (datab & 0x80) ? black : white;
slouken@1895
   457
            } else {
slouken@1895
   458
                *pixel++ = (datab & 0x80) ? black : transparent;
slouken@1895
   459
            }
slouken@1895
   460
            datab <<= 1;
slouken@1895
   461
            maskb <<= 1;
slouken@1895
   462
        }
slouken@1895
   463
    }
slouken@1895
   464
slouken@5473
   465
    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
slouken@5473
   466
slouken@5473
   467
    SDL_FreeSurface(surface);
slouken@5473
   468
slouken@5473
   469
    return cursor;
slouken@5473
   470
}
slouken@5473
   471
slouken@5473
   472
SDL_Cursor *
slouken@5473
   473
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
slouken@5473
   474
{
slouken@5473
   475
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5473
   476
    SDL_Surface *temp = NULL;
slouken@5473
   477
    SDL_Cursor *cursor;
slouken@5473
   478
slouken@5473
   479
    if (!surface) {
slouken@5473
   480
        SDL_SetError("Passed NULL cursor surface");
slouken@5473
   481
        return NULL;
slouken@5473
   482
    }
slouken@5473
   483
slouken@5473
   484
    if (!mouse->CreateCursor) {
slouken@5473
   485
        SDL_SetError("Cursors are not currently supported");
slouken@5473
   486
        return NULL;
slouken@5473
   487
    }
slouken@5473
   488
slouken@5473
   489
    /* Sanity check the hot spot */
slouken@5473
   490
    if ((hot_x < 0) || (hot_y < 0) ||
slouken@5473
   491
        (hot_x >= surface->w) || (hot_y >= surface->h)) {
slouken@5473
   492
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@5473
   493
        return NULL;
slouken@5473
   494
    }
slouken@5473
   495
slouken@5473
   496
    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
slouken@5473
   497
        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
slouken@5473
   498
        if (!temp) {
slouken@5473
   499
            return NULL;
slouken@5473
   500
        }
slouken@5473
   501
        surface = temp;
slouken@5473
   502
    }
slouken@5473
   503
slouken@1895
   504
    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
slouken@1895
   505
    if (cursor) {
slouken@1895
   506
        cursor->next = mouse->cursors;
slouken@1895
   507
        mouse->cursors = cursor;
slouken@1895
   508
    }
slouken@1895
   509
slouken@5473
   510
    if (temp) {
slouken@5473
   511
        SDL_FreeSurface(temp);
slouken@5473
   512
    }
slouken@1895
   513
slouken@1895
   514
    return cursor;
slouken@1895
   515
}
slouken@1895
   516
slouken@1895
   517
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@1895
   518
   if this is desired for any reason.  This is used when setting
slouken@1895
   519
   the video mode and when the SDL window gains the mouse focus.
slouken@1895
   520
 */
slouken@1895
   521
void
slouken@1895
   522
SDL_SetCursor(SDL_Cursor * cursor)
slouken@1895
   523
{
slouken@5371
   524
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   525
slouken@1895
   526
    /* Set the new cursor */
slouken@1895
   527
    if (cursor) {
slouken@1895
   528
        /* Make sure the cursor is still valid for this mouse */
slouken@5405
   529
        if (cursor != mouse->def_cursor) {
slouken@5405
   530
            SDL_Cursor *found;
slouken@5405
   531
            for (found = mouse->cursors; found; found = found->next) {
slouken@5405
   532
                if (found == cursor) {
slouken@5405
   533
                    break;
slouken@5405
   534
                }
slouken@1895
   535
            }
slouken@5405
   536
            if (!found) {
slouken@5405
   537
                SDL_SetError("Cursor not associated with the current mouse");
slouken@5405
   538
                return;
slouken@5405
   539
            }
slouken@1895
   540
        }
slouken@1895
   541
        mouse->cur_cursor = cursor;
slouken@1895
   542
    } else {
ghostunderscore@6301
   543
        if (mouse->focus) {
ghostunderscore@6301
   544
            cursor = mouse->cur_cursor;
ghostunderscore@6301
   545
        } else {
ghostunderscore@6301
   546
            cursor = mouse->def_cursor;
ghostunderscore@6301
   547
        }
slouken@1895
   548
    }
slouken@1895
   549
slouken@1895
   550
    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
slouken@1895
   551
        if (mouse->ShowCursor) {
slouken@1895
   552
            mouse->ShowCursor(cursor);
slouken@1895
   553
        }
slouken@1895
   554
    } else {
slouken@1895
   555
        if (mouse->ShowCursor) {
slouken@1895
   556
            mouse->ShowCursor(NULL);
slouken@1895
   557
        }
slouken@1895
   558
    }
slouken@1895
   559
}
slouken@1895
   560
slouken@1895
   561
SDL_Cursor *
slouken@1895
   562
SDL_GetCursor(void)
slouken@1895
   563
{
slouken@5371
   564
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   565
slouken@1895
   566
    if (!mouse) {
slouken@1895
   567
        return NULL;
slouken@1895
   568
    }
slouken@1895
   569
    return mouse->cur_cursor;
slouken@1895
   570
}
slouken@1895
   571
slouken@1895
   572
void
slouken@1895
   573
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@1895
   574
{
slouken@5371
   575
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   576
    SDL_Cursor *curr, *prev;
slouken@1895
   577
slouken@1895
   578
    if (!cursor) {
slouken@1895
   579
        return;
slouken@1895
   580
    }
slouken@1895
   581
slouken@1895
   582
    if (cursor == mouse->def_cursor) {
slouken@1895
   583
        return;
slouken@1895
   584
    }
slouken@1895
   585
    if (cursor == mouse->cur_cursor) {
slouken@1895
   586
        SDL_SetCursor(mouse->def_cursor);
slouken@1895
   587
    }
slouken@1895
   588
slouken@1895
   589
    for (prev = NULL, curr = mouse->cursors; curr;
slouken@1895
   590
         prev = curr, curr = curr->next) {
slouken@1895
   591
        if (curr == cursor) {
slouken@1895
   592
            if (prev) {
slouken@1895
   593
                prev->next = curr->next;
slouken@1895
   594
            } else {
slouken@1895
   595
                mouse->cursors = curr->next;
slouken@1895
   596
            }
slouken@1895
   597
slouken@1895
   598
            if (mouse->FreeCursor) {
slouken@1895
   599
                mouse->FreeCursor(curr);
slouken@1895
   600
            }
slouken@1895
   601
            return;
slouken@1895
   602
        }
slouken@1895
   603
    }
slouken@1895
   604
}
slouken@1895
   605
slouken@1895
   606
int
slouken@1895
   607
SDL_ShowCursor(int toggle)
slouken@1895
   608
{
slouken@5371
   609
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   610
    SDL_bool shown;
slouken@1895
   611
slouken@1895
   612
    if (!mouse) {
slouken@1895
   613
        return 0;
slouken@1895
   614
    }
slouken@1895
   615
slouken@1895
   616
    shown = mouse->cursor_shown;
slouken@1895
   617
    if (toggle >= 0) {
slouken@1895
   618
        if (toggle) {
slouken@1895
   619
            mouse->cursor_shown = SDL_TRUE;
slouken@1895
   620
        } else {
slouken@1895
   621
            mouse->cursor_shown = SDL_FALSE;
slouken@1895
   622
        }
slouken@1895
   623
        if (mouse->cursor_shown != shown) {
slouken@1895
   624
            SDL_SetCursor(NULL);
slouken@1895
   625
        }
slouken@1895
   626
    }
slouken@1895
   627
    return shown;
slouken@1895
   628
}
slouken@1895
   629
slouken@1895
   630
/* vi: set ts=4 sw=4 expandtab: */