src/events/SDL_mouse.c
author Sylvain Becker <sylvain.becker@gmail.com>
Thu, 04 Apr 2019 16:51:50 +0200
changeset 12688 cc45bcb16ef2
parent 12687 712d84dd14c9
child 12692 69f24f4ef99e
permissions -rw-r--r--
Add hint SDL_HINT_MOUSE_TOUCH_EVENTS for mouse events to generate touch events

controlling whether mouse events should generate synthetic touch events
By default SDL will *not* generate touch events for mouse events
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@12503
     3
  Copyright (C) 1997-2019 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@3685
    30
#include "../video/SDL_sysvideo.h"
slouken@12651
    31
#ifdef __WIN32__
slouken@12651
    32
#include "../core/windows/SDL_windows.h"    // For GetDoubleClickTime()
slouken@12651
    33
#endif
slouken@0
    34
gabomdq@7678
    35
/* #define DEBUG_MOUSE */
slouken@0
    36
slouken@5371
    37
/* The mouse state */
slouken@4465
    38
static SDL_Mouse SDL_mouse;
slouken@0
    39
sylvain@12688
    40
/* for mapping mouse events to touch */
sylvain@12688
    41
static SDL_bool track_mouse_down = SDL_FALSE;
sylvain@12688
    42
jorgen@7089
    43
static int
jorgen@7089
    44
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
slouken@0
    45
slouken@11284
    46
static void SDLCALL
slouken@12188
    47
SDL_MouseDoubleClickTimeChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@12188
    48
{
slouken@12188
    49
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@12188
    50
slouken@12188
    51
    if (hint && *hint) {
slouken@12188
    52
        mouse->double_click_time = SDL_atoi(hint);
slouken@12188
    53
    } else {
slouken@12188
    54
#ifdef __WIN32__
slouken@12188
    55
        mouse->double_click_time = GetDoubleClickTime();
slouken@12188
    56
#else
slouken@12188
    57
        mouse->double_click_time = 500;
slouken@12188
    58
#endif
slouken@12188
    59
    }
slouken@12188
    60
}
slouken@12188
    61
slouken@12188
    62
static void SDLCALL
slouken@12188
    63
SDL_MouseDoubleClickRadiusChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@12188
    64
{
slouken@12188
    65
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@12188
    66
slouken@12188
    67
    if (hint && *hint) {
slouken@12188
    68
        mouse->double_click_radius = SDL_atoi(hint);
slouken@12188
    69
    } else {
slouken@12188
    70
        mouse->double_click_radius = 32;    /* 32 pixels seems about right for touch interfaces */
slouken@12188
    71
    }
slouken@12188
    72
}
slouken@12188
    73
slouken@12188
    74
static void SDLCALL
slouken@10673
    75
SDL_MouseNormalSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@10673
    76
{
slouken@10673
    77
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@10673
    78
slouken@10676
    79
    if (hint && *hint) {
slouken@10676
    80
        mouse->normal_speed_scale = (float)SDL_atof(hint);
slouken@10676
    81
    } else {
slouken@10676
    82
        mouse->normal_speed_scale = 1.0f;
slouken@10676
    83
    }
slouken@10673
    84
}
slouken@10673
    85
slouken@11284
    86
static void SDLCALL
slouken@10673
    87
SDL_MouseRelativeSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@10673
    88
{
slouken@10673
    89
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@10673
    90
slouken@10676
    91
    if (hint && *hint) {
slouken@10676
    92
        mouse->relative_speed_scale = (float)SDL_atof(hint);
slouken@10676
    93
    } else {
slouken@10676
    94
        mouse->relative_speed_scale = 1.0f;
slouken@10676
    95
    }
slouken@10673
    96
}
slouken@10673
    97
slouken@11284
    98
static void SDLCALL
slouken@11182
    99
SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@11182
   100
{
slouken@11182
   101
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@11182
   102
slouken@11182
   103
    if (hint && (*hint == '0' || SDL_strcasecmp(hint, "false") == 0)) {
slouken@11182
   104
        mouse->touch_mouse_events = SDL_FALSE;
slouken@11182
   105
    } else {
slouken@11182
   106
        mouse->touch_mouse_events = SDL_TRUE;
slouken@11182
   107
    }
slouken@11182
   108
}
slouken@11182
   109
sylvain@12688
   110
static void SDLCALL
sylvain@12688
   111
SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
sylvain@12688
   112
{
sylvain@12688
   113
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
sylvain@12688
   114
sylvain@12688
   115
    if (hint && (*hint == '1' || SDL_strcasecmp(hint, "true") == 0)) {
sylvain@12688
   116
sylvain@12688
   117
        SDL_AddTouch(SDL_MOUSE_TOUCHID, SDL_TOUCH_DEVICE_DIRECT, "mouse_input");
sylvain@12688
   118
sylvain@12688
   119
        mouse->mouse_touch_events = SDL_TRUE;
sylvain@12688
   120
    } else {
sylvain@12688
   121
        mouse->mouse_touch_events = SDL_FALSE;
sylvain@12688
   122
    }
sylvain@12688
   123
}
sylvain@12688
   124
slouken@0
   125
/* Public functions */
slouken@1895
   126
int
slouken@1895
   127
SDL_MouseInit(void)
slouken@0
   128
{
slouken@5376
   129
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5376
   130
slouken@11607
   131
    SDL_zerop(mouse);
slouken@11607
   132
slouken@12188
   133
    SDL_AddHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME,
slouken@12188
   134
                        SDL_MouseDoubleClickTimeChanged, mouse);
slouken@12188
   135
slouken@12188
   136
    SDL_AddHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS,
slouken@12188
   137
                        SDL_MouseDoubleClickRadiusChanged, mouse);
slouken@12188
   138
slouken@10673
   139
    SDL_AddHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
slouken@10673
   140
                        SDL_MouseNormalSpeedScaleChanged, mouse);
slouken@10673
   141
slouken@10673
   142
    SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
slouken@10673
   143
                        SDL_MouseRelativeSpeedScaleChanged, mouse);
slouken@10673
   144
slouken@11182
   145
    SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
slouken@11182
   146
                        SDL_TouchMouseEventsChanged, mouse);
slouken@11182
   147
sylvain@12688
   148
    SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
sylvain@12688
   149
                        SDL_MouseTouchEventsChanged, mouse);
sylvain@12688
   150
slouken@5376
   151
    mouse->cursor_shown = SDL_TRUE;
slouken@5376
   152
slouken@1895
   153
    return (0);
slouken@1123
   154
}
slouken@0
   155
slouken@5405
   156
