src/events/SDL_mouse.c
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Wed, 24 Apr 2013 12:20:51 -0700
changeset 7107 2fcf7bf1d2b2
parent 7104 4e4ca313000c
child 7191 75360622e65f
permissions -rw-r--r--
Move cursor into window when enabling relative mode or gaining focus in relative mode.

This prevents wonky behavior where the clicks won't go to the window
because the cursor was outside it when we enabled relative mode.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 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
*/
slouken@1402
    21
#include "SDL_config.h"
slouken@0
    22
slouken@0
    23
/* General mouse handling code for SDL */
slouken@0
    24
slouken@6666
    25
#include "SDL_assert.h"
slouken@0
    26
#include "SDL_events.h"
slouken@0
    27
#include "SDL_events_c.h"
slouken@1895
    28
#include "default_cursor.h"
slouken@3685
    29
#include "../video/SDL_sysvideo.h"
slouken@0
    30
slouken@6666
    31
/*#define DEBUG_MOUSE*/
slouken@0
    32
slouken@5371
    33
/* The mouse state */
slouken@4465
    34
static SDL_Mouse SDL_mouse;
slouken@0
    35
jorgen@7089
    36
static int
jorgen@7089
    37
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
slouken@0
    38
slouken@0
    39
/* Public functions */
slouken@1895
    40
int
slouken@1895
    41
SDL_MouseInit(void)
slouken@0
    42
{
slouken@5376
    43
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5376
    44
slouken@5376
    45
    mouse->cursor_shown = SDL_TRUE;
slouken@5376
    46
slouken@1895
    47
    return (0);
slouken@1123
    48
}
slouken@0
    49
slouken@5405
    50
void
slouken@5405
    51
SDL_SetDefaultCursor(SDL_Cursor * cursor)
slouken@5405
    52
{
slouken@5405
    53
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5405
    54
slouken@5405
    55
    mouse->def_cursor = cursor;
slouken@5405
    56
    if (!mouse->cur_cursor) {
slouken@5405
    57
        SDL_SetCursor(cursor);
slouken@5405
    58
    }
slouken@5405
    59
}
slouken@5405
    60
slouken@5371
    61
SDL_Mouse *
slouken@5371
    62
SDL_GetMouse(void)
slouken@5371
    63
{
slouken@5371
    64
    return &SDL_mouse;
slouken@5371
    65
}
slouken@5371
    66
slouken@4465
    67
SDL_Window *
slouken@4465
    68
SDL_GetMouseFocus(void)
slouken@2710
    69
{
slouken@5371
    70
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@2940
    71
slouken@4465
    72
    return mouse->focus;
slouken@0
    73
}
slouken@0
    74
slouken@1895
    75
void
slouken@6666
    76
SDL_ResetMouse(void)
slouken@6666
    77
{
slouken@6666
    78
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6666
    79
    Uint8 i;
slouken@6666
    80
slouken@6666
    81
#ifdef DEBUG_MOUSE
slouken@6666
    82
    printf("Resetting mouse\n");
slouken@6666
    83
#endif
slouken@6666
    84
    for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
slouken@6666
    85
        if (mouse->buttonstate & SDL_BUTTON(i)) {
slouken@6950
    86
            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
slouken@6666
    87
        }
slouken@6666
    88
    }
slouken@6666
    89
    SDL_assert(mouse->buttonstate == 0);
slouken@6666
    90
}
slouken@6666
    91
slouken@6666
    92
void
slouken@4465
    93
