src/events/SDL_mouse.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 17 Jul 2015 21:03:58 -0400
changeset 9807 57b448735f48
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rw-r--r--
SDL_WarpMouseGlobal() should return non-void.

There are platforms it isn't implemented on (and currently can't be
implemented on!), and there's currently no way for an app to know this.

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