void
slouken@5405
   157
SDL_SetDefaultCursor(SDL_Cursor * cursor)
slouken@5405
   158
{
slouken@5405
   159
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5405
   160
slouken@5405
   161
    mouse->def_cursor = cursor;
slouken@5405
   162
    if (!mouse->cur_cursor) {
slouken@5405
   163
        SDL_SetCursor(cursor);
slouken@5405
   164
    }
slouken@5405
   165
}
slouken@5405
   166
slouken@5371
   167
SDL_Mouse *
slouken@5371
   168
SDL_GetMouse(void)
slouken@5371
   169
{
slouken@5371
   170
    return &SDL_mouse;
slouken@5371
   171
}
slouken@5371
   172
slouken@4465
   173
SDL_Window *
slouken@4465
   174
SDL_GetMouseFocus(void)
slouken@2710
   175
{
slouken@5371
   176
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@2940
   177
slouken@4465
   178
    return mouse->focus;
slouken@0
   179
}
slouken@0
   180
slouken@10609
   181
#if 0
slouken@1895
   182
void
slouken@6666
   183
SDL_ResetMouse(void)
slouken@6666
   184
{
slouken@6666
   185
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6666
   186
    Uint8 i;
slouken@6666
   187
slouken@6666
   188
#ifdef DEBUG_MOUSE
slouken@6666
   189
    printf("Resetting mouse\n");
slouken@6666
   190
#endif
slouken@6666
   191
    for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
slouken@6666
   192
        if (mouse->buttonstate & SDL_BUTTON(i)) {
slouken@6950
   193
            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
slouken@6666
   194
        }
slouken@6666
   195
    }
slouken@6666
   196
    SDL_assert(mouse->buttonstate == 0);
slouken@6666
   197
}
slouken@10609
   198
#endif
slouken@6666
   199
slouken@6666
   200
void
slouken@4465
   201
SDL_SetMouseFocus(SDL_Window * window)
slouken@0
   202
{
slouken@5371
   203
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   204
slouken@4465
   205
    if (mouse->focus == window) {
slouken@1895
   206
        return;
slouken@1895
   207
    }
slouken@1895
   208
slouken@6829
   209
    /* Actually, this ends up being a bad idea, because most operating
slouken@6829
   210
       systems have an implicit grab when you press the mouse button down
slouken@6829
   211
       so you can drag things out of the window and then get the mouse up
slouken@6829
   212
       when it happens.  So, #if 0...
slouken@6829
   213
    */
slouken@6829
   214
#if 0
slouken@6666
   215
    if (mouse->focus && !window) {
slouken@6666
   216
        /* We won't get anymore mouse messages, so reset mouse state */
slouken@6666
   217
        SDL_ResetMouse();
slouken@6666
   218
    }
slouken@6829
   219
#endif
slouken@6666
   220
slouken@1895
   221
    /* See if the current window has lost focus */
slouken@1895
   222
    if (mouse->focus) {
slouken@4465
   223
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
slouken@1895
   224
    }
slouken@1895
   225
slouken@3685
   226
    mouse->focus = window;
slouken@11258
   227
    mouse->has_position = SDL_FALSE;
slouken@1895
   228
slouken@1895
   229
    if (mouse->focus) {
slouken@4465
   230
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
slouken@1895
   231
    }
slouken@6666
   232
slouken@6666
   233
    /* Update cursor visibility */
slouken@6666
   234
    SDL_SetCursor(NULL);
slouken@6666
   235
}
slouken@6666
   236
slouken@6666
   237
/* Check to see if we need to synthesize focus events */
slouken@6666
   238
static SDL_bool
slouken@6673
   239
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
slouken@6666
   240
{
slouken@6666
   241
    SDL_Mouse *mouse = SDL_GetMouse();
icculus@8927
   242
    SDL_bool inWindow = SDL_TRUE;
slouken@6666
   243
slouken@8983
   244
    if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
icculus@8927
   245
        int w, h;
icculus@8927
   246
        SDL_GetWindowSize(window, &w, &h);
icculus@8927
   247
        if (x < 0 || y < 0 || x >= w || y >= h) {
icculus@8927
   248
            inWindow = SDL_FALSE;
icculus@8927
   249
        }
slouken@6666
   250
    }
slouken@6667
   251
icculus@8783
   252
/* Linux doesn't give you mouse events outside your window unless you grab
icculus@8783
   253
   the pointer.
icculus@8783
   254
icculus@8783
   255
   Windows doesn't give you mouse events outside your window unless you call
icculus@8783
   256
   SetCapture().
icculus@8783
   257
icculus@8783
   258
   Both of these are slightly scary changes, so for now we'll punt and if the
icculus@8783
   259
   mouse leaves the window you'll lose mouse focus and reset button state.
icculus@8783
   260
*/
icculus@8783
   261
#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
icculus@8783
   262
    if (!inWindow && !buttonstate) {
icculus@8783
   263
#else
slouken@6667
   264
    if (!inWindow) {
icculus@8783
   265
#endif
slouken@6666
   266
        if (window == mouse->focus) {
slouken@6666
   267
#ifdef DEBUG_MOUSE
jorgen@7089
   268
            printf("Mouse left window, synthesizing move & focus lost event\n");
slouken@6666
   269
#endif
jorgen@7089
   270
            SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@6666
   271
            SDL_SetMouseFocus(NULL);
slouken@6666
   272
        }
slouken@6666
   273
        return SDL_FALSE;
slouken@6666
   274
    }
slouken@6666
   275
slouken@6666
   276
    if (window != mouse->focus) {
slouken@6666
   277
#ifdef DEBUG_MOUSE
slouken@11258
   278
        printf("Mouse entered window, synthesizing focus gain & move event\n");
slouken@6666
   279
#endif
slouken@11258
   280
        SDL_SetMouseFocus(window);
slouken@11258
   281
        SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@6666
   282
    }
slouken@6666
   283
    return SDL_TRUE;
slouken@1895
   284
}
slouken@1895
   285
slouken@1895
   286
int
slouken@6950
   287
SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
slouken@1895
   288
{
jorgen@7089
   289
    if (window && !relative) {
jorgen@7089
   290
        SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7089
   291
        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
jorgen@7089
   292
            return 0;
jorgen@7089
   293
        }
jorgen@7089
   294
    }
jorgen@7089
   295
jorgen@7089
   296
    return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
jorgen@7089
   297
}
jorgen@7089
   298
jorgen@7089
   299
static int
slouken@10673
   300