SDL_SetMouseFocus(SDL_Window * window)
slouken@0
    94
{
slouken@5371
    95
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
    96
slouken@4465
    97
    if (mouse->focus == window) {
slouken@1895
    98
        return;
slouken@1895
    99
    }
slouken@1895
   100
slouken@6829
   101
    /* Actually, this ends up being a bad idea, because most operating
slouken@6829
   102
       systems have an implicit grab when you press the mouse button down
slouken@6829
   103
       so you can drag things out of the window and then get the mouse up
slouken@6829
   104
       when it happens.  So, #if 0...
slouken@6829
   105
    */
slouken@6829
   106
#if 0
slouken@6666
   107
    if (mouse->focus && !window) {
slouken@6666
   108
        /* We won't get anymore mouse messages, so reset mouse state */
slouken@6666
   109
        SDL_ResetMouse();
slouken@6666
   110
    }
slouken@6829
   111
#endif
slouken@6666
   112
slouken@1895
   113
    /* See if the current window has lost focus */
slouken@1895
   114
    if (mouse->focus) {
slouken@4465
   115
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
slouken@1895
   116
    }
slouken@1895
   117
slouken@3685
   118
    mouse->focus = window;
slouken@1895
   119
slouken@1895
   120
    if (mouse->focus) {
slouken@4465
   121
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
slouken@1895
   122
    }
slouken@6666
   123
slouken@6666
   124
    /* Update cursor visibility */
slouken@6666
   125
    SDL_SetCursor(NULL);
slouken@6666
   126
}
slouken@6666
   127
slouken@6666
   128
/* Check to see if we need to synthesize focus events */
slouken@6666
   129
static SDL_bool
slouken@6673
   130
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
slouken@6666
   131
{
slouken@6666
   132
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6666
   133
    int w, h;
slouken@6666
   134
    SDL_bool inWindow;
slouken@6666
   135
slouken@6666
   136
    SDL_GetWindowSize(window, &w, &h);
slouken@6666
   137
    if (x < 0 || y < 0 || x >= w || y >= h) {
slouken@6666
   138
        inWindow = SDL_FALSE;
slouken@6666
   139
    } else {
slouken@6666
   140
        inWindow = SDL_TRUE;
slouken@6666
   141
    }
slouken@6667
   142
slouken@6667
   143
/* Linux doesn't give you mouse events outside your window unless you grab
slouken@6667
   144
   the pointer.
slouken@6667
   145
slouken@6667
   146
   Windows doesn't give you mouse events outside your window unless you call
slouken@6667
   147
   SetCapture().
slouken@6667
   148
slouken@6667
   149
   Both of these are slightly scary changes, so for now we'll punt and if the
slouken@6667
   150
   mouse leaves the window you'll lose mouse focus and reset button state.
slouken@6667
   151
*/
slouken@6667
   152
#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
slouken@6666
   153
    if (!inWindow && !buttonstate) {
slouken@6667
   154
#else
slouken@6667
   155
    if (!inWindow) {
slouken@6667
   156
#endif
slouken@6666
   157
        if (window == mouse->focus) {
slouken@6666
   158
#ifdef DEBUG_MOUSE
jorgen@7089
   159
            printf("Mouse left window, synthesizing move & focus lost event\n");
slouken@6666
   160
#endif
jorgen@7089
   161
            SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@6666
   162
            SDL_SetMouseFocus(NULL);
slouken@6666
   163
        }
slouken@6666
   164
        return SDL_FALSE;
slouken@6666
   165
    }
slouken@6666
   166
slouken@6666
   167
    if (window != mouse->focus) {
slouken@6666
   168
#ifdef DEBUG_MOUSE
jorgen@7097
   169
         printf("Mouse entered window, synthesizing focus gain & move event\n");
slouken@6666
   170
#endif
jorgen@7097
   171
         SDL_SetMouseFocus(window);
jorgen@7097
   172
         SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@6666
   173
    }
slouken@6666
   174
    return SDL_TRUE;
slouken@1895
   175
}
slouken@1895
   176
slouken@1895
   177
int
slouken@6950
   178
SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
slouken@1895
   179
{
jorgen@7089
   180
    if (window && !relative) {
jorgen@7089
   181
        SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7089
   182
        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
jorgen@7089
   183
            return 0;
jorgen@7089
   184
        }
jorgen@7089
   185
    }
jorgen@7089
   186
jorgen@7089
   187
    return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
jorgen@7089
   188
}
jorgen@7089
   189
jorgen@7089
   190
