src/events/SDL_mouse.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 05 Jun 2014 00:02:42 -0400
changeset 8944 045aac36daac
parent 8927 be64f5daf64b
child 8945 04248c700ada
permissions -rw-r--r--
Added some (harmlessly) missing braces.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 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
icculus@8927
   145
    if ((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
    if (!inWindow) {
slouken@6666
   154
        if (window == mouse->focus) {
slouken@6666
   155
#ifdef DEBUG_MOUSE
jorgen@7089
   156
            printf("Mouse left window, synthesizing move & focus lost event\n");
slouken@6666
   157
#endif
jorgen@7089
   158
            SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@6666
   159
            SDL_SetMouseFocus(NULL);
slouken@6666
   160
        }
slouken@6666
   161
        return SDL_FALSE;
slouken@6666
   162
    }
slouken@6666
   163
slouken@6666
   164
    if (window != mouse->focus) {
slouken@6666
   165
#ifdef DEBUG_MOUSE
jorgen@7097
   166
         printf("Mouse entered window, synthesizing focus gain & move event\n");
slouken@6666
   167
#endif
jorgen@7097
   168
         SDL_SetMouseFocus(window);
jorgen@7097
   169
         SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@6666
   170
    }
slouken@6666
   171
    return SDL_TRUE;
slouken@1895
   172
}
slouken@1895
   173
slouken@1895
   174
int
slouken@6950
   175
SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
slouken@1895
   176
{
jorgen@7089
   177
    if (window && !relative) {
jorgen@7089
   178
        SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7089
   179
        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
jorgen@7089
   180
            return 0;
jorgen@7089
   181
        }
jorgen@7089
   182
    }
jorgen@7089
   183
jorgen@7089
   184
    return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
jorgen@7089
   185
}
jorgen@7089
   186
jorgen@7089
   187
static int
jorgen@7089
   188
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
jorgen@7089
   189
{
slouken@5371
   190
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   191
    int posted;
slouken@1895
   192
    int xrel;
slouken@1895
   193
    int yrel;
slouken@1895
   194
slouken@8071
   195
    if (mouse->relative_mode_warp) {
slouken@8071
   196
        int center_x = 0, center_y = 0;
slouken@8071
   197
        SDL_GetWindowSize(window, &center_x, &center_y);
slouken@8071
   198
        center_x /= 2;
slouken@8071
   199
        center_y /= 2;
slouken@8071
   200
        if (x == center_x && y == center_y) {
slouken@8071
   201
            mouse->last_x = center_x;
slouken@8071
   202
            mouse->last_y = center_y;
slouken@8071
   203
            return 0;
slouken@8071
   204
        }
slouken@8071
   205
        SDL_WarpMouseInWindow(window, center_x, center_y);
slouken@8071
   206
    }
slouken@8071
   207
slouken@2842
   208
    if (relative) {
slouken@2842
   209
        xrel = x;
slouken@2842
   210
        yrel = y;
slouken@8071
   211
        x = (mouse->last_x + xrel);
slouken@8071
   212
        y = (mouse->last_y + yrel);
slouken@2842
   213
    } else {
slouken@2860
   214
        xrel = x - mouse->last_x;
slouken@2860
   215
        yrel = y - mouse->last_y;
slouken@2842
   216
    }
slouken@2710
   217
slouken@1895
   218
    /* Drop events that don't change state */
slouken@1895
   219
    if (!xrel && !yrel) {
slouken@6666
   220
#ifdef DEBUG_MOUSE
slouken@1895
   221
        printf("Mouse event didn't change state - dropped!\n");
slouken@1895
   222
#endif
slouken@1895
   223
        return 0;
slouken@1895
   224
    }
slouken@1895
   225
slouken@2710
   226
    /* Update internal mouse coordinates */
slouken@8071
   227
    if (!mouse->relative_mode) {
slouken@1895
   228
        mouse->x = x;
slouken@1895
   229
        mouse->y = y;
slouken@2710
   230
    } else {
slouken@2860
   231
        mouse->x += xrel;
slouken@2860
   232
        mouse->y += yrel;
slouken@2860
   233
    }
slouken@2849
   234
icculus@8927
   235
    /* make sure that the pointers find themselves inside the windows,
icculus@8927
   236
       unless we have the mouse captured. */
icculus@8927
   237
    if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0) {
icculus@8927
   238
        int x_max = 0, y_max = 0;
slouken@2849
   239
icculus@8927
   240
        // !!! FIXME: shouldn't this be (window) instead of (mouse->focus)?
icculus@8927
   241
        SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
icculus@8927
   242
        --x_max;
icculus@8927
   243
        --y_max;
slouken@2860
   244
icculus@8927
   245
        if (mouse->x > x_max) {
icculus@8927
   246
            mouse->x = x_max;
icculus@8927
   247
        }
icculus@8927
   248
        if (mouse->x < 0) {
icculus@8927
   249
            mouse->x = 0;
icculus@8927
   250
        }
icculus@8927
   251
icculus@8927
   252
        if (mouse->y > y_max) {
icculus@8927
   253
            mouse->y = y_max;
icculus@8927
   254
        }
icculus@8927
   255
        if (mouse->y < 0) {
icculus@8927
   256
            mouse->y = 0;
icculus@8927
   257
        }
slouken@2860
   258
    }
