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