static int
jorgen@7089
   191
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
jorgen@7089
   192
{
slouken@5371
   193
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   194
    int posted;
slouken@1895
   195
    int xrel;
slouken@1895
   196
    int yrel;
slouken@2860
   197
    int x_max = 0, y_max = 0;
slouken@1895
   198
slouken@6666
   199
    /* relative motion is calculated regarding the system cursor last position */
slouken@2842
   200
    if (relative) {
slouken@2842
   201
        xrel = x;
slouken@2842
   202
        yrel = y;
slouken@2860
   203
        x = (mouse->last_x + x);
slouken@2860
   204
        y = (mouse->last_y + y);
slouken@2842
   205
    } else {
slouken@2860
   206
        xrel = x - mouse->last_x;
slouken@2860
   207
        yrel = y - mouse->last_y;
slouken@2842
   208
    }
slouken@2710
   209
slouken@1895
   210
    /* Drop events that don't change state */
slouken@1895
   211
    if (!xrel && !yrel) {
slouken@6666
   212
#ifdef DEBUG_MOUSE
slouken@1895
   213
        printf("Mouse event didn't change state - dropped!\n");
slouken@1895
   214
#endif
slouken@1895
   215
        return 0;
slouken@1895
   216
    }
slouken@1895
   217
slouken@2710
   218
    /* Update internal mouse coordinates */
slouken@2710
   219
    if (mouse->relative_mode == SDL_FALSE) {
slouken@1895
   220
        mouse->x = x;
slouken@1895
   221
        mouse->y = y;
slouken@2710
   222
    } else {
slouken@2860
   223
        mouse->x += xrel;
slouken@2860
   224
        mouse->y += yrel;
slouken@2860
   225
    }
slouken@2849
   226
slouken@2860
   227
    SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
slouken@5370
   228
    --x_max;
slouken@5370
   229
    --y_max;
slouken@2849
   230
slouken@2860
   231
    /* make sure that the pointers find themselves inside the windows */
slouken@5370
   232
    if (mouse->x > x_max) {
slouken@2860
   233
        mouse->x = x_max;
slouken@5370
   234
    }
slouken@5370
   235
    if (mouse->x < 0) {
slouken@2860
   236
        mouse->x = 0;
slouken@1895
   237
    }
slouken@2860
   238
slouken@5370
   239
    if (mouse->y > y_max) {
slouken@2860
   240
        mouse->y = y_max;
slouken@5370
   241
    }
slouken@5370
   242
    if (mouse->y < 0) {
slouken@2860
   243
        mouse->y = 0;
slouken@2860
   244
    }
slouken@2860
   245
slouken@1895
   246
    mouse->xdelta += xrel;
slouken@1895
   247
    mouse->ydelta += yrel;
slouken@1895
   248
slouken@4465
   249
#if 0 /* FIXME */
slouken@1895
   250
    /* Move the mouse cursor, if needed */
slouken@1895
   251
    if (mouse->cursor_shown && !mouse->relative_mode &&
slouken@1895
   252
        mouse->MoveCursor && mouse->cur_cursor) {
slouken@1895
   253
        mouse->MoveCursor(mouse->cur_cursor);
slouken@1895
   254
    }
slouken@4465
   255
#endif
slouken@1895
   256
slouken@1895
   257
    /* Post the event, if desired */
slouken@1895
   258
    posted = 0;
slouken@4465
   259
    if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
slouken@1895
   260
        SDL_Event event;
slouken@1895
   261
        event.motion.type = SDL_MOUSEMOTION;
slouken@4465
   262
        event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   263
        event.motion.which = mouseID;
slouken@1895
   264
        event.motion.state = mouse->buttonstate;
slouken@1895
   265
        event.motion.x = mouse->x;
slouken@1895
   266
        event.motion.y = mouse->y;
slouken@1895
   267
        event.motion.xrel = xrel;
slouken@1895
   268
        event.motion.yrel = yrel;
slouken@1895
   269
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   270
    }
slouken@6666
   271
    /* Use unclamped values if we're getting events outside the window */