GetScaledMouseDelta(float scale, int value, float *accum)
slouken@10673
   301
{
slouken@10673
   302
    if (scale != 1.0f) {
slouken@10673
   303
        *accum += scale * value;
slouken@10673
   304
        if (*accum >= 0.0f) {
slouken@10673
   305
            value = (int)SDL_floor(*accum);
slouken@10673
   306
        } else {
slouken@10673
   307
            value = (int)SDL_ceil(*accum);
slouken@10673
   308
        }
slouken@10673
   309
        *accum -= value;
slouken@10673
   310
    }
slouken@10673
   311
    return value;
slouken@10673
   312
}
slouken@10673
   313
slouken@10673
   314
static int
jorgen@7089
   315
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
jorgen@7089
   316
{
slouken@5371
   317
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   318
    int posted;
slouken@1895
   319
    int xrel;
slouken@1895
   320
    int yrel;
slouken@1895
   321
sylvain@12688
   322
    /* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
sylvain@12688
   323
    if (mouse->mouse_touch_events) {
sylvain@12688
   324
        if (mouseID != SDL_TOUCH_MOUSEID && !relative && track_mouse_down) {
sylvain@12688
   325
            if (window) {
sylvain@12688
   326
                float fx = (float)x / (float)window->w;
sylvain@12688
   327
                float fy = (float)y / (float)window->h;
sylvain@12688
   328
                SDL_SendTouchMotion(SDL_MOUSE_TOUCHID, 0, fx, fy, 1.0f);
sylvain@12688
   329
            }
sylvain@12688
   330
        }
sylvain@12688
   331
    }
sylvain@12688
   332
slouken@11258
   333
    if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
slouken@8071
   334
        int center_x = 0, center_y = 0;
slouken@8071
   335
        SDL_GetWindowSize(window, &center_x, &center_y);
slouken@8071
   336
        center_x /= 2;
slouken@8071
   337
        center_y /= 2;
slouken@8071
   338
        if (x == center_x && y == center_y) {
slouken@8071
   339
            mouse->last_x = center_x;
slouken@8071
   340
            mouse->last_y = center_y;
slouken@8071
   341
            return 0;
slouken@8071
   342
        }
slouken@8071
   343
        SDL_WarpMouseInWindow(window, center_x, center_y);
slouken@8071
   344
    }
slouken@8071
   345
slouken@2842
   346
    if (relative) {
slouken@10673
   347
        if (mouse->relative_mode) {
slouken@10673
   348
            x = GetScaledMouseDelta(mouse->relative_speed_scale, x, &mouse->scale_accum_x);
slouken@10673
   349
            y = GetScaledMouseDelta(mouse->relative_speed_scale, y, &mouse->scale_accum_y);
slouken@10673
   350
        } else {
slouken@10673
   351
            x = GetScaledMouseDelta(mouse->normal_speed_scale, x, &mouse->scale_accum_x);
slouken@10673
   352
            y = GetScaledMouseDelta(mouse->normal_speed_scale, y, &mouse->scale_accum_y);
slouken@10673
   353
        }
slouken@2842
   354
        xrel = x;
slouken@2842
   355
        yrel = y;
slouken@8071
   356
        x = (mouse->last_x + xrel);
slouken@8071
   357
        y = (mouse->last_y + yrel);
slouken@2842
   358
    } else {
slouken@2860
   359
        xrel = x - mouse->last_x;
slouken@2860
   360
        yrel = y - mouse->last_y;
slouken@2842
   361
    }
slouken@2710
   362
slouken@1895
   363
    /* Drop events that don't change state */
slouken@1895
   364
    if (!xrel && !yrel) {
slouken@6666
   365
#ifdef DEBUG_MOUSE
slouken@1895
   366
        printf("Mouse event didn't change state - dropped!\n");
slouken@1895
   367
#endif
slouken@1895
   368
        return 0;
slouken@1895
   369
    }
slouken@1895
   370
slouken@11258
   371
    /* Ignore relative motion when first positioning the mouse */
slouken@11258
   372
    if (!mouse->has_position) {
slouken@11258
   373
        xrel = 0;
slouken@11258
   374
        yrel = 0;
slouken@11258
   375
        mouse->has_position = SDL_TRUE;
slouken@11258
   376
    }
slouken@11258
   377
slouken@11258
   378
    /* Ignore relative motion positioning the first touch */
slouken@11258
   379
    if (mouseID == SDL_TOUCH_MOUSEID && !mouse->buttonstate) {
slouken@11258
   380
        xrel = 0;
slouken@11258
   381
        yrel = 0;
slouken@11258
   382
    }
slouken@11258
   383
slouken@2710
   384
    /* Update internal mouse coordinates */
slouken@8071
   385
    if (!mouse->relative_mode) {
slouken@1895
   386
        mouse->x = x;
slouken@1895
   387
        mouse->y = y;
slouken@2710
   388
    } else {
slouken@2860
   389
        mouse->x += xrel;
slouken@2860
   390
        mouse->y += yrel;
slouken@2860
   391
    }
slouken@2849
   392
icculus@8927
   393
    /* make sure that the pointers find themselves inside the windows,
icculus@8927
   394
       unless we have the mouse captured. */
slouken@8983
   395
    if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
icculus@8927
   396
        int x_max = 0, y_max = 0;
slouken@2849
   397
icculus@10780
   398
        /* !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? */
icculus@8927
   399
        SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
icculus@8927
   400
        --x_max;
icculus@8927
   401
        --y_max;
slouken@2860
   402
icculus@8927
   403
        if (mouse->x > x_max) {
icculus@8927
   404
            mouse->x = x_max;
icculus@8927
   405
        }
icculus@8927
   406
        if (mouse->x < 0) {
icculus@8927
   407
            mouse->x = 0;
icculus@8927
   408
        }
icculus@8927
   409
icculus@8927
   410
        if (mouse->y > y_max) {
icculus@8927
   411
            mouse->y = y_max;
icculus@8927
   412
        }
icculus@8927
   413
        if (mouse->y < 0) {
icculus@8927
   414
            mouse->y = 0;
icculus@8927
   415
        }
slouken@2860
   416
    }
slouken@2860
   417
slouken@1895
   418
    mouse->xdelta += xrel;
slouken@1895
   419
    mouse->ydelta += yrel;
slouken@1895
   420
slouken@1895
   421
    /* Move the mouse cursor, if needed */
slouken@1895
   422
    if (mouse->cursor_shown && !mouse->relative_mode &&
slouken@1895
   423
        mouse->MoveCursor && mouse->cur_cursor) {
slouken@1895
   424
        mouse->MoveCursor(mouse->cur_cursor);
slouken@1895
   425
    }
