src/events/SDL_mouse.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 04 Jun 2014 10:55:26 -0700
changeset 8815 c6d0a457f3b2
parent 8783 400f1d2b9e52
child 8953 dc80dc0bd22e
permissions -rw-r--r--
Added an API function to warp the mouse cursor in global screen space: SDL_WarpMouseGlobal()
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.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     /* !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? */
   250     SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
   251     --x_max;
   252     --y_max;
   253 
   254     /* make sure that the pointers find themselves inside the windows */
   255     if (mouse->x > x_max) {
   256         mouse->x = x_max;
   257     }
   258     if (mouse->x < 0) {
   259         mouse->x = 0;
   260     }
   261 
   262     if (mouse->y > y_max) {
   263         mouse->y = y_max;
   264     }
   265     if (mouse->y < 0) {
   266         mouse->y = 0;
   267     }
   268 
   269     mouse->xdelta += xrel;
   270     mouse->ydelta += yrel;
   271 
   272     /* Move the mouse cursor, if needed */
   273     if (mouse->cursor_shown && !mouse->relative_mode &&
   274         mouse->MoveCursor && mouse->cur_cursor) {
   275         mouse->MoveCursor(mouse->cur_cursor);
   276     }
   277 
   278     /* Post the event, if desired */
   279     posted = 0;
   280     if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
   281         SDL_Event event;
   282         event.motion.type = SDL_MOUSEMOTION;
   283         event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
   284         event.motion.which = mouseID;
   285         event.motion.state = mouse->buttonstate;
   286         event.motion.x = mouse->x;
   287         event.motion.y = mouse->y;
   288         event.motion.xrel = xrel;
   289         event.motion.yrel = yrel;
   290         posted = (SDL_PushEvent(&event) > 0);
   291     }
   292     /* Use unclamped values if we're getting events outside the window */
   293     mouse->last_x = x;
   294     mouse->last_y = y;
   295     return posted;
   296 }
   297 
   298 static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
   299 {
   300     if (button >= mouse->num_clickstates) {
   301         int i, count = button + 1;
   302         mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
   303         if (!mouse->clickstate) {
   304             return NULL;
   305         }
   306 
   307         for (i = mouse->num_clickstates; i < count; ++i) {
   308             SDL_zero(mouse->clickstate[i]);
   309         }
   310         mouse->num_clickstates = count;
   311     }
   312     return &mouse->clickstate[button];
   313 }
   314 
   315 int
   316 SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
   317 {
   318     SDL_Mouse *mouse = SDL_GetMouse();
   319     int posted;
   320     Uint32 type;
   321     Uint32 buttonstate = mouse->buttonstate;
   322     SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
   323     Uint8 click_count;
   324 
   325     /* Figure out which event to perform */
   326     switch (state) {
   327     case SDL_PRESSED:
   328         type = SDL_MOUSEBUTTONDOWN;
   329         buttonstate |= SDL_BUTTON(button);
   330         break;
   331     case SDL_RELEASED:
   332         type = SDL_MOUSEBUTTONUP;
   333         buttonstate &= ~SDL_BUTTON(button);
   334         break;
   335     default:
   336         /* Invalid state -- bail */
   337         return 0;
   338     }
   339 
   340     /* We do this after calculating buttonstate so button presses gain focus */
   341     if (window && state == SDL_PRESSED) {
   342         SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   343     }
   344 
   345     if (buttonstate == mouse->buttonstate) {
   346         /* Ignore this event, no state change */
   347         return 0;
   348     }
   349     mouse->buttonstate = buttonstate;
   350 
   351     if (clickstate) {
   352         if (state == SDL_PRESSED) {
   353             Uint32 now = SDL_GetTicks();
   354 
   355             if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
   356                 SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
   357                 SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
   358                 clickstate->click_count = 0;
   359             }
   360             clickstate->last_timestamp = now;
   361             clickstate->last_x = mouse->x;
   362             clickstate->last_y = mouse->y;
   363             if (clickstate->click_count < 255) {
   364                 ++clickstate->click_count;
   365             }
   366         }
   367         click_count = clickstate->click_count;
   368     } else {
   369         click_count = 1;
   370     }
   371 
   372     /* Post the event, if desired */
   373     posted = 0;
   374     if (SDL_GetEventState(type) == SDL_ENABLE) {
   375         SDL_Event event;
   376         event.type = type;
   377         event.button.windowID = mouse->focus ? mouse->focus->id : 0;
   378         event.button.which = mouseID;
   379         event.button.state = state;
   380         event.button.button = button;
   381         event.button.clicks = click_count;
   382         event.button.x = mouse->x;
   383         event.button.y = mouse->y;
   384         posted = (SDL_PushEvent(&event) > 0);
   385     }
   386 
   387     /* We do this after dispatching event so button releases can lose focus */
   388     if (window && state == SDL_RELEASED) {
   389         SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   390     }
   391 
   392     return posted;
   393 }
   394 
   395 int
   396 SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y)
   397 {
   398     SDL_Mouse *mouse = SDL_GetMouse();
   399     int posted;
   400 
   401     if (window) {
   402         SDL_SetMouseFocus(window);
   403     }
   404 
   405     if (!x && !y) {
   406         return 0;
   407     }
   408 
   409     /* Post the event, if desired */
   410     posted = 0;
   411     if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
   412         SDL_Event event;
   413         event.type = SDL_MOUSEWHEEL;
   414         event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
   415         event.wheel.which = mouseID;
   416         event.wheel.x = x;
   417         event.wheel.y = y;
   418         posted = (SDL_PushEvent(&event) > 0);
   419     }
   420     return posted;
   421 }
   422 
   423 void
   424 SDL_MouseQuit(void)
   425 {
   426     SDL_Cursor *cursor, *next;
   427     SDL_Mouse *mouse = SDL_GetMouse();
   428 
   429     SDL_SetRelativeMouseMode(SDL_FALSE);
   430     SDL_ShowCursor(1);
   431 
   432     cursor = mouse->cursors;
   433     while (cursor) {
   434         next = cursor->next;
   435         SDL_FreeCursor(cursor);
   436         cursor = next;
   437     }
   438 
   439     if (mouse->def_cursor && mouse->FreeCursor) {
   440         mouse->FreeCursor(mouse->def_cursor);
   441     }
   442 
   443     if (mouse->clickstate) {
   444         SDL_free(mouse->clickstate);
   445     }
   446 
   447     SDL_zerop(mouse);
   448 }
   449 
   450 Uint32
   451 SDL_GetMouseState(int *x, int *y)
   452 {
   453     SDL_Mouse *mouse = SDL_GetMouse();
   454 
   455     if (x) {
   456         *x = mouse->x;
   457     }
   458     if (y) {
   459         *y = mouse->y;
   460     }
   461     return mouse->buttonstate;
   462 }
   463 
   464 Uint32
   465 SDL_GetRelativeMouseState(int *x, int *y)
   466 {
   467     SDL_Mouse *mouse = SDL_GetMouse();
   468 
   469     if (x) {
   470         *x = mouse->xdelta;
   471     }
   472     if (y) {
   473         *y = mouse->ydelta;
   474     }
   475     mouse->xdelta = 0;
   476     mouse->ydelta = 0;
   477     return mouse->buttonstate;
   478 }
   479 
   480 void
   481 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
   482 {
   483     SDL_Mouse *mouse = SDL_GetMouse();
   484 
   485     if (window == NULL)
   486         window = mouse->focus;
   487 
   488     if (window == NULL)
   489         return;
   490 
   491     if (mouse->WarpMouse) {
   492         mouse->WarpMouse(window, x, y);
   493     } else {
   494         SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
   495     }
   496 }
   497 
   498 void
   499 SDL_WarpMouseGlobal(int x, int y)
   500 {
   501     SDL_Mouse *mouse = SDL_GetMouse();
   502 
   503     if (mouse->WarpMouseGlobal) {
   504         mouse->WarpMouseGlobal(x, y);
   505     }
   506 }
   507 
   508 static SDL_bool
   509 ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
   510 {
   511     const char *hint;
   512 
   513     if (!mouse->SetRelativeMouseMode) {
   514         return SDL_TRUE;
   515     }
   516 
   517     hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
   518     if (hint) {
   519         if (*hint == '0') {
   520             return SDL_FALSE;
   521         } else {
   522             return SDL_TRUE;
   523         }
   524     }
   525     return SDL_FALSE;
   526 }
   527 
   528 int
   529 SDL_SetRelativeMouseMode(SDL_bool enabled)
   530 {
   531     SDL_Mouse *mouse = SDL_GetMouse();
   532     SDL_Window *focusWindow = SDL_GetKeyboardFocus();
   533 
   534     if (enabled == mouse->relative_mode) {
   535         return 0;
   536     }
   537 
   538     if (enabled && focusWindow) {
   539         /* Center it in the focused window to prevent clicks from going through
   540          * to background windows.
   541          */
   542         SDL_SetMouseFocus(focusWindow);
   543         SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
   544     }
   545 
   546     /* Set the relative mode */
   547     if (!enabled && mouse->relative_mode_warp) {
   548         mouse->relative_mode_warp = SDL_FALSE;
   549     } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
   550         mouse->relative_mode_warp = SDL_TRUE;
   551     } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
   552         if (enabled) {
   553             /* Fall back to warp mode if native relative mode failed */
   554             mouse->relative_mode_warp = SDL_TRUE;
   555         }
   556     }
   557     mouse->relative_mode = enabled;
   558 
   559     if (mouse->focus) {
   560         SDL_UpdateWindowGrab(mouse->focus);
   561 
   562         /* Put the cursor back to where the application expects it */
   563         if (!enabled) {
   564             SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   565         }
   566     }
   567 
   568     /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
   569     SDL_FlushEvent(SDL_MOUSEMOTION);
   570 
   571     /* Update cursor visibility */
   572     SDL_SetCursor(NULL);
   573 
   574     return 0;
   575 }
   576 
   577 SDL_bool
   578 SDL_GetRelativeMouseMode()
   579 {
   580     SDL_Mouse *mouse = SDL_GetMouse();
   581 
   582     return mouse->relative_mode;
   583 }
   584 
   585 SDL_Cursor *
   586 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   587                  int w, int h, int hot_x, int hot_y)
   588 {
   589     SDL_Surface *surface;
   590     SDL_Cursor *cursor;
   591     int x, y;
   592     Uint32 *pixel;
   593     Uint8 datab = 0, maskb = 0;
   594     const Uint32 black = 0xFF000000;
   595     const Uint32 white = 0xFFFFFFFF;
   596     const Uint32 transparent = 0x00000000;
   597 
   598     /* Make sure the width is a multiple of 8 */
   599     w = ((w + 7) & ~7);
   600 
   601     /* Create the surface from a bitmap */
   602     surface = SDL_CreateRGBSurface(0, w, h, 32,
   603                                    0x00FF0000,
   604                                    0x0000FF00,
   605                                    0x000000FF,
   606                                    0xFF000000);
   607     if (!surface) {
   608         return NULL;
   609     }
   610     for (y = 0; y < h; ++y) {
   611         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   612         for (x = 0; x < w; ++x) {
   613             if ((x % 8) == 0) {
   614                 datab = *data++;
   615                 maskb = *mask++;
   616             }
   617             if (maskb & 0x80) {
   618                 *pixel++ = (datab & 0x80) ? black : white;
   619             } else {
   620                 *pixel++ = (datab & 0x80) ? black : transparent;
   621             }
   622             datab <<= 1;
   623             maskb <<= 1;
   624         }
   625     }
   626 
   627     cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
   628 
   629     SDL_FreeSurface(surface);
   630 
   631     return cursor;
   632 }
   633 
   634 SDL_Cursor *
   635 SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
   636 {
   637     SDL_Mouse *mouse = SDL_GetMouse();
   638     SDL_Surface *temp = NULL;
   639     SDL_Cursor *cursor;
   640 
   641     if (!surface) {
   642         SDL_SetError("Passed NULL cursor surface");
   643         return NULL;
   644     }
   645 
   646     if (!mouse->CreateCursor) {
   647         SDL_SetError("Cursors are not currently supported");
   648         return NULL;
   649     }
   650 
   651     /* Sanity check the hot spot */
   652     if ((hot_x < 0) || (hot_y < 0) ||
   653         (hot_x >= surface->w) || (hot_y >= surface->h)) {
   654         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   655         return NULL;
   656     }
   657 
   658     if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
   659         temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
   660         if (!temp) {
   661             return NULL;
   662         }
   663         surface = temp;
   664     }
   665 
   666     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   667     if (cursor) {
   668         cursor->next = mouse->cursors;
   669         mouse->cursors = cursor;
   670     }
   671 
   672     SDL_FreeSurface(temp);
   673 
   674     return cursor;
   675 }
   676 
   677 SDL_Cursor *
   678 SDL_CreateSystemCursor(SDL_SystemCursor id)
   679 {
   680     SDL_Mouse *mouse = SDL_GetMouse();
   681     SDL_Cursor *cursor;
   682 
   683     if (!mouse->CreateSystemCursor) {
   684         SDL_SetError("CreateSystemCursor is not currently supported");
   685         return NULL;
   686     }
   687 
   688     cursor = mouse->CreateSystemCursor(id);
   689     if (cursor) {
   690         cursor->next = mouse->cursors;
   691         mouse->cursors = cursor;
   692     }
   693 
   694     return cursor;
   695 }
   696 
   697 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   698    if this is desired for any reason.  This is used when setting
   699    the video mode and when the SDL window gains the mouse focus.
   700  */
   701 void
   702 SDL_SetCursor(SDL_Cursor * cursor)
   703 {
   704     SDL_Mouse *mouse = SDL_GetMouse();
   705 
   706     /* Set the new cursor */
   707     if (cursor) {
   708         /* Make sure the cursor is still valid for this mouse */
   709         if (cursor != mouse->def_cursor) {
   710             SDL_Cursor *found;
   711             for (found = mouse->cursors; found; found = found->next) {
   712                 if (found == cursor) {
   713                     break;
   714                 }
   715             }
   716             if (!found) {
   717                 SDL_SetError("Cursor not associated with the current mouse");
   718                 return;
   719             }
   720         }
   721         mouse->cur_cursor = cursor;
   722     } else {
   723         if (mouse->focus) {
   724             cursor = mouse->cur_cursor;
   725         } else {
   726             cursor = mouse->def_cursor;
   727         }
   728     }
   729 
   730     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   731         if (mouse->ShowCursor) {
   732             mouse->ShowCursor(cursor);
   733         }
   734     } else {
   735         if (mouse->ShowCursor) {
   736             mouse->ShowCursor(NULL);
   737         }
   738     }
   739 }
   740 
   741 SDL_Cursor *
   742 SDL_GetCursor(void)
   743 {
   744     SDL_Mouse *mouse = SDL_GetMouse();
   745 
   746     if (!mouse) {
   747         return NULL;
   748     }
   749     return mouse->cur_cursor;
   750 }
   751 
   752 SDL_Cursor *
   753 SDL_GetDefaultCursor(void)
   754 {
   755     SDL_Mouse *mouse = SDL_GetMouse();
   756 
   757     if (!mouse) {
   758         return NULL;
   759     }
   760     return mouse->def_cursor;
   761 }
   762 
   763 void
   764 SDL_FreeCursor(SDL_Cursor * cursor)
   765 {
   766     SDL_Mouse *mouse = SDL_GetMouse();
   767     SDL_Cursor *curr, *prev;
   768 
   769     if (!cursor) {
   770         return;
   771     }
   772 
   773     if (cursor == mouse->def_cursor) {
   774         return;
   775     }
   776     if (cursor == mouse->cur_cursor) {
   777         SDL_SetCursor(mouse->def_cursor);
   778     }
   779 
   780     for (prev = NULL, curr = mouse->cursors; curr;
   781          prev = curr, curr = curr->next) {
   782         if (curr == cursor) {
   783             if (prev) {
   784                 prev->next = curr->next;
   785             } else {
   786                 mouse->cursors = curr->next;
   787             }
   788 
   789             if (mouse->FreeCursor) {
   790                 mouse->FreeCursor(curr);
   791             }
   792             return;
   793         }
   794     }
   795 }
   796 
   797 int
   798 SDL_ShowCursor(int toggle)
   799 {
   800     SDL_Mouse *mouse = SDL_GetMouse();
   801     SDL_bool shown;
   802 
   803     if (!mouse) {
   804         return 0;
   805     }
   806 
   807     shown = mouse->cursor_shown;
   808     if (toggle >= 0) {
   809         if (toggle) {
   810             mouse->cursor_shown = SDL_TRUE;
   811         } else {
   812             mouse->cursor_shown = SDL_FALSE;
   813         }
   814         if (mouse->cursor_shown != shown) {
   815             SDL_SetCursor(NULL);
   816         }
   817     }
   818     return shown;
   819 }
   820 
   821 /* vi: set ts=4 sw=4 expandtab: */