slouken@6666
   272
    mouse->last_x = x;
slouken@6666
   273
    mouse->last_y = y;
slouken@1895
   274
    return posted;
slouken@1895
   275
}
slouken@1895
   276
slouken@1895
   277
int
slouken@6950
   278
SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
slouken@1895
   279
{
slouken@5371
   280
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   281
    int posted;
slouken@4429
   282
    Uint32 type;
slouken@6673
   283
    Uint32 buttonstate = mouse->buttonstate;
slouken@4484
   284
slouken@1895
   285
    /* Figure out which event to perform */
slouken@1895
   286
    switch (state) {
slouken@1895
   287
    case SDL_PRESSED:
slouken@1895
   288
        type = SDL_MOUSEBUTTONDOWN;
slouken@6666
   289
        buttonstate |= SDL_BUTTON(button);
slouken@1895
   290
        break;
slouken@1895
   291
    case SDL_RELEASED:
slouken@1895
   292
        type = SDL_MOUSEBUTTONUP;
slouken@6666
   293
        buttonstate &= ~SDL_BUTTON(button);
slouken@1895
   294
        break;
slouken@1895
   295
    default:
slouken@1895
   296
        /* Invalid state -- bail */
slouken@1895
   297
        return 0;
slouken@1895
   298
    }
slouken@1895
   299
slouken@6666
   300
    /* We do this after calculating buttonstate so button presses gain focus */
slouken@6666
   301
    if (window && state == SDL_PRESSED) {
slouken@6666
   302
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   303
    }
slouken@6666
   304
slouken@6666
   305
    if (buttonstate == mouse->buttonstate) {
slouken@6666
   306
        /* Ignore this event, no state change */
slouken@6666
   307
        return 0;
slouken@6666
   308
    }
slouken@6666
   309
    mouse->buttonstate = buttonstate;
slouken@6666
   310
slouken@1895
   311
    /* Post the event, if desired */
slouken@1895
   312
    posted = 0;
slouken@4429
   313
    if (SDL_GetEventState(type) == SDL_ENABLE) {
slouken@1895
   314
        SDL_Event event;
slouken@1895
   315
        event.type = type;
slouken@6950
   316
        event.button.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   317
        event.button.which = mouseID;
slouken@1895
   318
        event.button.state = state;
slouken@1895
   319
        event.button.button = button;
slouken@1895
   320
        event.button.x = mouse->x;
slouken@1895
   321
        event.button.y = mouse->y;
slouken@1895
   322
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   323
    }
slouken@6666
   324
slouken@6666
   325
    /* We do this after dispatching event so button releases can lose focus */
slouken@6666
   326
    if (window && state == SDL_RELEASED) {
slouken@6666
   327
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   328
    }
slouken@6666
   329
slouken@1895
   330
    return posted;
slouken@1895
   331
}
slouken@1895
   332
slouken@1895
   333
int
slouken@6950
   334
SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y)
slouken@1895
   335
{
slouken@5371
   336
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   337
    int posted;
slouken@1895
   338
slouken@4484
   339
    if (window) {
slouken@4484
   340
        SDL_SetMouseFocus(window);
slouken@4484
   341
    }
slouken@4484
   342
slouken@4465
   343
    if (!x && !y) {
slouken@1895
   344
        return 0;
slouken@1895
   345
    }
slouken@1895
   346
slouken@1895
   347
    /* Post the event, if desired */
slouken@1895
   348
    posted = 0;
slouken@4429
   349
    if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
slouken@1895
   350
        SDL_Event event;
slouken@1895
   351
        event.type = SDL_MOUSEWHEEL;
slouken@4465
   352
        event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   353
        event.wheel.which = mouseID;
slouken@2152
   354
        event.wheel.x = x;
slouken@2152
   355
        event.wheel.y = y;
slouken@1895
   356
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   357
    }
slouken@1895
   358
    return posted;
slouken@1895
   359
}
slouken@1895
   360
slouken@1895
   361
void
slouken@4465
   362