slouken@1895
   426
slouken@1895
   427
    /* Post the event, if desired */
slouken@1895
   428
    posted = 0;
slouken@4465
   429
    if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
slouken@1895
   430
        SDL_Event event;
slouken@1895
   431
        event.motion.type = SDL_MOUSEMOTION;
slouken@4465
   432
        event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   433
        event.motion.which = mouseID;
slouken@1895
   434
        event.motion.state = mouse->buttonstate;
slouken@1895
   435
        event.motion.x = mouse->x;
slouken@1895
   436
        event.motion.y = mouse->y;
slouken@1895
   437
        event.motion.xrel = xrel;
slouken@1895
   438
        event.motion.yrel = yrel;
slouken@1895
   439
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   440
    }
slouken@9448
   441
    if (relative) {
slouken@9448
   442
        mouse->last_x = mouse->x;
slouken@9448
   443
        mouse->last_y = mouse->y;
slouken@9448
   444
    } else {
slouken@9448
   445
        /* Use unclamped values if we're getting events outside the window */
slouken@9448
   446
        mouse->last_x = x;
slouken@9448
   447
        mouse->last_y = y;
slouken@9448
   448
    }
slouken@1895
   449
    return posted;
slouken@1895
   450
}
slouken@1895
   451
slouken@8066
   452
static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
slouken@8066
   453
{
slouken@8066
   454
    if (button >= mouse->num_clickstates) {
slouken@8066
   455
        int i, count = button + 1;
philipp@9334
   456
        SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
philipp@9334
   457
        if (!clickstate) {
slouken@8066
   458
            return NULL;
slouken@8066
   459
        }
philipp@9334
   460
        mouse->clickstate = clickstate;
slouken@8066
   461
slouken@8066
   462
        for (i = mouse->num_clickstates; i < count; ++i) {
slouken@8066
   463
            SDL_zero(mouse->clickstate[i]);
slouken@8066
   464
        }
slouken@8066
   465
        mouse->num_clickstates = count;
slouken@8066
   466
    }
slouken@8066
   467
    return &mouse->clickstate[button];
slouken@8066
   468
}
slouken@8066
   469
slime73@10366
   470
static int
slime73@10366
   471
SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
slouken@1895
   472
{
slouken@5371
   473
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   474
    int posted;
slouken@4429
   475
    Uint32 type;
slouken@6673
   476
    Uint32 buttonstate = mouse->buttonstate;
slouken@4484
   477
sylvain@12688
   478
    /* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
sylvain@12688
   479
    if (mouse->mouse_touch_events) {
sylvain@12688
   480
        if (mouseID != SDL_TOUCH_MOUSEID && button == SDL_BUTTON_LEFT) {
sylvain@12688
   481
            if (window) {
sylvain@12688
   482
                float fx = (float)mouse->x / (float)window->w;
sylvain@12688
   483
                float fy = (float)mouse->y / (float)window->h;
sylvain@12688
   484
                if (state == SDL_PRESSED) {
sylvain@12688
   485
                    track_mouse_down = SDL_TRUE;
sylvain@12688
   486
                } else {
sylvain@12688
   487
                    track_mouse_down = SDL_FALSE;
sylvain@12688
   488
                }
sylvain@12688
   489
                SDL_SendTouch(SDL_MOUSE_TOUCHID, 0, track_mouse_down, fx, fy, 1.0f);
sylvain@12688
   490
            }
sylvain@12688
   491
        }
sylvain@12688
   492
    }
sylvain@12688
   493
slouken@1895
   494
    /* Figure out which event to perform */
slouken@1895
   495
    switch (state) {
slouken@1895
   496
    case SDL_PRESSED:
slouken@1895
   497
        type = SDL_MOUSEBUTTONDOWN;
slouken@6666
   498
        buttonstate |= SDL_BUTTON(button);
slouken@1895
   499
        break;
slouken@1895
   500
    case SDL_RELEASED:
slouken@1895
   501
        type = SDL_MOUSEBUTTONUP;
slouken@6666
   502
        buttonstate &= ~SDL_BUTTON(button);
slouken@1895
   503
        break;
slouken@1895
   504
    default:
slouken@1895
   505
        /* Invalid state -- bail */
slouken@1895
   506
        return 0;
slouken@1895
   507
    }
slouken@1895
   508
slouken@6666
   509
    /* We do this after calculating buttonstate so button presses gain focus */
slouken@6666
   510
    if (window && state == SDL_PRESSED) {
slouken@6666
   511
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   512
    }
slouken@6666
   513
slouken@6666
   514
    if (buttonstate == mouse->buttonstate) {
slouken@6666
   515
        /* Ignore this event, no state change */
slouken@6666
   516
        return 0;
slouken@6666
   517
    }
slouken@6666
   518
    mouse->buttonstate = buttonstate;
slouken@6666
   519
slime73@10366
   520
    if (clicks < 0) {
slime73@10366
   521
        SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
philipp@10390
   522
        if (clickstate) {
philipp@10390
   523
            if (state == SDL_PRESSED) {
philipp@10390
   524
                Uint32 now = SDL_GetTicks();
slouken@8066
   525
slouken@12188
   526
                if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + mouse->double_click_time) ||
slouken@12188
   527
                    SDL_abs(mouse->x - clickstate->last_x) > mouse->double_click_radius ||
slouken@12188
   528
                    SDL_abs(mouse->y - clickstate->last_y) > mouse->double_click_radius) {
philipp@10390
   529
                    clickstate->click_count = 0;
philipp@10390
   530
                }
philipp@10390
   531
                clickstate->last_timestamp = now;
philipp@10390
   532
                clickstate->last_x = mouse->x;
philipp@10390
   533
                clickstate->last_y = mouse->y;
philipp@10390
   534
                if (clickstate->click_count < 255) {
philipp@10390
   535
                    ++clickstate->click_count;
philipp@10390
   536
                }
slouken@8066
   537
            }
philipp@10390
   538
            clicks = clickstate->click_count;
philipp@10390
   539
        } else {
philipp@10390
   540
            clicks = 1;
slouken@8066
   541
        }
slouken@8066
   542
    }
slouken@8066
   543
slouken@1895
   544
    /* Post the event, if desired */
slouken@1895
   545
    posted = 0;