slouken@2860
   259
slouken@1895
   260
    mouse->xdelta += xrel;
slouken@1895
   261
    mouse->ydelta += yrel;
slouken@1895
   262
slouken@1895
   263
    /* Move the mouse cursor, if needed */
slouken@1895
   264
    if (mouse->cursor_shown && !mouse->relative_mode &&
slouken@1895
   265
        mouse->MoveCursor && mouse->cur_cursor) {
slouken@1895
   266
        mouse->MoveCursor(mouse->cur_cursor);
slouken@1895
   267
    }
slouken@1895
   268
slouken@1895
   269
    /* Post the event, if desired */
slouken@1895
   270
    posted = 0;
slouken@4465
   271
    if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
slouken@1895
   272
        SDL_Event event;
slouken@1895
   273
        event.motion.type = SDL_MOUSEMOTION;
slouken@4465
   274
        event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   275
        event.motion.which = mouseID;
slouken@1895
   276
        event.motion.state = mouse->buttonstate;
slouken@1895
   277
        event.motion.x = mouse->x;
slouken@1895
   278
        event.motion.y = mouse->y;
slouken@1895
   279
        event.motion.xrel = xrel;
slouken@1895
   280
        event.motion.yrel = yrel;
slouken@1895
   281
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   282
    }
slouken@6666
   283
    /* Use unclamped values if we're getting events outside the window */
slouken@6666
   284
    mouse->last_x = x;
slouken@6666
   285
    mouse->last_y = y;
slouken@1895
   286
    return posted;
slouken@1895
   287
}
slouken@1895
   288
slouken@8066
   289
static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
slouken@8066
   290
{
slouken@8066
   291
    if (button >= mouse->num_clickstates) {
slouken@8066
   292
        int i, count = button + 1;
slouken@8066
   293
        mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
slouken@8066
   294
        if (!mouse->clickstate) {
slouken@8066
   295
            return NULL;
slouken@8066
   296
        }
slouken@8066
   297
slouken@8066
   298
        for (i = mouse->num_clickstates; i < count; ++i) {
slouken@8066
   299
            SDL_zero(mouse->clickstate[i]);
slouken@8066
   300
        }
slouken@8066
   301
        mouse->num_clickstates = count;
slouken@8066
   302
    }
slouken@8066
   303
    return &mouse->clickstate[button];
slouken@8066
   304
}
slouken@8066
   305
slouken@1895
   306
int
slouken@6950
   307
SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
slouken@1895
   308
{
slouken@5371
   309
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   310
    int posted;
slouken@4429
   311
    Uint32 type;
slouken@6673
   312
    Uint32 buttonstate = mouse->buttonstate;
slouken@8066
   313
    SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
slouken@8066
   314
    Uint8 click_count;
slouken@4484
   315
slouken@1895
   316
    /* Figure out which event to perform */
slouken@1895
   317
    switch (state) {
slouken@1895
   318
    case SDL_PRESSED:
slouken@1895
   319
        type = SDL_MOUSEBUTTONDOWN;
slouken@6666
   320
        buttonstate |= SDL_BUTTON(button);
slouken@1895
   321
        break;
slouken@1895
   322
    case SDL_RELEASED:
slouken@1895
   323
        type = SDL_MOUSEBUTTONUP;
slouken@6666
   324
        buttonstate &= ~SDL_BUTTON(button);
slouken@1895
   325
        break;
slouken@1895
   326
    default:
slouken@1895
   327
        /* Invalid state -- bail */
slouken@1895
   328
        return 0;
slouken@1895
   329
    }
slouken@1895
   330
slouken@6666
   331
    /* We do this after calculating buttonstate so button presses gain focus */
slouken@6666
   332
    if (window && state == SDL_PRESSED) {
slouken@6666
   333
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   334
    }
slouken@6666
   335
slouken@6666
   336
    if (buttonstate == mouse->buttonstate) {
slouken@6666
   337
        /* Ignore this event, no state change */
slouken@6666
   338
        return 0;
slouken@6666
   339
    }
slouken@6666
   340
    mouse->buttonstate = buttonstate;
slouken@6666
   341
slouken@8066
   342
    if (clickstate) {
slouken@8066
   343
        if (state == SDL_PRESSED) {
slouken@8066
   344
            Uint32 now = SDL_GetTicks();
slouken@8066
   345
slouken@8066
   346
            if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
slouken@8066
   347
                SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
slouken@8066
   348
                SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
slouken@8066
   349
                clickstate->click_count = 0;
slouken@8066
   350
            }
slouken@8066
   351
            clickstate->last_timestamp = now;
slouken@8066
   352
            clickstate->last_x = mouse->x;
slouken@8066
   353
            clickstate->last_y = mouse->y;
slouken@8066
   354
            if (clickstate->click_count < 255) {
slouken@8066
   355
                ++clickstate->click_count;
slouken@8066
   356
            }
slouken@8066
   357
        }
slouken@8066
   358
        click_count = clickstate->click_count;
slouken@8066
   359
    } else {
slouken@8066
   360
        click_count = 1;
slouken@8066
   361
    }
slouken@8066
   362
slouken@1895
   363
    /* Post the event, if desired */
slouken@1895
   364
    posted = 0;
slouken@4429
   365
    if (SDL_GetEventState(type) == SDL_ENABLE) {
slouken@1895
   366
        SDL_Event event;
slouken@1895
   367
        event.type = type;
slouken@6950
   368
        event.button.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   369
        event.button.which = mouseID;
slouken@1895
   370
        event.button.state = state;
slouken@1895
   371
        event.button.button = button;
slouken@8066
   372
        event.button.clicks = click_count;
slouken@1895
   373
        event.button.x = mouse->x;
slouken@1895
   374
        event.button.y = mouse->y;
slouken@1895
   375
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   376
    }
slouken@6666
   377
slouken@6666
   378
    /* We do this after dispatching event so button releases can lose focus */
slouken@6666
   379
    if (window && state == SDL_RELEASED) {
slouken@6666
   380
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   381
    }
slouken@6666
   382
slouken@1895
   383
    return posted;
slouken@1895
   384
}
slouken@1895
   385
slouken@1895
   386
int
slouken@6950
   387
SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y)
slouken@1895
   388
{
slouken@5371
   389
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   390
    int posted;
slouken@1895
   391
slouken@4484
   392
    if (window) {
slouken@4484
   393
        SDL_SetMouseFocus(window);
slouken@4484
   394
    }
slouken@4484
   395
slouken@4465
   396
    if (!x && !y) {
slouken@1895
   397
        return 0;
slouken@1895
   398
    }
slouken@1895
   399
slouken@1895
   400
    /* Post the event, if desired */
slouken@1895
   401
    posted = 0;
slouken@4429
   402
    if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
slouken@1895
   403
        SDL_Event event;
slouken@1895
   404
        event.type = SDL_MOUSEWHEEL;
slouken@4465
   405
        event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   406
        event.wheel.which = mouseID;
slouken@2152
   407
        event.wheel.x = x;
slouken@2152
   408
        event.wheel.y = y;
slouken@1895
   409
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   410
    }