SDL_MouseQuit(void)
slouken@4465
   363
{
slouken@4465
   364
}
slouken@4465
   365
slouken@6673
   366
Uint32
slouken@4465
   367
SDL_GetMouseState(int *x, int *y)
slouken@4465
   368
{
slouken@5371
   369
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   370
slouken@4465
   371
    if (x) {
slouken@4465
   372
        *x = mouse->x;
slouken@4465
   373
    }
slouken@4465
   374
    if (y) {
slouken@4465
   375
        *y = mouse->y;
slouken@4465
   376
    }
slouken@4465
   377
    return mouse->buttonstate;
slouken@4465
   378
}
slouken@4465
   379
slouken@6673
   380
Uint32
slouken@4465
   381
SDL_GetRelativeMouseState(int *x, int *y)
slouken@4465
   382
{
slouken@5371
   383
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   384
slouken@4465
   385
    if (x) {
slouken@4465
   386
        *x = mouse->xdelta;
slouken@4465
   387
    }
slouken@4465
   388
    if (y) {
slouken@4465
   389
        *y = mouse->ydelta;
slouken@4465
   390
    }
slouken@4465
   391
    mouse->xdelta = 0;
slouken@4465
   392
    mouse->ydelta = 0;
slouken@4465
   393
    return mouse->buttonstate;
slouken@4465
   394
}
slouken@4465
   395
slouken@4465
   396
void
slouken@3685
   397
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
slouken@1895
   398
{
slouken@5371
   399
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6755
   400
	
slouken@6755
   401
	if ( window == NULL )
slouken@6755
   402
		window = mouse->focus;
slouken@6755
   403
	
slouken@6755
   404
	if ( window == NULL )
slouken@6755
   405
		return;
slouken@1895
   406
slouken@1895
   407
    if (mouse->WarpMouse) {
slouken@5371
   408
        mouse->WarpMouse(window, x, y);
slouken@1895
   409
    } else {
slouken@6950
   410
        SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@1895
   411
    }
slouken@1895
   412
}
slouken@1895
   413
slouken@4465
   414
int
slouken@4465
   415
SDL_SetRelativeMouseMode(SDL_bool enabled)
slouken@4465
   416
{
slouken@5371
   417
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7107
   418
    SDL_Window *focusWindow = SDL_GetKeyboardFocus();
jorgen@7107
   419
    int original_x = mouse->x, original_y = mouse->y;
slouken@4465
   420
slouken@5406
   421
    if (enabled == mouse->relative_mode) {
slouken@5406
   422
        return 0;
slouken@5406
   423
    }
slouken@5406
   424
slouken@5406
   425
    if (!mouse->SetRelativeMouseMode) {
icculus@7037
   426
        return SDL_Unsupported();
slouken@5406
   427
    }
slouken@5406
   428
jorgen@7107
   429
    if (enabled && focusWindow) {
jorgen@7107
   430
        /* Center it in the focused window to prevent clicks from going through
jorgen@7107
   431
         * to background windows.
jorgen@7107
   432
         */
jorgen@7107
   433
        SDL_SetMouseFocus(focusWindow);
jorgen@7107
   434
        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
jorgen@7107
   435
    }
jorgen@7107
   436
slouken@5406
   437
    if (mouse->SetRelativeMouseMode(enabled) < 0) {
slouken@5406
   438
        return -1;
slouken@5406
   439
    }
slouken@4465
   440
slouken@4465
   441
    /* Set the relative mode */
slouken@4465
   442
    mouse->relative_mode = enabled;
slouken@4465
   443
ghostunderscore@6302
   444
    if (enabled) {
ghostunderscore@6302
   445
        /* Save the expected mouse position */
jorgen@7107
   446
        mouse->original_x = original_x;
jorgen@7107
   447
        mouse->original_y = original_y;
ghostunderscore@6302
   448
    } else if (mouse->focus) {
slouken@4465
   449
        /* Restore the expected mouse position */
ghostunderscore@6302
   450
        SDL_WarpMouseInWindow(mouse->focus, mouse->original_x, mouse->original_y);
slouken@4465
   451
    }
slouken@4465
   452
slouken@5406
   453
    /* Flush pending mouse motion */
slouken@5406
   454
    SDL_FlushEvent(SDL_MOUSEMOTION);
slouken@5406
   455
slouken@4465
   456
    /* Update cursor visibility */
slouken@4465
   457
    SDL_SetCursor(NULL);
slouken@4465
   458
slouken@4465
   459
    return 0;
slouken@4465
   460
}
slouken@4465
   461
