src/events/SDL_mouse.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 23 Dec 2013 17:37:22 -0800
changeset 8071 1ac2db4abe11
parent 8066 658b461d81be
child 8093 b43765095a6f
permissions -rw-r--r--
Added a relative mouse mode that uses mouse warping instead of raw input.
To enable this, set the environment variable SDL_MOUSE_RELATIVE_MODE_WARP to "1"

When mouse relative mode is disabled, put the cursor back where the application expects it to be, instead of where it was when relative mode was enabled.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* General mouse handling code for SDL */
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_hints.h"
    27 #include "SDL_timer.h"
    28 #include "SDL_events.h"
    29 #include "SDL_events_c.h"
    30 #include "default_cursor.h"
    31 #include "../video/SDL_sysvideo.h"
    32 
    33 /* #define DEBUG_MOUSE */
    34 
    35 /* The mouse state */
    36 static SDL_Mouse SDL_mouse;
    37 static Uint32 SDL_double_click_time = 500;
    38 static int SDL_double_click_radius = 1;
    39 
    40 static int
    41 SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
    42 
    43 /* Public functions */
    44 int
    45 SDL_MouseInit(void)
    46 {
    47     SDL_Mouse *mouse = SDL_GetMouse();
    48 
    49     mouse->cursor_shown = SDL_TRUE;
    50 
    51     return (0);
    52 }
    53 
    54 void
    55 SDL_SetDefaultCursor(SDL_Cursor * cursor)
    56 {
    57     SDL_Mouse *mouse = SDL_GetMouse();
    58 
    59     mouse->def_cursor = cursor;
    60     if (!mouse->cur_cursor) {
    61         SDL_SetCursor(cursor);
    62     }
    63 }
    64 
    65 SDL_Mouse *
    66 SDL_GetMouse(void)
    67 {
    68     return &SDL_mouse;
    69 }
    70 
    71 void
    72 SDL_SetDoubleClickTime(Uint32 interval)
    73 {
    74     SDL_double_click_time = interval;
    75 }
    76 
    77 SDL_Window *
    78 SDL_GetMouseFocus(void)
    79 {
    80     SDL_Mouse *mouse = SDL_GetMouse();
    81 
    82     return mouse->focus;
    83 }
    84 
    85 void
    86 SDL_ResetMouse(void)
    87 {
    88     SDL_Mouse *mouse = SDL_GetMouse();
    89     Uint8 i;
    90 
    91 #ifdef DEBUG_MOUSE
    92     printf("Resetting mouse\n");
    93 #endif
    94     for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
    95         if (mouse->buttonstate & SDL_BUTTON(i)) {
    96             SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
    97         }
    98     }
    99     SDL_assert(mouse->buttonstate == 0);
   100 }
   101 
   102 void
   103 SDL_SetMouseFocus(SDL_Window * window)
   104 {
   105     SDL_Mouse *mouse = SDL_GetMouse();
   106 
   107     if (mouse->focus == window) {
   108         return;
   109     }
   110 
   111     /* Actually, this ends up being a bad idea, because most operating
   112        systems have an implicit grab when you press the mouse button down
   113        so you can drag things out of the window and then get the mouse up
   114        when it happens.  So, #if 0...
   115     */
   116 #if 0
   117     if (mouse->focus && !window) {
   118         /* We won't get anymore mouse messages, so reset mouse state */
   119         SDL_ResetMouse();
   120     }
   121 #endif
   122 
   123     /* See if the current window has lost focus */
   124     if (mouse->focus) {
   125         SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   126     }
   127 
   128     mouse->focus = window;
   129 
   130     if (mouse->focus) {
   131         SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   132     }
   133 
   134     /* Update cursor visibility */
   135     SDL_SetCursor(NULL);
   136 }
   137 
   138 /* Check to see if we need to synthesize focus events */
   139 static SDL_bool
   140 SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
   141 {
   142     SDL_Mouse *mouse = SDL_GetMouse();
   143     int w, h;
   144     SDL_bool inWindow;
   145 
   146     SDL_GetWindowSize(window, &w, &h);
   147     if (x < 0 || y < 0 || x >= w || y >= h) {
   148         inWindow = SDL_FALSE;
   149     } else {
   150         inWindow = SDL_TRUE;
   151     }
   152 
   153 /* Linux doesn't give you mouse events outside your window unless you grab
   154    the pointer.
   155 
   156    Windows doesn't give you mouse events outside your window unless you call
   157    SetCapture().
   158 
   159    Both of these are slightly scary changes, so for now we'll punt and if the
   160    mouse leaves the window you'll lose mouse focus and reset button state.
   161 */
   162 #ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
   163     if (!inWindow && !buttonstate) {
   164 #else
   165     if (!inWindow) {
   166 #endif
   167         if (window == mouse->focus) {
   168 #ifdef DEBUG_MOUSE
   169             printf("Mouse left window, synthesizing move & focus lost event\n");
   170 #endif
   171             SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
   172             SDL_SetMouseFocus(NULL);
   173         }
   174         return SDL_FALSE;
   175     }
   176 
   177     if (window != mouse->focus) {
   178 #ifdef DEBUG_MOUSE
   179          printf("Mouse entered window, synthesizing focus gain & move event\n");
   180 #endif
   181          SDL_SetMouseFocus(window);
   182          SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
   183     }
   184     return SDL_TRUE;
   185 }
   186 
   187 int
   188 SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
   189 {
   190     if (window && !relative) {
   191         SDL_Mouse *mouse = SDL_GetMouse();
   192         if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
   193             return 0;
   194         }
   195     }
   196 
   197     return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
   198 }
   199 
   200 static int
   201 SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
   202 {
   203     SDL_Mouse *mouse = SDL_GetMouse();
   204     int posted;
   205     int xrel;
   206     int yrel;
   207     int x_max = 0, y_max = 0;
   208 
   209     if (mouse->relative_mode_warp) {
   210         int center_x = 0, center_y = 0;
   211         SDL_GetWindowSize(window, &center_x, &center_y);
   212         center_x /= 2;
   213         center_y /= 2;
   214         if (x == center_x && y == center_y) {
   215             mouse->last_x = center_x;
   216             mouse->last_y = center_y;
   217             return 0;
   218         }
   219         SDL_WarpMouseInWindow(window, center_x, center_y);
   220     }
   221 
   222     if (relative) {
   223         xrel = x;
   224         yrel = y;
   225         x = (mouse->last_x + xrel);
   226         y = (mouse->last_y + yrel);
   227     } else {
   228         xrel = x - mouse->last_x;
   229         yrel = y - mouse->last_y;
   230     }
   231 
   232     /* Drop events that don't change state */
   233     if (!xrel && !yrel) {
   234 #ifdef DEBUG_MOUSE
   235         printf("Mouse event didn't change state - dropped!\n");
   236 #endif
   237         return 0;
   238     }
   239 
   240     /* Update internal mouse coordinates */
   241     if (!mouse->relative_mode) {
   242         mouse->x = x;
   243         mouse->y = y;
   244     } else {
   245         mouse->x += xrel;
   246         mouse->y += yrel;
   247     }
   248 
   249     SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
   250     --x_max;
   251     --y_max;
   252 
   253     /* make sure that the pointers find themselves inside the windows */
   254     if (mouse->x > x_max) {
   255         mouse->x = x_max;
   256     }
   257     if (mouse->x < 0) {
   258         mouse->x = 0;
   259     }
   260 
   261     if (mouse->y > y_max) {
   262         mouse->y = y_max;
   263     }
   264     if (mouse->y < 0) {
   265         mouse->y = 0;
   266     }
   267 
   268     mouse->xdelta += xrel;
   269     mouse->ydelta += yrel;
   270 
   271     /* Move the mouse cursor, if needed */
   272     if (mouse->cursor_shown && !mouse->relative_mode &&
   273         mouse->MoveCursor && mouse->cur_cursor) {
   274         mouse->MoveCursor(mouse->cur_cursor);
   275     }
   276 
   277     /* Post the event, if desired */
   278     posted = 0;
   279     if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
   280         SDL_Event event;
   281         event.motion.type = SDL_MOUSEMOTION;
   282         event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
   283         event.motion.which = mouseID;
   284         event.motion.state = mouse->buttonstate;
   285         event.motion.x = mouse->x;
   286         event.motion.y = mouse->y;
   287         event.motion.xrel = xrel;
   288         event.motion.yrel = yrel;
   289         posted = (SDL_PushEvent(&event) > 0);
   290     }
   291     /* Use unclamped values if we're getting events outside the window */
   292     mouse->last_x = x;
   293     mouse->last_y = y;
   294     return posted;
   295 }
   296 
   297 static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
   298 {
   299     if (button >= mouse->num_clickstates) {
   300         int i, count = button + 1;
   301         mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
   302         if (!mouse->clickstate) {
   303             return NULL;
   304         }
   305 
   306         for (i = mouse->num_clickstates; i < count; ++i) {
   307             SDL_zero(mouse->clickstate[i]);
   308         }
   309         mouse->num_clickstates = count;
   310     }
   311     return &mouse->clickstate[button];
   312 }
   313 
   314 int
   315 SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
   316 {
   317     SDL_Mouse *mouse = SDL_GetMouse();
   318     int posted;
   319     Uint32 type;
   320     Uint32 buttonstate = mouse->buttonstate;
   321     SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
   322     Uint8 click_count;
   323 
   324     /* Figure out which event to perform */
   325     switch (state) {
   326     case SDL_PRESSED:
   327         type = SDL_MOUSEBUTTONDOWN;
   328         buttonstate |= SDL_BUTTON(button);
   329         break;
   330     case SDL_RELEASED:
   331         type = SDL_MOUSEBUTTONUP;
   332         buttonstate &= ~SDL_BUTTON(button);
   333         break;
   334     default:
   335         /* Invalid state -- bail */
   336         return 0;
   337     }
   338 
   339     /* We do this after calculating buttonstate so button presses gain focus */
   340     if (window && state == SDL_PRESSED) {
   341         SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   342     }
   343 
   344     if (buttonstate == mouse->buttonstate) {
   345         /* Ignore this event, no state change */
   346         return 0;
   347     }
   348     mouse->buttonstate = buttonstate;
   349 
   350     if (clickstate) {
   351         if (state == SDL_PRESSED) {
   352             Uint32 now = SDL_GetTicks();
   353 
   354             if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
   355                 SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
   356                 SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
   357                 clickstate->click_count = 0;
   358             }
   359             clickstate->last_timestamp = now;
   360             clickstate->last_x = mouse->x;
   361             clickstate->last_y = mouse->y;
   362             if (clickstate->click_count < 255) {
   363                 ++clickstate->click_count;
   364             }
   365         }
   366         click_count = clickstate->click_count;
   367     } else {
   368         click_count = 1;
   369     }
   370 
   371     /* Post the event, if desired */
   372     posted = 0;
   373     if (SDL_GetEventState(type) == SDL_ENABLE) {
   374         SDL_Event event;
   375         event.type = type;
   376         event.button.windowID = mouse->focus ? mouse->focus->id : 0;
   377         event.button.which = mouseID;
   378         event.button.state = state;
   379         event.button.button = button;
   380         event.button.clicks = click_count;
   381         event.button.x = mouse->x;
   382         event.button.y = mouse->y;
   383         posted = (SDL_PushEvent(&event) > 0);
   384     }
   385 
   386     /* We do this after dispatching event so button releases can lose focus */
   387     if (window && state == SDL_RELEASED) {
   388         SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   389     }
   390 
   391     return posted;
   392 }
   393 
   394 int
   395 SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y)
   396 {
   397     SDL_Mouse *mouse = SDL_GetMouse();
   398     int posted;
   399 
   400     if (window) {
   401         SDL_SetMouseFocus(window);
   402     }
   403 
   404     if (!x && !y) {
   405         return 0;
   406     }
   407 
   408     /* Post the event, if desired */
   409     posted = 0;
   410     if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
   411         SDL_Event event;
   412         event.type = SDL_MOUSEWHEEL;
   413         event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
   414         event.wheel.which = mouseID;
   415         event.wheel.x = x;
   416         event.wheel.y = y;
   417         posted = (SDL_PushEvent(&event) > 0);
   418     }
   419     return posted;
   420 }
   421 
   422 void
   423 SDL_MouseQuit(void)
   424 {
   425     SDL_Cursor *cursor, *next;
   426     SDL_Mouse *mouse = SDL_GetMouse();
   427 
   428     SDL_SetRelativeMouseMode(SDL_FALSE);
   429     SDL_ShowCursor(1);
   430 
   431     cursor = mouse->cursors;
   432     while (cursor) {
   433         next = cursor->next;
   434         SDL_FreeCursor(cursor);
   435         cursor = next;
   436     }
   437 
   438     if (mouse->def_cursor && mouse->FreeCursor) {
   439         mouse->FreeCursor(mouse->def_cursor);
   440     }
   441 
   442     if (mouse->clickstate) {
   443         SDL_free(mouse->clickstate);
   444     }
   445 
   446     SDL_zerop(mouse);
   447 }
   448 
   449 Uint32
   450 SDL_GetMouseState(int *x, int *y)
   451 {
   452     SDL_Mouse *mouse = SDL_GetMouse();
   453 
   454     if (x) {
   455         *x = mouse->x;
   456     }
   457     if (y) {
   458         *y = mouse->y;
   459     }
   460     return mouse->buttonstate;
   461 }
   462 
   463 Uint32
   464 SDL_GetRelativeMouseState(int *x, int *y)
   465 {
   466     SDL_Mouse *mouse = SDL_GetMouse();
   467 
   468     if (x) {
   469         *x = mouse->xdelta;
   470     }
   471     if (y) {
   472         *y = mouse->ydelta;
   473     }
   474     mouse->xdelta = 0;
   475     mouse->ydelta = 0;
   476     return mouse->buttonstate;
   477 }
   478 
   479 void
   480 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
   481 {
   482     SDL_Mouse *mouse = SDL_GetMouse();
   483 
   484     if ( window == NULL )
   485         window = mouse->focus;
   486 
   487     if ( window == NULL )
   488         return;
   489 
   490     if (mouse->WarpMouse) {
   491         mouse->WarpMouse(window, x, y);
   492     } else {
   493         SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
   494     }
   495 }
   496 
   497 static SDL_bool
   498 ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
   499 {
   500     const char *hint;
   501 
   502     if (!mouse->SetRelativeMouseMode) {
   503         return SDL_TRUE;
   504     }
   505 
   506     hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
   507     if (hint) {
   508         if (*hint == '0') {
   509             return SDL_FALSE;
   510         } else {
   511             return SDL_TRUE;
   512         }
   513     }
   514     return SDL_FALSE;
   515 }
   516 
   517 int
   518 SDL_SetRelativeMouseMode(SDL_bool enabled)
   519 {
   520     SDL_Mouse *mouse = SDL_GetMouse();
   521     SDL_Window *focusWindow = SDL_GetKeyboardFocus();
   522 
   523     if (enabled == mouse->relative_mode) {
   524         return 0;
   525     }
   526 
   527     if (enabled && focusWindow) {
   528         /* Center it in the focused window to prevent clicks from going through
   529          * to background windows.
   530          */
   531         SDL_SetMouseFocus(focusWindow);
   532         SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
   533     }
   534 
   535     /* Set the relative mode */
   536     if (!enabled && mouse->relative_mode_warp) {
   537         mouse->relative_mode_warp = SDL_FALSE;
   538     } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
   539         mouse->relative_mode_warp = SDL_TRUE;
   540     } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
   541         return -1;
   542     }
   543     mouse->relative_mode = enabled;
   544 
   545     if (mouse->focus) {
   546         SDL_UpdateWindowGrab(mouse->focus);
   547 
   548         /* Put the cursor back to where the application expects it */
   549         if (!enabled) {
   550             SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   551         }
   552     }
   553 
   554     /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
   555     SDL_FlushEvent(SDL_MOUSEMOTION);
   556 
   557     /* Update cursor visibility */
   558     SDL_SetCursor(NULL);
   559 
   560     return 0;
   561 }
   562 
   563 SDL_bool
   564 SDL_GetRelativeMouseMode()
   565 {
   566     SDL_Mouse *mouse = SDL_GetMouse();
   567 
   568     return mouse->relative_mode;
   569 }
   570 
   571 SDL_Cursor *
   572 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   573                  int w, int h, int hot_x, int hot_y)
   574 {
   575     SDL_Surface *surface;
   576     SDL_Cursor *cursor;
   577     int x, y;
   578     Uint32 *pixel;
   579     Uint8 datab = 0, maskb = 0;
   580     const Uint32 black = 0xFF000000;
   581     const Uint32 white = 0xFFFFFFFF;
   582     const Uint32 transparent = 0x00000000;
   583 
   584     /* Make sure the width is a multiple of 8 */
   585     w = ((w + 7) & ~7);
   586 
   587     /* Create the surface from a bitmap */
   588     surface = SDL_CreateRGBSurface(0, w, h, 32,
   589                                    0x00FF0000,
   590                                    0x0000FF00,
   591                                    0x000000FF,
   592                                    0xFF000000);
   593     if (!surface) {
   594         return NULL;
   595     }
   596     for (y = 0; y < h; ++y) {
   597         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   598         for (x = 0; x < w; ++x) {
   599             if ((x % 8) == 0) {
   600                 datab = *data++;
   601                 maskb = *mask++;
   602             }
   603             if (maskb & 0x80) {
   604                 *pixel++ = (datab & 0x80) ? black : white;
   605             } else {
   606                 *pixel++ = (datab & 0x80) ? black : transparent;
   607             }
   608             datab <<= 1;
   609             maskb <<= 1;
   610         }
   611     }
   612 
   613     cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
   614 
   615     SDL_FreeSurface(surface);
   616 
   617     return cursor;
   618 }
   619 
   620 SDL_Cursor *
   621 SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
   622 {
   623     SDL_Mouse *mouse = SDL_GetMouse();
   624     SDL_Surface *temp = NULL;
   625     SDL_Cursor *cursor;
   626 
   627     if (!surface) {
   628         SDL_SetError("Passed NULL cursor surface");
   629         return NULL;
   630     }
   631 
   632     if (!mouse->CreateCursor) {
   633         SDL_SetError("Cursors are not currently supported");
   634         return NULL;
   635     }
   636 
   637     /* Sanity check the hot spot */
   638     if ((hot_x < 0) || (hot_y < 0) ||
   639         (hot_x >= surface->w) || (hot_y >= surface->h)) {
   640         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   641         return NULL;
   642     }
   643 
   644     if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
   645         temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
   646         if (!temp) {
   647             return NULL;
   648         }
   649         surface = temp;
   650     }
   651 
   652     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   653     if (cursor) {
   654         cursor->next = mouse->cursors;
   655         mouse->cursors = cursor;
   656     }
   657 
   658     SDL_FreeSurface(temp);
   659 
   660     return cursor;
   661 }
   662 
   663 SDL_Cursor *
   664 SDL_CreateSystemCursor(SDL_SystemCursor id)
   665 {
   666     SDL_Mouse *mouse = SDL_GetMouse();
   667     SDL_Cursor *cursor;
   668 
   669     if (!mouse->CreateSystemCursor) {
   670         SDL_SetError("CreateSystemCursor is not currently supported");
   671         return NULL;
   672     }
   673 
   674     cursor = mouse->CreateSystemCursor(id);
   675     if (cursor) {
   676         cursor->next = mouse->cursors;
   677         mouse->cursors = cursor;
   678     }
   679 
   680     return cursor;
   681 }
   682 
   683 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   684    if this is desired for any reason.  This is used when setting
   685    the video mode and when the SDL window gains the mouse focus.
   686  */
   687 void
   688 SDL_SetCursor(SDL_Cursor * cursor)
   689 {
   690     SDL_Mouse *mouse = SDL_GetMouse();
   691 
   692     /* Set the new cursor */
   693     if (cursor) {
   694         /* Make sure the cursor is still valid for this mouse */
   695         if (cursor != mouse->def_cursor) {
   696             SDL_Cursor *found;
   697             for (found = mouse->cursors; found; found = found->next) {
   698                 if (found == cursor) {
   699                     break;
   700                 }
   701             }
   702             if (!found) {
   703                 SDL_SetError("Cursor not associated with the current mouse");
   704                 return;
   705             }
   706         }
   707         mouse->cur_cursor = cursor;
   708     } else {
   709         if (mouse->focus) {
   710             cursor = mouse->cur_cursor;
   711         } else {
   712             cursor = mouse->def_cursor;
   713         }
   714     }
   715 
   716     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   717         if (mouse->ShowCursor) {
   718             mouse->ShowCursor(cursor);
   719         }
   720     } else {
   721         if (mouse->ShowCursor) {
   722             mouse->ShowCursor(NULL);
   723         }
   724     }
   725 }
   726 
   727 SDL_Cursor *
   728 SDL_GetCursor(void)
   729 {
   730     SDL_Mouse *mouse = SDL_GetMouse();
   731 
   732     if (!mouse) {
   733         return NULL;
   734     }
   735     return mouse->cur_cursor;
   736 }
   737 
   738 SDL_Cursor *
   739 SDL_GetDefaultCursor(void)
   740 {
   741     SDL_Mouse *mouse = SDL_GetMouse();
   742 
   743     if (!mouse) {
   744         return NULL;
   745     }
   746     return mouse->def_cursor;
   747 }
   748 
   749 void
   750 SDL_FreeCursor(SDL_Cursor * cursor)
   751 {
   752     SDL_Mouse *mouse = SDL_GetMouse();
   753     SDL_Cursor *curr, *prev;
   754 
   755     if (!cursor) {
   756         return;
   757     }
   758 
   759     if (cursor == mouse->def_cursor) {
   760         return;
   761     }
   762     if (cursor == mouse->cur_cursor) {
   763         SDL_SetCursor(mouse->def_cursor);
   764     }
   765 
   766     for (prev = NULL, curr = mouse->cursors; curr;
   767          prev = curr, curr = curr->next) {
   768         if (curr == cursor) {
   769             if (prev) {
   770                 prev->next = curr->next;
   771             } else {
   772                 mouse->cursors = curr->next;
   773             }
   774 
   775             if (mouse->FreeCursor) {
   776                 mouse->FreeCursor(curr);
   777             }
   778             return;
   779         }
   780     }
   781 }
   782 
   783 int
   784 SDL_ShowCursor(int toggle)
   785 {
   786     SDL_Mouse *mouse = SDL_GetMouse();
   787     SDL_bool shown;
   788 
   789     if (!mouse) {
   790         return 0;
   791     }
   792 
   793     shown = mouse->cursor_shown;
   794     if (toggle >= 0) {
   795         if (toggle) {
   796             mouse->cursor_shown = SDL_TRUE;
   797         } else {
   798             mouse->cursor_shown = SDL_FALSE;
   799         }
   800         if (mouse->cursor_shown != shown) {
   801             SDL_SetCursor(NULL);
   802         }
   803     }
   804     return shown;
   805 }
   806 
   807 /* vi: set ts=4 sw=4 expandtab: */