src/events/SDL_mouse.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 14 Aug 2017 21:28:04 -0700
changeset 11300 68a80d7afec3
parent 11284 3db78361e751
child 11313 14d04f0a4914
permissions -rw-r--r--
Fixed bug 2293 - Precise scrolling events

Martijn Courteaux

I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.

The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.

I believe this is pretty solid way of doing it, although I'm not the expert here.

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