slouken@4465
   462
SDL_bool
slouken@4465
   463
SDL_GetRelativeMouseMode()
slouken@4465
   464
{
slouken@5371
   465
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   466
slouken@4465
   467
    return mouse->relative_mode;
slouken@4465
   468
}
slouken@4465
   469
slouken@1895
   470
SDL_Cursor *
slouken@1895
   471
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
slouken@1895
   472
                 int w, int h, int hot_x, int hot_y)
slouken@1895
   473
{
slouken@1895
   474
    SDL_Surface *surface;
slouken@1895
   475
    SDL_Cursor *cursor;
slouken@1895
   476
    int x, y;
slouken@1895
   477
    Uint32 *pixel;
slouken@4465
   478
    Uint8 datab = 0, maskb = 0;
slouken@1895
   479
    const Uint32 black = 0xFF000000;
slouken@1895
   480
    const Uint32 white = 0xFFFFFFFF;
slouken@1895
   481
    const Uint32 transparent = 0x00000000;
slouken@1895
   482
slouken@1895
   483
    /* Make sure the width is a multiple of 8 */
slouken@1895
   484
    w = ((w + 7) & ~7);
slouken@1895
   485
slouken@1895
   486
    /* Create the surface from a bitmap */
slouken@5473
   487
    surface = SDL_CreateRGBSurface(0, w, h, 32,
slouken@5473
   488
                                   0x00FF0000,
slouken@5473
   489
                                   0x0000FF00,
slouken@5473
   490
                                   0x000000FF,
slouken@5473
   491
                                   0xFF000000);
slouken@1895
   492
    if (!surface) {
slouken@1895
   493
        return NULL;
slouken@1895
   494
    }
slouken@1895
   495
    for (y = 0; y < h; ++y) {
slouken@1895
   496
        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
slouken@1895
   497
        for (x = 0; x < w; ++x) {
slouken@1895
   498
            if ((x % 8) == 0) {
slouken@1895
   499
                datab = *data++;
slouken@1895
   500
                maskb = *mask++;
slouken@1895
   501
            }
slouken@1895
   502
            if (maskb & 0x80) {
slouken@1895
   503
                *pixel++ = (datab & 0x80) ? black : white;
slouken@1895
   504
            } else {
slouken@1895
   505
                *pixel++ = (datab & 0x80) ? black : transparent;
slouken@1895
   506
            }
slouken@1895
   507
            datab <<= 1;
slouken@1895
   508
            maskb <<= 1;
slouken@1895
   509
        }
slouken@1895
   510
    }
slouken@1895
   511
slouken@5473
   512
    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
slouken@5473
   513
slouken@5473
   514
    SDL_FreeSurface(surface);
slouken@5473
   515
slouken@5473
   516
    return cursor;
slouken@5473
   517
}
slouken@5473
   518
slouken@5473
   519