slouken@1895
   411
    return posted;
slouken@1895
   412
}
slouken@1895
   413
slouken@1895
   414
void
slouken@4465
   415
SDL_MouseQuit(void)
slouken@4465
   416
{
slouken@7493
   417
    SDL_Cursor *cursor, *next;
slouken@7493
   418
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@7493
   419
icculus@8927
   420
    SDL_CaptureMouse(SDL_FALSE);
slouken@8049
   421
    SDL_SetRelativeMouseMode(SDL_FALSE);
slouken@7493
   422
    SDL_ShowCursor(1);
slouken@7493
   423
slouken@7493
   424
    cursor = mouse->cursors;
slouken@7493
   425
    while (cursor) {
slouken@7493
   426
        next = cursor->next;
slouken@7493
   427
        SDL_FreeCursor(cursor);
slouken@7493
   428
        cursor = next;
slouken@7493
   429
    }
slouken@7493
   430
slouken@7493
   431
    if (mouse->def_cursor && mouse->FreeCursor) {
slouken@7493
   432
        mouse->FreeCursor(mouse->def_cursor);
slouken@7493
   433
    }
slouken@7493
   434
slouken@8066
   435
    if (mouse->clickstate) {
slouken@8066
   436
        SDL_free(mouse->clickstate);
slouken@8066
   437
    }
slouken@8066
   438
slouken@7493
   439
    SDL_zerop(mouse);
slouken@4465
   440
}
slouken@4465
   441
slouken@6673
   442
Uint32
slouken@4465
   443
SDL_GetMouseState(int *x, int *y)
slouken@4465
   444
{
slouken@5371
   445
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   446
slouken@4465
   447
    if (x) {
slouken@4465
   448
        *x = mouse->x;
slouken@4465
   449
    }
slouken@4465
   450
    if (y) {
slouken@4465
   451
        *y = mouse->y;
slouken@4465
   452
    }
slouken@4465
   453
    return mouse->buttonstate;
slouken@4465
   454
}
slouken@4465
   455
slouken@6673
   456
Uint32
slouken@4465
   457
SDL_GetRelativeMouseState(int *x, int *y)
slouken@4465
   458
{
slouken@5371
   459
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   460
slouken@4465
   461
    if (x) {
slouken@4465
   462
        *x = mouse->xdelta;
slouken@4465
   463
    }
slouken@4465
   464
    if (y) {
slouken@4465
   465
        *y = mouse->ydelta;
slouken@4465
   466
    }
slouken@4465
   467
    mouse->xdelta = 0;
slouken@4465
   468
    mouse->ydelta = 0;
slouken@4465
   469
    return mouse->buttonstate;
slouken@4465
   470
}
slouken@4465
   471
slouken@4465
   472
void
slouken@3685
   473
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
slouken@1895
   474
{
slouken@5371
   475
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@7191
   476
icculus@8944
   477
    if ( window == NULL ) {
slouken@7191
   478
        window = mouse->focus;
icculus@8944
   479
    }
slouken@7191
   480
icculus@8944
   481
    if ( window == NULL ) {
slouken@7191
   482
        return;
icculus@8944
   483
    }
slouken@1895
   484
slouken@1895
   485
    if (mouse->WarpMouse) {
slouken@5371
   486
        mouse->WarpMouse(window, x, y);
slouken@1895
   487
    } else {
slouken@6950
   488
        SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@1895
   489
    }
slouken@1895
   490
}
slouken@1895
   491
slouken@8071
   492