slouken@4429
   546
    if (SDL_GetEventState(type) == SDL_ENABLE) {
slouken@1895
   547
        SDL_Event event;
slouken@1895
   548
        event.type = type;
slouken@6950
   549
        event.button.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   550
        event.button.which = mouseID;
slouken@1895
   551
        event.button.state = state;
slouken@1895
   552
        event.button.button = button;
slime73@10366
   553
        event.button.clicks = (Uint8) SDL_min(clicks, 255);
slouken@1895
   554
        event.button.x = mouse->x;
slouken@1895
   555
        event.button.y = mouse->y;
slouken@1895
   556
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   557
    }
slouken@6666
   558
slouken@6666
   559
    /* We do this after dispatching event so button releases can lose focus */
slouken@6666
   560
    if (window && state == SDL_RELEASED) {
slouken@6666
   561
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   562
    }
sylvain@12687
   563
slime73@10366
   564
    return posted;
slime73@10366
   565
}
slouken@6666
   566
slime73@10366
   567
int
slime73@10366
   568
SDL_SendMouseButtonClicks(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
slime73@10366
   569
{
slime73@10366
   570
    clicks = SDL_max(clicks, 0);
slime73@10366
   571
    return SDL_PrivateSendMouseButton(window, mouseID, state, button, clicks);
slime73@10366
   572
}
slime73@10366
   573
slime73@10366
   574
int
slime73@10366
   575
SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
slime73@10366
   576
{
slime73@10366
   577
    return SDL_PrivateSendMouseButton(window, mouseID, state, button, -1);
slouken@1895
   578
}
slouken@1895
   579
slouken@1895
   580
int
slouken@11300
   581
SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
slouken@1895
   582
{
slouken@5371
   583
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   584
    int posted;
slouken@11300
   585
    int integral_x, integral_y;
slouken@1895
   586
slouken@4484
   587
    if (window) {
slouken@4484
   588
        SDL_SetMouseFocus(window);
slouken@4484
   589
    }
slouken@4484
   590
slouken@12466
   591
    if (x == 0.0f && y == 0.0f) {
slouken@1895
   592
        return 0;
slouken@1895
   593
    }
slouken@1895
   594
slouken@11300
   595
    mouse->accumulated_wheel_x += x;
slouken@11300
   596
    if (mouse->accumulated_wheel_x > 0) {
slouken@11300
   597
        integral_x = (int)SDL_floor(mouse->accumulated_wheel_x);
slouken@11300
   598
    } else if (mouse->accumulated_wheel_x < 0) {
slouken@11300
   599
        integral_x = (int)SDL_ceil(mouse->accumulated_wheel_x);
slouken@11300
   600
    } else {
slouken@11300
   601
        integral_x = 0;
slouken@11300
   602
    }
slouken@11300
   603
    mouse->accumulated_wheel_x -= integral_x;
slouken@11300
   604
slouken@11300
   605
    mouse->accumulated_wheel_y += y;
slouken@11300
   606
    if (mouse->accumulated_wheel_y > 0) {
slouken@11300
   607
        integral_y = (int)SDL_floor(mouse->accumulated_wheel_y);
slouken@11300
   608
    } else if (mouse->accumulated_wheel_y < 0) {
slouken@11300
   609
        integral_y = (int)SDL_ceil(mouse->accumulated_wheel_y);
slouken@11300
   610
    } else {
slouken@11300
   611
        integral_y = 0;
slouken@11300
   612
    }
slouken@11300
   613
    mouse->accumulated_wheel_y -= integral_y;
slouken@11300
   614
slouken@1895
   615
    /* Post the event, if desired */
slouken@1895
   616
    posted = 0;
slouken@4429
   617
    if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
slouken@1895
   618
        SDL_Event event;
slouken@1895
   619
        event.type = SDL_MOUSEWHEEL;
slouken@4465
   620
        event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   621
        event.wheel.which = mouseID;
slouken@11300
   622
#if 0 /* Uncomment this when it goes in for SDL 2.1 */
slouken@11300
   623
        event.wheel.preciseX = x;
slouken@11300
   624
        event.wheel.preciseY = y;
slouken@11300
   625
#endif
slouken@11300
   626
        event.wheel.x = integral_x;
slouken@11300
   627
        event.wheel.y = integral_y;
urkle@9257
   628
        event.wheel.direction = (Uint32)direction;
slouken@1895
   629
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   630
    }
slouken@1895
   631
    return posted;
slouken@1895
   632
}
slouken@1895
   633
slouken@1895
   634
void
slouken@4465
   635
SDL_MouseQuit(void)
slouken@4465
   636
{
slouken@7493
   637
    SDL_Cursor *cursor, *next;
slouken@7493
   638
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@7493
   639
slouken@9161
   640
    if (mouse->CaptureMouse) {
slouken@9161
   641
        SDL_CaptureMouse(SDL_FALSE);
slouken@9161
   642
    }
slouken@8049
   643
    SDL_SetRelativeMouseMode(SDL_FALSE);
slouken@7493
   644
    SDL_ShowCursor(1);
slouken@7493
   645
slouken@7493
   646
    cursor = mouse->cursors;
slouken@7493
   647
    while (cursor) {
slouken@7493
   648
        next = cursor->next;
slouken@7493
   649
        SDL_FreeCursor(cursor);
slouken@7493
   650
        cursor = next;
slouken@7493
   651
    }
slouken@11622
   652
    mouse->cursors = NULL;
sylvain@12620
   653
    mouse->cur_cursor = NULL;
slouken@7493
   654
slouken@7493
   655
    if (mouse->def_cursor && mouse->FreeCursor) {
slouken@7493
   656
        mouse->FreeCursor(mouse->def_cursor);
slouken@11622
   657
        mouse->def_cursor = NULL;
slouken@7493
   658
    }
slouken@7493
   659
slouken@8066
   660
    if (mouse->clickstate) {
slouken@8066
   661
        SDL_free(mouse->clickstate);
slouken@11622
   662
        mouse->clickstate = NULL;
slouken@8066
   663
    }
slouken@8066
   664
slouken@10673
   665
    SDL_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
slouken@10673
   666
                        SDL_MouseNormalSpeedScaleChanged, mouse);
slouken@10673
   667
slouken@10673
   668
    SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
slouken@10673
   669
                        SDL_MouseRelativeSpeedScaleChanged, mouse);
slouken@4465
   670
}
slouken@4465
   671
slouken@6673
   672
Uint32
slouken@4465
   673
SDL_GetMouseState(int *x, int *y)
slouken@4465
   674
{
slouken@5371
   675
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   676
slouken@4465
   677
    if (x) {
slouken@4465
   678
        *x = mouse->x;
slouken@4465
   679
    }
slouken@4465
   680
    if (y) {
slouken@4465
   681
        *y = mouse->y;
slouken@4465
   682
    }
slouken@4465
   683
    return mouse->buttonstate;
slouken@4465
   684
}
slouken@4465
   685