SDL_Cursor *
slouken@5473
   520
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
slouken@5473
   521
{
slouken@5473
   522
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5473
   523
    SDL_Surface *temp = NULL;
slouken@5473
   524
    SDL_Cursor *cursor;
slouken@5473
   525
slouken@5473
   526
    if (!surface) {
slouken@5473
   527
        SDL_SetError("Passed NULL cursor surface");
slouken@5473
   528
        return NULL;
slouken@5473
   529
    }
slouken@5473
   530
slouken@5473
   531
    if (!mouse->CreateCursor) {
slouken@5473
   532
        SDL_SetError("Cursors are not currently supported");
slouken@5473
   533
        return NULL;
slouken@5473
   534
    }
slouken@5473
   535
slouken@5473
   536
    /* Sanity check the hot spot */
slouken@5473
   537
    if ((hot_x < 0) || (hot_y < 0) ||
slouken@5473
   538
        (hot_x >= surface->w) || (hot_y >= surface->h)) {
slouken@5473
   539
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@5473
   540
        return NULL;
slouken@5473
   541
    }
slouken@5473
   542
slouken@5473
   543
    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
slouken@5473
   544
        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
slouken@5473
   545
        if (!temp) {
slouken@5473
   546
            return NULL;
slouken@5473
   547
        }
slouken@5473
   548
        surface = temp;
slouken@5473
   549
    }
slouken@5473
   550
slouken@1895
   551
    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
slouken@1895
   552
    if (cursor) {
slouken@1895
   553
        cursor->next = mouse->cursors;
slouken@1895
   554
        mouse->cursors = cursor;
slouken@1895
   555
    }
slouken@1895
   556
slouken@5473
   557
    if (temp) {
slouken@5473
   558
        SDL_FreeSurface(temp);
slouken@5473
   559
    }
slouken@1895
   560
slouken@1895
   561
    return cursor;
slouken@1895
   562
}
slouken@1895
   563
mikesart@6675
   564
SDL_Cursor *
mikesart@6675
   565
SDL_CreateSystemCursor(SDL_SystemCursor id)
mikesart@6675
   566
{
mikesart@6675
   567
    SDL_Mouse *mouse = SDL_GetMouse();
mikesart@6675
   568
    SDL_Cursor *cursor;
mikesart@6675
   569
mikesart@6675
   570
    if (!mouse->CreateSystemCursor) {
mikesart@6675
   571
        SDL_SetError("CreateSystemCursor is not currently supported");
mikesart@6675
   572
        return NULL;
mikesart@6675
   573
    }
mikesart@6675
   574
mikesart@6675
   575
	cursor = mouse->CreateSystemCursor(id);
mikesart@6675
   576
    if (cursor) {
mikesart@6675
   577
        cursor->next = mouse->cursors;
mikesart@6675
   578
        mouse->cursors = cursor;
mikesart@6675
   579
    }
mikesart@6675
   580
mikesart@6675
   581
	return cursor;
mikesart@6675
   582
}
mikesart@6675
   583
slouken@1895
   584
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@1895
   585
   if this is desired for any reason.  This is used when setting
slouken@1895
   586
   the video mode and when the SDL window gains the mouse focus.
slouken@1895
   587
 */
slouken@1895
   588
void
slouken@1895
   589
SDL_SetCursor(SDL_Cursor * cursor)
slouken@1895
   590
{
slouken@5371
   591
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   592
slouken@1895
   593
    /* Set the new cursor */
slouken@1895
   594
    if (cursor) {
slouken@1895
   595
        /* Make sure the cursor is still valid for this mouse */
slouken@5405
   596
        if (cursor != mouse->def_cursor) {
slouken@5405
   597
            SDL_Cursor *found;
slouken@5405
   598
            for (found = mouse->cursors; found; found = found->next) {
slouken@5405
   599
                if (found == cursor) {
slouken@5405
   600
                    break;
slouken@5405
   601
                }
slouken@1895
   602
            }
slouken@5405
   603
            if (!found) {
slouken@5405
   604
                SDL_SetError("Cursor not associated with the current mouse");
slouken@5405
   605
                return;
slouken@5405
   606
            }
slouken@1895
   607
        }
slouken@1895
   608
        mouse->cur_cursor = cursor;
slouken@1895
   609
    } else {
ghostunderscore@6301
   610
        if (mouse->focus) {
ghostunderscore@6301
   611
            cursor = mouse->cur_cursor;
ghostunderscore@6301
   612
        } else {
ghostunderscore@6301
   613
            cursor = mouse->def_cursor;
ghostunderscore@6301
   614
        }
slouken@1895
   615
    }
slouken@1895
   616
slouken@1895
   617
    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
slouken@1895
   618
        if (mouse->ShowCursor) {
slouken@1895
   619
            mouse->ShowCursor(cursor);
slouken@1895
   620
        }
slouken@1895
   621
    } else {
slouken@1895
   622
        if (mouse->ShowCursor) {
slouken@1895
   623
            mouse->ShowCursor(NULL);
slouken@1895
   624
        }
slouken@1895
   625
    }
