src/events/SDL_mouse.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 16 Mar 2019 19:07:34 -0700
changeset 12651 d188272453ce
parent 12620 0010b9a064d3
child 12687 712d84dd14c9
permissions -rw-r--r--
Fixed bug 4450 - SDL_mouse.c fails to compile with CMake generated Visual Studio files if SDL_VIDEO_VULKAN 0/undefined

Max Waine

SDL_mouse.c, if compiled for Windows, requires GetDoubleClickTime to compile (available from winuser.h). Without Vulkan present this fails to compile as the include chain for winuser.h is the following.

SDL_mouse.c -> SDL_sysvideo.h -> SDL_vulkan_internal.h -> SDL_windows.h -> windows.h -> winuser.h.
Problem is that SDL_vulkan_internal.h doesn't include SDL_windows.h if Vulkan isn't present, so under MinGW/GCC it will give a -Wimplicit-function-declaration warning for GetDoubleClickTime, and under MSVC fails to compile completely.

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