slouken@6673
   686
Uint32
slouken@4465
   687
SDL_GetRelativeMouseState(int *x, int *y)
slouken@4465
   688
{
slouken@5371
   689
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   690
slouken@4465
   691
    if (x) {
slouken@4465
   692
        *x = mouse->xdelta;
slouken@4465
   693
    }
slouken@4465
   694
    if (y) {
slouken@4465
   695
        *y = mouse->ydelta;
slouken@4465
   696
    }
slouken@4465
   697
    mouse->xdelta = 0;
slouken@4465
   698
    mouse->ydelta = 0;
slouken@4465
   699
    return mouse->buttonstate;
slouken@4465
   700
}
slouken@4465
   701
icculus@8945
   702
Uint32
icculus@8952
   703
SDL_GetGlobalMouseState(int *x, int *y)
icculus@8945
   704
{
icculus@8945
   705
    SDL_Mouse *mouse = SDL_GetMouse();
icculus@8945
   706
    int tmpx, tmpy;
icculus@8945
   707
icculus@8945
   708
    /* make sure these are never NULL for the backend implementations... */
icculus@8945
   709
    if (!x) {
icculus@8945
   710
        x = &tmpx;
icculus@8945
   711
    }
icculus@8945
   712
    if (!y) {
icculus@8945
   713
        y = &tmpy;
icculus@8945
   714
    }
icculus@8945
   715
icculus@8945
   716
    *x = *y = 0;
icculus@8945
   717
icculus@8952
   718
    if (!mouse->GetGlobalMouseState) {
icculus@8945
   719
        return 0;
icculus@8945
   720
    }
icculus@8945
   721
icculus@8952
   722
    return mouse->GetGlobalMouseState(x, y);
icculus@8945
   723
}
icculus@8945
   724
slouken@4465
   725
void
slouken@3685
   726
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
slouken@1895
   727
{
slouken@5371
   728
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@7191
   729
icculus@8953
   730
    if (window == NULL) {
slouken@7191
   731
        window = mouse->focus;
icculus@8944
   732
    }
slouken@7191
   733
icculus@8953
   734
    if (window == NULL) {
slouken@7191
   735
        return;
icculus@8944
   736
    }
slouken@1895
   737
slouken@1895
   738
    if (mouse->WarpMouse) {
slouken@5371
   739
        mouse->WarpMouse(window, x, y);
slouken@1895
   740
    } else {
slouken@6950
   741
        SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@1895
   742
    }
slouken@1895
   743
}
slouken@1895
   744
icculus@9807
   745
int
slouken@8815
   746
SDL_WarpMouseGlobal(int x, int y)
slouken@8815
   747
{
slouken@8815
   748
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@8815
   749
slouken@8815
   750
    if (mouse->WarpMouseGlobal) {
icculus@9807
   751
        return mouse->WarpMouseGlobal(x, y);
slouken@8815
   752
    }
icculus@9807
   753
icculus@9807
   754
    return SDL_Unsupported();
slouken@8815
   755
}
slouken@8815
   756
slouken@8071
   757
static SDL_bool
slouken@8071
   758
ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
slouken@8071
   759
{
slouken@8071
   760
    if (!mouse->SetRelativeMouseMode) {
slouken@12007
   761
        SDL_assert(mouse->WarpMouse);   /* Need this functionality for relative mode warp implementation */
slouken@8071
   762
        return SDL_TRUE;
slouken@8071
   763
    }
slouken@8071
   764
slouken@10499
   765
    return SDL_GetHintBoolean(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, SDL_FALSE);
slouken@8071
   766
}
slouken@8071
   767
slouken@4465
   768
int
slouken@4465
   769
SDL_SetRelativeMouseMode(SDL_bool enabled)
slouken@4465
   770
{
slouken@5371
   771
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7107
   772
    SDL_Window *focusWindow = SDL_GetKeyboardFocus();
slouken@4465
   773
slouken@5406
   774
    if (enabled == mouse->relative_mode) {
slouken@5406
   775
        return 0;
slouken@5406
   776
    }
slouken@5406
   777
jorgen@7107
   778
    if (enabled && focusWindow) {
jorgen@7107
   779
        /* Center it in the focused window to prevent clicks from going through
jorgen@7107
   780
         * to background windows.
jorgen@7107
   781
         */
jorgen@7107
   782
        SDL_SetMouseFocus(focusWindow);
jorgen@7107
   783
        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
jorgen@7107
   784
    }
jorgen@7107
   785
slouken@8071
   786
    /* Set the relative mode */
slouken@8071
   787
    if (!enabled && mouse->relative_mode_warp) {
slouken@8071
   788
        mouse->relative_mode_warp = SDL_FALSE;
slouken@8071
   789
    } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
slouken@8071
   790
        mouse->relative_mode_warp = SDL_TRUE;
slouken@8071
   791
    } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
slouken@8269
   792
        if (enabled) {
philipp@8776
   793
            /* Fall back to warp mode if native relative mode failed */
slouken@12024
   794
            if (!mouse->WarpMouse) {
slouken@12024
   795
                return SDL_SetError("No relative mode implementation available");
slouken@12024
   796
            }
slouken@8269
   797
            mouse->relative_mode_warp = SDL_TRUE;
slouken@8269
   798
        }
slouken@5406
   799
    }
slouken@4465
   800
    mouse->relative_mode = enabled;
slouken@10673
   801
    mouse->scale_accum_x = 0.0f;
slouken@10673
   802
    mouse->scale_accum_y = 0.0f;
slouken@4465
   803
slouken@8071
   804
    if (mouse->focus) {
slouken@8071
   805
        SDL_UpdateWindowGrab(mouse->focus);
slouken@8071
   806
slouken@8071
   807
        /* Put the cursor back to where the application expects it */
slouken@8071
   808
        if (!enabled) {
slouken@8071
   809
            SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
slouken@8071
   810
        }
slouken@4465
   811
    }
slouken@4465
   812
slouken@8071
   813
    /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
slouken@5406
   814
    SDL_FlushEvent(SDL_MOUSEMOTION);
slouken@5406
   815
slouken@4465
   816
    /* Update cursor visibility */
slouken@4465
   817
    SDL_SetCursor(NULL);
slouken@4465
   818
slouken@4465
   819
    return 0;
slouken@4465
   820
}
slouken@4465
   821
slouken@4465
   822
SDL_bool
slouken@4465
   823