slouken@1895
   626
}
slouken@1895
   627
slouken@1895
   628
SDL_Cursor *
slouken@1895
   629
SDL_GetCursor(void)
slouken@1895
   630
{
slouken@5371
   631
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   632
slouken@1895
   633
    if (!mouse) {
slouken@1895
   634
        return NULL;
slouken@1895
   635
    }
slouken@1895
   636
    return mouse->cur_cursor;
slouken@1895
   637
}
slouken@1895
   638
jorgen@7104
   639
SDL_Cursor *
jorgen@7104
   640
SDL_GetDefaultCursor(void)
jorgen@7104
   641
{
jorgen@7104
   642
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7104
   643
jorgen@7104
   644
    if (!mouse) {
jorgen@7104
   645
        return NULL;
jorgen@7104
   646
    }
jorgen@7104
   647
    return mouse->def_cursor;
jorgen@7104
   648
}
jorgen@7104
   649
slouken@1895
   650
void
slouken@1895
   651
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@1895
   652
{
slouken@5371
   653
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   654
    SDL_Cursor *curr, *prev;
slouken@1895
   655
slouken@1895
   656
    if (!cursor) {
slouken@1895
   657
        return;
slouken@1895
   658
    }
slouken@1895
   659
slouken@1895
   660
    if (cursor == mouse->def_cursor) {
slouken@1895
   661
        return;
slouken@1895
   662
    }
slouken@1895
   663
    if (cursor == mouse->cur_cursor) {
slouken@1895
   664
        SDL_SetCursor(mouse->def_cursor);
slouken@1895
   665
    }
slouken@1895
   666
slouken@1895
   667
    for (prev = NULL, curr = mouse->cursors; curr;
slouken@1895
   668
         prev = curr, curr = curr->next) {
slouken@1895
   669
        if (curr == cursor) {
slouken@1895
   670
            if (prev) {
slouken@1895
   671
                prev->next = curr->next;
slouken@1895
   672
            } else {
slouken@1895
   673
                mouse->cursors = curr->next;
slouken@1895
   674
            }
slouken@1895
   675
slouken@1895
   676
            if (mouse->FreeCursor) {
slouken@1895
   677
                mouse->FreeCursor(curr);
slouken@1895
   678
            }
slouken@1895
   679
            return;
slouken@1895
   680
        }
slouken@1895
   681
    }
slouken@1895
   682
}
slouken@1895
   683
slouken@1895
   684
int
slouken@1895
   685
SDL_ShowCursor(int toggle)
slouken@1895
   686
{
slouken@5371
   687
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   688
    SDL_bool shown;
slouken@1895
   689
slouken@1895
   690
    if (!mouse) {
slouken@1895
   691
        return 0;
slouken@1895
   692
    }
slouken@1895
   693
slouken@1895
   694
    shown = mouse->cursor_shown;
slouken@1895
   695
    if (toggle >= 0) {
slouken@1895
   696
        if (toggle) {
slouken@1895
   697
            mouse->cursor_shown = SDL_TRUE;
slouken@1895
   698
        } else {
slouken@1895
   699
            mouse->cursor_shown = SDL_FALSE;
slouken@1895
   700
        }
slouken@1895
   701
        if (mouse->cursor_shown != shown) {
slouken@1895
   702
            SDL_SetCursor(NULL);
slouken@1895
   703
        }
slouken@1895
   704
    }
slouken@1895
   705
    return shown;
slouken@1895
   706
}
slouken@1895
   707
jorgen@7097
   708
/* vi: set ts=4 sw=4 expandtab: */