src/events/SDL_mouse.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 22 Jun 2015 23:36:06 -0700
changeset 9776 952ff8a5076f
parent 9619 b94b6d0bff0f
child 9807 57b448735f48
permissions -rw-r--r--
Fixed bug 3030 - SDL_RecreateWindow fails to restore title, icon, etc.

Adam M.

It loses the title and icon when window recreation fails. For instance, this may happen when trying to create an OpenGL ES window on a system that doesn't support it. But at that point, the title and icon have already been lost.
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@1895
    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@1895
    52
}
slouken@1895
    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@0
    79
{
slouken@5371
    80
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
    81
slouken@4465
    82
    return mouse->focus;
slouken@1895
    83
}
slouken@1895
    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@1895
   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
slouken@6667
   153
/* Linux doesn't give you mouse events outside your window unless you grab
slouken@6667
   154
   the pointer.
slouken@6667
   155
slouken@6667
   156
   Windows doesn't give you mouse events outside your window unless you call
slouken@6667
   157
   SetCapture().
slouken@6667
   158
slouken@6667
   159
   Both of these are slightly scary changes, so for now we'll punt and if the
slouken@6667
   160
   mouse leaves the window you'll lose mouse focus and reset button state.
slouken@6667
   161
*/
slouken@6667
   162
#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
slouken@6666
   163
    if (!inWindow && !buttonstate) {
slouken@6667
   164
#else
slouken@6667
   165
    if (!inWindow) {
slouken@6667
   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@0
   185
}
slouken@0
   186
slouken@1895
   187
int
slouken@6950
   188
SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
slouken@0
   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@0
   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;
icculus@8927
   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@2849
   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
        }
slouken@2860
   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@0
   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@0
   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@1283
   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@0
   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@0
   536
}
slouken@0
   537
slouken@8815
   538
void
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) {
slouken@8815
   544
        mouse->WarpMouseGlobal(x, y);
slouken@8815
   545
    }
slouken@8815
   546
}
slouken@8815
   547
slouken@8071
   548
static SDL_bool
slouken@8071
   549
ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
slouken@8071
   550
{
slouken@8071
   551
    const char *hint;
slouken@8071
   552
slouken@8071
   553
    if (!mouse->SetRelativeMouseMode) {
slouken@8071
   554
        return SDL_TRUE;
slouken@8071
   555
    }
slouken@8071
   556
slouken@8071
   557
    hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
slouken@8071
   558
    if (hint) {
slouken@8071
   559
        if (*hint == '0') {
slouken@8071
   560
            return SDL_FALSE;
slouken@8071
   561
        } else {
slouken@8071
   562
            return SDL_TRUE;
slouken@8071
   563
        }
slouken@8071
   564
    }
slouken@8071
   565
    return SDL_FALSE;
slouken@8071
   566
}
slouken@8071
   567
slouken@4465
   568
int
slouken@4465
   569
SDL_SetRelativeMouseMode(SDL_bool enabled)
slouken@4465
   570
{
slouken@5371
   571
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7107
   572
    SDL_Window *focusWindow = SDL_GetKeyboardFocus();
slouken@4465
   573
slouken@5406
   574
    if (enabled == mouse->relative_mode) {
slouken@5406
   575
        return 0;
slouken@5406
   576
    }
slouken@5406
   577
jorgen@7107
   578
    if (enabled && focusWindow) {
jorgen@7107
   579
        /* Center it in the focused window to prevent clicks from going through
jorgen@7107
   580
         * to background windows.
jorgen@7107
   581
         */
jorgen@7107
   582
        SDL_SetMouseFocus(focusWindow);
jorgen@7107
   583
        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
jorgen@7107
   584
    }
jorgen@7107
   585
slouken@8071
   586
    /* Set the relative mode */
slouken@8071
   587
    if (!enabled && mouse->relative_mode_warp) {
slouken@8071
   588
        mouse->relative_mode_warp = SDL_FALSE;
slouken@8071
   589
    } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
slouken@8071
   590
        mouse->relative_mode_warp = SDL_TRUE;
slouken@8071
   591
    } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
slouken@8269
   592
        if (enabled) {
philipp@8776
   593
            /* Fall back to warp mode if native relative mode failed */
slouken@8269
   594
            mouse->relative_mode_warp = SDL_TRUE;
slouken@8269
   595
        }
slouken@5406
   596
    }
slouken@4465
   597
    mouse->relative_mode = enabled;
slouken@4465
   598