static SDL_bool
slouken@8071
   493
ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
slouken@8071
   494
{
slouken@8071
   495
    const char *hint;
slouken@8071
   496
slouken@8071
   497
    if (!mouse->SetRelativeMouseMode) {
slouken@8071
   498
        return SDL_TRUE;
slouken@8071
   499
    }
slouken@8071
   500
slouken@8071
   501
    hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
slouken@8071
   502
    if (hint) {
slouken@8071
   503
        if (*hint == '0') {
slouken@8071
   504
            return SDL_FALSE;
slouken@8071
   505
        } else {
slouken@8071
   506
            return SDL_TRUE;
slouken@8071
   507
        }
slouken@8071
   508
    }
slouken@8071
   509
    return SDL_FALSE;
slouken@8071
   510
}
slouken@8071
   511
slouken@4465
   512
int
slouken@4465
   513
SDL_SetRelativeMouseMode(SDL_bool enabled)
slouken@4465
   514
{
slouken@5371
   515
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7107
   516
    SDL_Window *focusWindow = SDL_GetKeyboardFocus();
slouken@4465
   517
slouken@5406
   518
    if (enabled == mouse->relative_mode) {
slouken@5406
   519
        return 0;
slouken@5406
   520
    }
slouken@5406
   521
jorgen@7107
   522
    if (enabled && focusWindow) {
jorgen@7107
   523
        /* Center it in the focused window to prevent clicks from going through
jorgen@7107
   524
         * to background windows.
jorgen@7107
   525
         */
jorgen@7107
   526
        SDL_SetMouseFocus(focusWindow);
jorgen@7107
   527
        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
jorgen@7107
   528
    }
jorgen@7107
   529
slouken@8071
   530
    /* Set the relative mode */
slouken@8071
   531
    if (!enabled && mouse->relative_mode_warp) {
slouken@8071
   532
        mouse->relative_mode_warp = SDL_FALSE;
slouken@8071
   533
    } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
slouken@8071
   534
        mouse->relative_mode_warp = SDL_TRUE;
slouken@8071
   535
    } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
slouken@8269
   536
        if (enabled) {
philipp@8776
   537
            /* Fall back to warp mode if native relative mode failed */
slouken@8269
   538
            mouse->relative_mode_warp = SDL_TRUE;
slouken@8269
   539
        }
slouken@5406
   540
    }
slouken@4465
   541
    mouse->relative_mode = enabled;
slouken@4465
   542
slouken@8071
   543
    if (mouse->focus) {
slouken@8071
   544
        SDL_UpdateWindowGrab(mouse->focus);
slouken@8071
   545
slouken@8071
   546
        /* Put the cursor back to where the application expects it */
slouken@8071
   547
        if (!enabled) {
slouken@8071
   548
            SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
slouken@8071
   549
        }
slouken@4465
   550
    }
slouken@4465
   551
slouken@8071
   552
    /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
slouken@5406
   553
    SDL_FlushEvent(SDL_MOUSEMOTION);
slouken@5406
   554
slouken@4465
   555
    /* Update cursor visibility */
slouken@4465
   556
    SDL_SetCursor(NULL);
slouken@4465
   557
slouken@4465
   558
    return 0;
slouken@4465
   559
}
slouken@4465
   560
slouken@4465
   561
SDL_bool
slouken@4465
   562
SDL_GetRelativeMouseMode()
slouken@4465
   563
{
slouken@5371
   564
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   565
slouken@4465
   566
    return mouse->relative_mode;
slouken@4465
   567
}
slouken@4465
   568
icculus@8927
   569
int
icculus@8927
   570
