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