slouken@8071
   599
    if (mouse->focus) {
slouken@8071
   600
        SDL_UpdateWindowGrab(mouse->focus);
slouken@8071
   601
slouken@8071
   602
        /* Put the cursor back to where the application expects it */
slouken@8071
   603
        if (!enabled) {
slouken@8071
   604
            SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
slouken@8071
   605
        }
slouken@4465
   606
    }
slouken@4465
   607
slouken@8071
   608
    /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
slouken@5406
   609
    SDL_FlushEvent(SDL_MOUSEMOTION);
slouken@5406
   610
slouken@4465
   611
    /* Update cursor visibility */
slouken@4465
   612
    SDL_SetCursor(NULL);
slouken@4465
   613
slouken@4465
   614
    return 0;
slouken@4465
   615
}
slouken@4465
   616
slouken@4465
   617
SDL_bool
slouken@4465
   618
SDL_GetRelativeMouseMode()
slouken@4465
   619
{
slouken@5371
   620
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   621
slouken@4465
   622
    return mouse->relative_mode;
slouken@4465
   623
}
slouken@4465
   624
icculus@8955
   625
int
icculus@8955
   626
SDL_CaptureMouse(SDL_bool enabled)
icculus@8955
   627
{
icculus@8955
   628
    SDL_Mouse *mouse = SDL_GetMouse();
icculus@8955
   629
    SDL_Window *focusWindow;
icculus@8955
   630
    SDL_bool isCaptured;
icculus@8955
   631
icculus@8955
   632
    if (!mouse->CaptureMouse) {
icculus@8955
   633
        return SDL_Unsupported();
icculus@8955
   634
    }
icculus@8955
   635
icculus@8955
   636
    focusWindow = SDL_GetKeyboardFocus();
icculus@8955
   637
icculus@8955
   638
    isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
icculus@8955
   639
    if (isCaptured == enabled) {
icculus@8955
   640
        return 0;  /* already done! */
icculus@8955
   641
    }
icculus@8955
   642
icculus@8955
   643
    if (enabled) {
icculus@8955
   644
        if (!focusWindow) {
icculus@8955
   645
            return SDL_SetError("No window has focus");
icculus@8955
   646
        } else if (mouse->CaptureMouse(focusWindow) == -1) {
icculus@8955
   647
            return -1;  /* CaptureMouse() should call SetError */
icculus@8955
   648
        }
icculus@8955
   649
        focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
icculus@8955
   650
    } else {
icculus@8955
   651
        if (mouse->CaptureMouse(NULL) == -1) {
icculus@8955
   652
            return -1;  /* CaptureMouse() should call SetError */
icculus@8955
   653
        }
icculus@8955
   654
        focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
icculus@8955
   655
    }
icculus@8955
   656
icculus@8955
   657
    return 0;
icculus@8955
   658
}
icculus@8955
   659
slouken@1895
   660
SDL_Cursor *
slouken@1895
   661
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
slouken@1895
   662
                 int w, int h, int hot_x, int hot_y)
slouken@0
   663
{
slouken@1895
   664
    SDL_Surface *surface;
slouken@1895
   665
    SDL_Cursor *cursor;
slouken@1895
   666
    int x, y;
slouken@1895
   667
    Uint32 *pixel;
slouken@4465
   668
    Uint8 datab = 0, maskb = 0;
slouken@1895
   669
    const Uint32 black = 0xFF000000;
slouken@1895
   670
    const Uint32 white = 0xFFFFFFFF;
slouken@1895
   671
    const Uint32 transparent = 0x00000000;
slouken@0
   672
slouken@1895
   673
    /* Make sure the width is a multiple of 8 */
slouken@1895
   674
    w = ((w + 7) & ~7);
slouken@0
   675
slouken@1895
   676
    /* Create the surface from a bitmap */
slouken@5473
   677
    surface = SDL_CreateRGBSurface(0, w, h, 32,
slouken@5473
   678
                                   0x00FF0000,
slouken@5473
   679
                                   0x0000FF00,
slouken@5473
   680
                                   0x000000FF,
slouken@5473
   681
                                   0xFF000000);
slouken@1895
   682
    if (!surface) {
slouken@1895
   683
        return NULL;
slouken@1895
   684
    }
slouken@1895
   685
    for (y = 0; y < h; ++y) {
slouken@1895
   686
        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
slouken@1895
   687
        for (x = 0; x < w; ++x) {
slouken@1895
   688
            if ((x % 8) == 0) {
slouken@1895
   689
                datab = *data++;
slouken@1895
   690
                maskb = *mask++;
slouken@1895
   691
            }
slouken@1895
   692
            if (maskb & 0x80) {
slouken@1895
   693
                *pixel++ = (datab & 0x80) ? black : white;
slouken@1895
   694
            } else {
slouken@1895
   695
                *pixel++ = (datab & 0x80) ? black : transparent;
slouken@1895
   696
            }
slouken@1895
   697
            datab <<= 1;
slouken@1895
   698
            maskb <<= 1;
slouken@1895
   699
        }
slouken@1895
   700
    }
slouken@0
   701
slouken@5473
   702
    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
slouken@5473
   703
slouken@5473
   704
    SDL_FreeSurface(surface);
slouken@5473
   705
slouken@5473
   706
    return cursor;
slouken@5473
   707
}
slouken@5473
   708