SDL_CaptureMouse(SDL_bool enabled)
icculus@8927
   571
{
icculus@8927
   572
    SDL_Mouse *mouse = SDL_GetMouse();
icculus@8927
   573
    SDL_Window *focusWindow;
icculus@8927
   574
    SDL_bool isCaptured;
icculus@8927
   575
icculus@8927
   576
    if (!mouse->CaptureMouse) {
icculus@8927
   577
        return SDL_Unsupported();
icculus@8927
   578
    }
icculus@8927
   579
icculus@8927
   580
    focusWindow = SDL_GetKeyboardFocus();
icculus@8927
   581
icculus@8927
   582
    isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
icculus@8927
   583
    if (isCaptured == enabled) {
icculus@8927
   584
        return 0;  /* already done! */
icculus@8927
   585
    }
icculus@8927
   586
icculus@8927
   587
    if (enabled) {
icculus@8927
   588
        if (!focusWindow) {
icculus@8927
   589
            return SDL_SetError("No window has focus");
icculus@8927
   590
        } else if (mouse->CaptureMouse(focusWindow) == -1) {
icculus@8927
   591
            return -1;  /* CaptureMouse() should call SetError */
icculus@8927
   592
        }
icculus@8927
   593
        focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
icculus@8927
   594
    } else {
icculus@8927
   595
        if (mouse->CaptureMouse(NULL) == -1) {
icculus@8927
   596
            return -1;  /* CaptureMouse() should call SetError */
icculus@8927
   597
        }
icculus@8927
   598
        focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
icculus@8927
   599
    }
icculus@8927
   600
icculus@8927
   601
    return 0;
icculus@8927
   602
}
icculus@8927
   603
icculus@8927
   604
slouken@1895
   605
SDL_Cursor *
slouken@1895
   606
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
slouken@1895
   607
                 int w, int h, int hot_x, int hot_y)
slouken@1895
   608
{
slouken@1895
   609
    SDL_Surface *surface;
slouken@1895
   610
    SDL_Cursor *cursor;
slouken@1895
   611
    int x, y;
slouken@1895
   612
    Uint32 *pixel;
slouken@4465
   613
    Uint8 datab = 0, maskb = 0;
slouken@1895
   614
    const Uint32 black = 0xFF000000;
slouken@1895
   615
    const Uint32 white = 0xFFFFFFFF;
slouken@1895
   616
    const Uint32 transparent = 0x00000000;
slouken@1895
   617
slouken@1895
   618
    /* Make sure the width is a multiple of 8 */
slouken@1895
   619
    w = ((w + 7) & ~7);
slouken@1895
   620
slouken@1895
   621
    /* Create the surface from a bitmap */
slouken@5473
   622
    surface = SDL_CreateRGBSurface(0, w, h, 32,
slouken@5473
   623
                                   0x00FF0000,
slouken@5473
   624
                                   0x0000FF00,
slouken@5473
   625
                                   0x000000FF,
slouken@5473
   626
                                   0xFF000000);
slouken@1895
   627
    if (!surface) {
slouken@1895
   628
        return NULL;
slouken@1895
   629
    }
slouken@1895
   630
    for (y = 0; y < h; ++y) {
slouken@1895
   631
        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
slouken@1895
   632
        for (x = 0; x < w; ++x) {
slouken@1895
   633
            if ((x % 8) == 0) {
slouken@1895
   634
                datab = *data++;
slouken@1895
   635
                maskb = *mask++;
slouken@1895
   636
            }
slouken@1895
   637
            if (maskb & 0x80) {
slouken@1895
   638
                *pixel++ = (datab & 0x80) ? black : white;
slouken@1895
   639
            } else {
slouken@1895
   640
                *pixel++ = (datab & 0x80) ? black : transparent;
slouken@1895
   641
            }
slouken@1895
   642
            datab <<= 1;
slouken@1895
   643
            maskb <<= 1;
slouken@1895
   644
        }
slouken@1895
   645
    }
slouken@1895
   646
slouken@5473
   647
    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
slouken@5473
   648
slouken@5473
   649
    SDL_FreeSurface(surface);
slouken@5473
   650
slouken@5473
   651
    return cursor;
slouken@5473
   652
}
slouken@5473
   653
slouken@5473
   654