SDL_GetRelativeMouseMode()
slouken@4465
   824
{
slouken@5371
   825
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   826
slouken@4465
   827
    return mouse->relative_mode;
slouken@4465
   828
}
slouken@4465
   829
icculus@8955
   830
int
icculus@8955
   831
SDL_CaptureMouse(SDL_bool enabled)
icculus@8955
   832
{
icculus@8955
   833
    SDL_Mouse *mouse = SDL_GetMouse();
icculus@8955
   834
    SDL_Window *focusWindow;
icculus@8955
   835
    SDL_bool isCaptured;
icculus@8955
   836
icculus@8955
   837
    if (!mouse->CaptureMouse) {
icculus@8955
   838
        return SDL_Unsupported();
icculus@8955
   839
    }
icculus@8955
   840
icculus@8955
   841
    focusWindow = SDL_GetKeyboardFocus();
icculus@8955
   842
icculus@8955
   843
    isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
icculus@8955
   844
    if (isCaptured == enabled) {
icculus@8955
   845
        return 0;  /* already done! */
icculus@8955
   846
    }
icculus@8955
   847
icculus@8955
   848
    if (enabled) {
icculus@8955
   849
        if (!focusWindow) {
icculus@8955
   850
            return SDL_SetError("No window has focus");
icculus@8955
   851
        } else if (mouse->CaptureMouse(focusWindow) == -1) {
icculus@8955
   852
            return -1;  /* CaptureMouse() should call SetError */
icculus@8955
   853
        }
icculus@8955
   854
        focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
icculus@8955
   855
    } else {
icculus@8955
   856
        if (mouse->CaptureMouse(NULL) == -1) {
icculus@8955
   857
            return -1;  /* CaptureMouse() should call SetError */
icculus@8955
   858
        }
icculus@8955
   859
        focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
icculus@8955
   860
    }
icculus@8955
   861
icculus@8955
   862
    return 0;
icculus@8955
   863
}
icculus@8955
   864
slouken@1895
   865
SDL_Cursor *
slouken@1895
   866
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
slouken@1895
   867
                 int w, int h, int hot_x, int hot_y)
slouken@1895
   868
{
slouken@1895
   869
    SDL_Surface *surface;
slouken@1895
   870
    SDL_Cursor *cursor;
slouken@1895
   871
    int x, y;
slouken@1895
   872
    Uint32 *pixel;
slouken@4465
   873
    Uint8 datab = 0, maskb = 0;
slouken@1895
   874
    const Uint32 black = 0xFF000000;
slouken@1895
   875
    const Uint32 white = 0xFFFFFFFF;
slouken@1895
   876
    const Uint32 transparent = 0x00000000;
slouken@1895
   877
slouken@1895
   878
    /* Make sure the width is a multiple of 8 */
slouken@1895
   879
    w = ((w + 7) & ~7);
slouken@1895
   880
slouken@1895
   881
    /* Create the surface from a bitmap */
slouken@5473
   882
    surface = SDL_CreateRGBSurface(0, w, h, 32,
slouken@5473
   883
                                   0x00FF0000,
slouken@5473
   884
                                   0x0000FF00,
slouken@5473
   885
                                   0x000000FF,
slouken@5473
   886
                                   0xFF000000);
slouken@1895
   887
    if (!surface) {
slouken@1895
   888
        return NULL;
slouken@1895
   889
    }
slouken@1895
   890
    for (y = 0; y < h; ++y) {
slouken@1895
   891
        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
slouken@1895
   892
        for (x = 0; x < w; ++x) {
slouken@1895
   893
            if ((x % 8) == 0) {
slouken@1895
   894
                datab = *data++;
slouken@1895
   895
                maskb = *mask++;
slouken@1895
   896
            }
slouken@1895
   897
            if (maskb & 0x80) {
slouken@1895
   898
                *pixel++ = (datab & 0x80) ? black : white;
slouken@1895
   899
            } else {
slouken@1895
   900
                *pixel++ = (datab & 0x80) ? black : transparent;
slouken@1895
   901
            }
slouken@1895
   902
            datab <<= 1;
slouken@1895
   903
            maskb <<= 1;
slouken@1895
   904
        }
slouken@1895
   905
    }
slouken@1895
   906
slouken@5473
   907
    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
slouken@5473
   908
slouken@5473
   909
    SDL_FreeSurface(surface);
slouken@5473
   910
slouken@5473
   911
    return cursor;
slouken@5473
   912
}
slouken@5473
   913
slouken@5473
   914
SDL_Cursor *
slouken@5473
   915
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
slouken@5473
   916
{
slouken@5473
   917
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5473
   918
    SDL_Surface *temp = NULL;
slouken@5473
   919
    SDL_Cursor *cursor;
slouken@5473
   920
slouken@5473
   921
    if (!surface) {
slouken@5473
   922
        SDL_SetError("Passed NULL cursor surface");
slouken@5473
   923
        return NULL;
slouken@5473
   924
    }
slouken@5473
   925
slouken@5473
   926
    if (!mouse->CreateCursor) {
slouken@5473
   927
        SDL_SetError("Cursors are not currently supported");
slouken@5473
   928
        return NULL;
slouken@5473
   929
    }
slouken@5473
   930
slouken@5473
   931
    /* Sanity check the hot spot */
slouken@5473
   932
    if ((hot_x < 0) || (hot_y < 0) ||
slouken@5473
   933
        (hot_x >= surface->w) || (hot_y >= surface->h)) {
slouken@5473
   934
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@5473
   935
        return NULL;
slouken@5473
   936
    }
slouken@5473
   937
slouken@5473
   938
    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
slouken@5473
   939
        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
slouken@5473
   940
        if (!temp) {
slouken@5473
   941
            return NULL;
slouken@5473
   942
        }
slouken@5473
   943
        surface = temp;
slouken@5473
   944
    }
slouken@5473
   945
slouken@1895
   946
    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
slouken@1895
   947
    if (cursor) {
slouken@1895
   948
        cursor->next = mouse->cursors;
slouken@1895
   949
        mouse->cursors = cursor;
slouken@1895
   950
    }
slouken@1895
   951
slouken@7720
   952
    SDL_FreeSurface(temp);
slouken@1895
   953
slouken@1895
   954
    return cursor;
slouken@1895
   955
}
slouken@1895
   956
mikesart@6675
   957
SDL_Cursor *
mikesart@6675
   958