slouken@5473
   709
SDL_Cursor *
slouken@5473
   710
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
slouken@5473
   711
{
slouken@5473
   712
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5473
   713
    SDL_Surface *temp = NULL;
slouken@5473
   714
    SDL_Cursor *cursor;
slouken@5473
   715
slouken@5473
   716
    if (!surface) {
slouken@5473
   717
        SDL_SetError("Passed NULL cursor surface");
slouken@5473
   718
        return NULL;
slouken@5473
   719
    }
slouken@5473
   720
slouken@5473
   721
    if (!mouse->CreateCursor) {
slouken@5473
   722
        SDL_SetError("Cursors are not currently supported");
slouken@5473
   723
        return NULL;
slouken@5473
   724
    }
slouken@5473
   725
slouken@5473
   726
    /* Sanity check the hot spot */
slouken@5473
   727
    if ((hot_x < 0) || (hot_y < 0) ||
slouken@5473
   728
        (hot_x >= surface->w) || (hot_y >= surface->h)) {
slouken@5473
   729
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@5473
   730
        return NULL;
slouken@5473
   731
    }
slouken@5473
   732
slouken@5473
   733
    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
slouken@5473
   734
        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
slouken@5473
   735
        if (!temp) {
slouken@5473
   736
            return NULL;
slouken@5473
   737
        }
slouken@5473
   738
        surface = temp;
slouken@5473
   739
    }
slouken@5473
   740
slouken@1895
   741
    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
slouken@1895
   742
    if (cursor) {
slouken@1895
   743
        cursor->next = mouse->cursors;
slouken@1895
   744
        mouse->cursors = cursor;
slouken@1895
   745
    }
slouken@0
   746
slouken@7720
   747
    SDL_FreeSurface(temp);
slouken@1895
   748
slouken@1895
   749
    return cursor;
slouken@0
   750
}
slouken@0
   751
mikesart@6675
   752
SDL_Cursor *
mikesart@6675
   753
SDL_CreateSystemCursor(SDL_SystemCursor id)
mikesart@6675
   754
{
mikesart@6675
   755
    SDL_Mouse *mouse = SDL_GetMouse();
mikesart@6675
   756
    SDL_Cursor *cursor;
mikesart@6675
   757
mikesart@6675
   758
    if (!mouse->CreateSystemCursor) {
mikesart@6675
   759
        SDL_SetError("CreateSystemCursor is not currently supported");
mikesart@6675
   760
        return NULL;
mikesart@6675
   761
    }
mikesart@6675
   762
slouken@7191
   763
    cursor = mouse->CreateSystemCursor(id);
mikesart@6675
   764
    if (cursor) {
mikesart@6675
   765
        cursor->next = mouse->cursors;
mikesart@6675
   766
        mouse->cursors = cursor;
mikesart@6675
   767
    }
mikesart@6675
   768
slouken@7191
   769
    return cursor;
mikesart@6675
   770
}
mikesart@6675
   771
slouken@1895
   772
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@1895
   773
   if this is desired for any reason.  This is used when setting
slouken@1895
   774
   the video mode and when the SDL window gains the mouse focus.
slouken@1895
   775
 */
slouken@1895
   776
void
slouken@1895
   777