SDL_Cursor *
slouken@5473
   655
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
slouken@5473
   656
{
slouken@5473
   657
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5473
   658
    SDL_Surface *temp = NULL;
slouken@5473
   659
    SDL_Cursor *cursor;
slouken@5473
   660
slouken@5473
   661
    if (!surface) {
slouken@5473
   662
        SDL_SetError("Passed NULL cursor surface");
slouken@5473
   663
        return NULL;
slouken@5473
   664
    }
slouken@5473
   665
slouken@5473
   666
    if (!mouse->CreateCursor) {
slouken@5473
   667
        SDL_SetError("Cursors are not currently supported");
slouken@5473
   668
        return NULL;
slouken@5473
   669
    }
slouken@5473
   670
slouken@5473
   671
    /* Sanity check the hot spot */
slouken@5473
   672
    if ((hot_x < 0) || (hot_y < 0) ||
slouken@5473
   673
        (hot_x >= surface->w) || (hot_y >= surface->h)) {
slouken@5473
   674
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@5473
   675
        return NULL;
slouken@5473
   676
    }
slouken@5473
   677
slouken@5473
   678
    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
slouken@5473
   679
        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
slouken@5473
   680
        if (!temp) {
slouken@5473
   681
            return NULL;
slouken@5473
   682
        }
slouken@5473
   683
        surface = temp;
slouken@5473
   684
    }
slouken@5473
   685
slouken@1895
   686
    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
slouken@1895
   687
    if (cursor) {
slouken@1895
   688
        cursor->next = mouse->cursors;
slouken@1895
   689
        mouse->cursors = cursor;
slouken@1895
   690
    }
slouken@1895
   691
slouken@7720
   692
    SDL_FreeSurface(temp);
slouken@1895
   693
slouken@1895
   694
    return cursor;
slouken@1895
   695
}
slouken@1895
   696
mikesart@6675
   697
SDL_Cursor *
mikesart@6675
   698
SDL_CreateSystemCursor(SDL_SystemCursor id)
mikesart@6675
   699
{
mikesart@6675
   700
    SDL_Mouse *mouse = SDL_GetMouse();
mikesart@6675
   701
    SDL_Cursor *cursor;
mikesart@6675
   702
mikesart@6675
   703
    if (!mouse->CreateSystemCursor) {
mikesart@6675
   704
        SDL_SetError("CreateSystemCursor is not currently supported");
mikesart@6675
   705
        return NULL;
mikesart@6675
   706
    }
mikesart@6675
   707
slouken@7191
   708
    cursor = mouse->CreateSystemCursor(id);
mikesart@6675
   709
    if (cursor) {
mikesart@6675
   710
        cursor->next = mouse->cursors;
mikesart@6675
   711
        mouse->cursors = cursor;
mikesart@6675
   712
    }
mikesart@6675
   713
slouken@7191
   714
    return cursor;
mikesart@6675
   715
}
mikesart@6675
   716
slouken@1895
   717
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@1895
   718
   if this is desired for any reason.  This is used when setting
slouken@1895
   719
   the video mode and when the SDL window gains the mouse focus.
slouken@1895
   720
 */
slouken@1895
   721
void
slouken@1895
   722
SDL_SetCursor(SDL_Cursor * cursor)
slouken@1895
   723
{
slouken@5371
   724
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   725
slouken@1895
   726
    /* Set the new cursor */
slouken@1895
   727
    if (cursor) {
slouken@1895
   728
        /* Make sure the cursor is still valid for this mouse */
slouken@5405
   729
        if (cursor != mouse->def_cursor) {
slouken@5405
   730
            SDL_Cursor *found;
slouken@5405
   731
            for (found = mouse->cursors; found; found = found->next) {
slouken@5405
   732
                if (found == cursor) {
slouken@5405
   733
                    break;
slouken@5405
   734
                }
slouken@1895
   735
            }
slouken@5405
   736
            if (!found) {
slouken@5405
   737
                SDL_SetError("Cursor not associated with the current mouse");
slouken@5405
   738
                return;
slouken@5405
   739
            }
slouken@1895
   740
        }
slouken@1895
   741
        mouse->cur_cursor = cursor;
slouken@1895
   742
    } else {
ghostunderscore@6301
   743
        if (mouse->focus) {
ghostunderscore@6301
   744
            cursor = mouse->cur_cursor;
ghostunderscore@6301
   745
        } else {
ghostunderscore@6301
   746
            cursor = mouse->def_cursor;
ghostunderscore@6301
   747
        }
slouken@1895
   748
    }
slouken@1895
   749
slouken@1895
   750
    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
slouken@1895
   751
        if (mouse->ShowCursor) {
slouken@1895
   752
            mouse->ShowCursor(cursor);
slouken@1895
   753
        }
slouken@1895
   754
    } else {
slouken@1895
   755
        if (mouse->ShowCursor) {
slouken@1895
   756
            mouse->ShowCursor(NULL);
slouken@1895
   757
        }
slouken@1895
   758
    }