SDL_CreateSystemCursor(SDL_SystemCursor id)
mikesart@6675
   959
{
mikesart@6675
   960
    SDL_Mouse *mouse = SDL_GetMouse();
mikesart@6675
   961
    SDL_Cursor *cursor;
mikesart@6675
   962
mikesart@6675
   963
    if (!mouse->CreateSystemCursor) {
mikesart@6675
   964
        SDL_SetError("CreateSystemCursor is not currently supported");
mikesart@6675
   965
        return NULL;
mikesart@6675
   966
    }
mikesart@6675
   967
slouken@7191
   968
    cursor = mouse->CreateSystemCursor(id);
mikesart@6675
   969
    if (cursor) {
mikesart@6675
   970
        cursor->next = mouse->cursors;
mikesart@6675
   971
        mouse->cursors = cursor;
mikesart@6675
   972
    }
mikesart@6675
   973
slouken@7191
   974
    return cursor;
mikesart@6675
   975
}
mikesart@6675
   976
slouken@1895
   977
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@1895
   978
   if this is desired for any reason.  This is used when setting
slouken@1895
   979
   the video mode and when the SDL window gains the mouse focus.
slouken@1895
   980
 */
slouken@1895
   981
void
slouken@1895
   982
SDL_SetCursor(SDL_Cursor * cursor)
slouken@1895
   983
{
slouken@5371
   984
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   985
slouken@1895
   986
    /* Set the new cursor */
slouken@1895
   987
    if (cursor) {
slouken@1895
   988
        /* Make sure the cursor is still valid for this mouse */
slouken@5405
   989
        if (cursor != mouse->def_cursor) {
slouken@5405
   990
            SDL_Cursor *found;
slouken@5405
   991
            for (found = mouse->cursors; found; found = found->next) {
slouken@5405
   992
                if (found == cursor) {
slouken@5405
   993
                    break;
slouken@5405
   994
                }
slouken@1895
   995
            }
slouken@5405
   996
            if (!found) {
slouken@5405
   997
                SDL_SetError("Cursor not associated with the current mouse");
slouken@5405
   998
                return;
slouken@5405
   999
            }
slouken@1895
  1000
        }
slouken@1895
  1001
        mouse->cur_cursor = cursor;
slouken@1895
  1002
    } else {
ghostunderscore@6301
  1003
        if (mouse->focus) {
ghostunderscore@6301
  1004
            cursor = mouse->cur_cursor;
ghostunderscore@6301
  1005
        } else {
ghostunderscore@6301
  1006
            cursor = mouse->def_cursor;
ghostunderscore@6301
  1007
        }
slouken@1895
  1008
    }
slouken@1895
  1009
slouken@1895
  1010
    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
slouken@1895
  1011
        if (mouse->ShowCursor) {
slouken@1895
  1012
            mouse->ShowCursor(cursor);
slouken@1895
  1013
        }
slouken@1895
  1014
    } else {
slouken@1895
  1015
        if (mouse->ShowCursor) {
slouken@1895
  1016
            mouse->ShowCursor(NULL);
slouken@1895
  1017
        }
slouken@1895
  1018
    }
slouken@1895
  1019
}
slouken@1895
  1020
slouken@1895
  1021
SDL_Cursor *
slouken@1895
  1022
SDL_GetCursor(void)
slouken@1895
  1023
{
slouken@5371
  1024
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
  1025
slouken@1895
  1026
    if (!mouse) {
slouken@1895
  1027
        return NULL;
slouken@1895
  1028
    }
slouken@1895
  1029
    return mouse->cur_cursor;
slouken@1895
  1030
}
slouken@1895
  1031
jorgen@7104
  1032
SDL_Cursor *
jorgen@7104
  1033
SDL_GetDefaultCursor(void)
jorgen@7104
  1034
{
jorgen@7104
  1035
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7104
  1036
jorgen@7104
  1037
    if (!mouse) {
jorgen@7104
  1038
        return NULL;
jorgen@7104
  1039
    }
jorgen@7104
  1040
    return mouse->def_cursor;
jorgen@7104
  1041
}
jorgen@7104
  1042
slouken@1895
  1043
void
slouken@1895
  1044
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@1895
  1045
{
slouken@5371
  1046
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
  1047
    SDL_Cursor *curr, *prev;
slouken@1895
  1048
slouken@1895
  1049
    if (!cursor) {
slouken@1895
  1050
        return;
slouken@1895
  1051
    }
slouken@1895
  1052
slouken@1895
  1053
    if (cursor == mouse->def_cursor) {
slouken@1895
  1054
        return;
slouken@1895
  1055
    }
slouken@1895
  1056
    if (cursor == mouse->cur_cursor) {
slouken@1895
  1057
        SDL_SetCursor(mouse->def_cursor);
slouken@1895
  1058
    }
slouken@1895
  1059
slouken@1895
  1060
    for (prev = NULL, curr = mouse->cursors; curr;
slouken@1895
  1061
         prev = curr, curr = curr->next) {
slouken@1895
  1062
        if (curr == cursor) {
slouken@1895
  1063
            if (prev) {
slouken@1895
  1064
                prev->next = curr->next;
slouken@1895
  1065
            } else {
slouken@1895
  1066
                mouse->cursors = curr->next;
slouken@1895
  1067
            }
slouken@1895
  1068
slouken@1895
  1069
            if (mouse->FreeCursor) {
slouken@1895
  1070
                mouse->FreeCursor(curr);
slouken@1895
  1071
            }
slouken@1895
  1072
            return;
slouken@1895
  1073
        }
slouken@1895
  1074
    }
slouken@1895
  1075
}
slouken@1895
  1076
slouken@1895
  1077
int
slouken@1895
  1078
SDL_ShowCursor(int toggle)
slouken@1895
  1079
{
slouken@5371
  1080
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
  1081
    SDL_bool shown;
slouken@1895
  1082
slouken@1895
  1083
    if (!mouse) {
slouken@1895
  1084
        return 0;
slouken@1895
  1085
    }
slouken@1895
  1086
slouken@1895
  1087
    shown = mouse->cursor_shown;
slouken@1895
  1088
    if (toggle >= 0) {
slouken@1895
  1089
        if (toggle) {
slouken@1895
  1090
            mouse->cursor_shown = SDL_TRUE;
slouken@1895
  1091
        } else {
slouken@1895
  1092
            mouse->cursor_shown = SDL_FALSE;
slouken@1895
  1093
        }
slouken@1895
  1094
        if (mouse->cursor_shown != shown) {
slouken@1895
  1095
            SDL_SetCursor(NULL);
slouken@1895
  1096
        }
slouken@1895
  1097
    }
slouken@1895
  1098
    return shown;
slouken@1895
  1099
}
slouken@1895
  1100
jorgen@7097
  1101
/* vi: set ts=4 sw=4 expandtab: */