SDL_SetCursor(SDL_Cursor * cursor)
slouken@1895
   778
{
slouken@5371
   779
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   780
slouken@1895
   781
    /* Set the new cursor */
slouken@1895
   782
    if (cursor) {
slouken@1895
   783
        /* Make sure the cursor is still valid for this mouse */
slouken@5405
   784
        if (cursor != mouse->def_cursor) {
slouken@5405
   785
            SDL_Cursor *found;
slouken@5405
   786
            for (found = mouse->cursors; found; found = found->next) {
slouken@5405
   787
                if (found == cursor) {
slouken@5405
   788
                    break;
slouken@5405
   789
                }
slouken@1895
   790
            }
slouken@5405
   791
            if (!found) {
slouken@5405
   792
                SDL_SetError("Cursor not associated with the current mouse");
slouken@5405
   793
                return;
slouken@5405
   794
            }
slouken@1895
   795
        }
slouken@1895
   796
        mouse->cur_cursor = cursor;
slouken@1895
   797
    } else {
ghostunderscore@6301
   798
        if (mouse->focus) {
ghostunderscore@6301
   799
            cursor = mouse->cur_cursor;
ghostunderscore@6301
   800
        } else {
ghostunderscore@6301
   801
            cursor = mouse->def_cursor;
ghostunderscore@6301
   802
        }
slouken@1895
   803
    }
slouken@1895
   804
slouken@1895
   805
    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
slouken@1895
   806
        if (mouse->ShowCursor) {
slouken@1895
   807
            mouse->ShowCursor(cursor);
slouken@1895
   808
        }
slouken@1895
   809
    } else {
slouken@1895
   810
        if (mouse->ShowCursor) {
slouken@1895
   811
            mouse->ShowCursor(NULL);
slouken@1895
   812
        }
slouken@1895
   813
    }
slouken@1895
   814
}
slouken@1895
   815
slouken@1895
   816
SDL_Cursor *
slouken@1895
   817
SDL_GetCursor(void)
slouken@1895
   818
{
slouken@5371
   819
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   820
slouken@1895
   821
    if (!mouse) {
slouken@1895
   822
        return NULL;
slouken@1895
   823
    }
slouken@1895
   824
    return mouse->cur_cursor;
slouken@1895
   825
}
slouken@1895
   826
jorgen@7104
   827
SDL_Cursor *
jorgen@7104
   828
SDL_GetDefaultCursor(void)
jorgen@7104
   829
{
jorgen@7104
   830
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7104
   831
jorgen@7104
   832
    if (!mouse) {
jorgen@7104
   833
        return NULL;
jorgen@7104
   834
    }
jorgen@7104
   835
    return mouse->def_cursor;
jorgen@7104
   836
}
jorgen@7104
   837
slouken@1895
   838
void
slouken@1895
   839
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@1895
   840
{
slouken@5371
   841
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   842
    SDL_Cursor *curr, *prev;
slouken@1895
   843
slouken@1895
   844
    if (!cursor) {
slouken@1895
   845
        return;
slouken@1895
   846
    }
slouken@1895
   847
slouken@1895
   848
    if (cursor == mouse->def_cursor) {
slouken@1895
   849
        return;
slouken@1895
   850
    }
slouken@1895
   851
    if (cursor == mouse->cur_cursor) {
slouken@1895
   852
        SDL_SetCursor(mouse->def_cursor);
slouken@1895
   853
    }
slouken@1895
   854
slouken@1895
   855
    for (prev = NULL, curr = mouse->cursors; curr;
slouken@1895
   856
         prev = curr, curr = curr->next) {
slouken@1895
   857
        if (curr == cursor) {
slouken@1895
   858
            if (prev) {
slouken@1895
   859
                prev->next = curr->next;
slouken@1895
   860
            } else {
slouken@1895
   861
                mouse->cursors = curr->next;
slouken@1895
   862
            }
slouken@1895
   863
slouken@1895
   864
            if (mouse->FreeCursor) {
slouken@1895
   865
                mouse->FreeCursor(curr);
slouken@1895
   866
            }
slouken@1895
   867
            return;
slouken@1895
   868
        }
slouken@1895
   869
    }
slouken@1895
   870
}
slouken@1895
   871
slouken@1895
   872
int
slouken@1895
   873
SDL_ShowCursor(int toggle)
slouken@1895
   874
{
slouken@5371
   875
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   876
    SDL_bool shown;
slouken@1895
   877
slouken@1895
   878
    if (!mouse) {
slouken@1895
   879
        return 0;
slouken@1895
   880
    }
slouken@1895
   881
slouken@1895
   882
    shown = mouse->cursor_shown;
slouken@1895
   883
    if (toggle >= 0) {
slouken@1895
   884
        if (toggle) {
slouken@1895
   885
            mouse->cursor_shown = SDL_TRUE;
slouken@1895
   886
        } else {
slouken@1895
   887
            mouse->cursor_shown = SDL_FALSE;
slouken@1895
   888
        }
slouken@1895
   889
        if (mouse->cursor_shown != shown) {
slouken@1895
   890
            SDL_SetCursor(NULL);
slouken@1895
   891
        }
slouken@1895
   892
    }
slouken@1895
   893
    return shown;
slouken@1895
   894
}
slouken@1895
   895
jorgen@7097
   896
/* vi: set ts=4 sw=4 expandtab: */