slouken@1895
   759
}
slouken@1895
   760
slouken@1895
   761
SDL_Cursor *
slouken@1895
   762
SDL_GetCursor(void)
slouken@1895
   763
{
slouken@5371
   764
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   765
slouken@1895
   766
    if (!mouse) {
slouken@1895
   767
        return NULL;
slouken@1895
   768
    }
slouken@1895
   769
    return mouse->cur_cursor;
slouken@1895
   770
}
slouken@1895
   771
jorgen@7104
   772
SDL_Cursor *
jorgen@7104
   773
SDL_GetDefaultCursor(void)
jorgen@7104
   774
{
jorgen@7104
   775
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7104
   776
jorgen@7104
   777
    if (!mouse) {
jorgen@7104
   778
        return NULL;
jorgen@7104
   779
    }
jorgen@7104
   780
    return mouse->def_cursor;
jorgen@7104
   781
}
jorgen@7104
   782
slouken@1895
   783
void
slouken@1895
   784
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@1895
   785
{
slouken@5371
   786
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   787
    SDL_Cursor *curr, *prev;
slouken@1895
   788
slouken@1895
   789
    if (!cursor) {
slouken@1895
   790
        return;
slouken@1895
   791
    }
slouken@1895
   792
slouken@1895
   793
    if (cursor == mouse->def_cursor) {
slouken@1895
   794
        return;
slouken@1895
   795
    }
slouken@1895
   796
    if (cursor == mouse->cur_cursor) {
slouken@1895
   797
        SDL_SetCursor(mouse->def_cursor);
slouken@1895
   798
    }
slouken@1895
   799
slouken@1895
   800
    for (prev = NULL, curr = mouse->cursors; curr;
slouken@1895
   801
         prev = curr, curr = curr->next) {
slouken@1895
   802
        if (curr == cursor) {
slouken@1895
   803
            if (prev) {
slouken@1895
   804
                prev->next = curr->next;
slouken@1895
   805
            } else {
slouken@1895
   806
                mouse->cursors = curr->next;
slouken@1895
   807
            }
slouken@1895
   808
slouken@1895
   809
            if (mouse->FreeCursor) {
slouken@1895
   810
                mouse->FreeCursor(curr);
slouken@1895
   811
            }
slouken@1895
   812
            return;
slouken@1895
   813
        }
slouken@1895
   814
    }
slouken@1895
   815
}
slouken@1895
   816
slouken@1895
   817
int
slouken@1895
   818
SDL_ShowCursor(int toggle)
slouken@1895
   819
{
slouken@5371
   820
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   821
    SDL_bool shown;
slouken@1895
   822
slouken@1895
   823
    if (!mouse) {
slouken@1895
   824
        return 0;
slouken@1895
   825
    }
slouken@1895
   826
slouken@1895
   827
    shown = mouse->cursor_shown;
slouken@1895
   828
    if (toggle >= 0) {
slouken@1895
   829
        if (toggle) {
slouken@1895
   830
            mouse->cursor_shown = SDL_TRUE;
slouken@1895
   831
        } else {
slouken@1895
   832
            mouse->cursor_shown = SDL_FALSE;
slouken@1895
   833
        }
slouken@1895
   834
        if (mouse->cursor_shown != shown) {
slouken@1895
   835
            SDL_SetCursor(NULL);
slouken@1895
   836
        }
slouken@1895
   837
    }
slouken@1895
   838
    return shown;
slouken@1895
   839
}
slouken@1895
   840
jorgen@7097
   841
/* vi: set ts=4 sw=4 expandtab: */