src/events/SDL_mouse.c
author Ryan C. Gordon <icculus@icculus.org>
Sat, 24 May 2014 01:27:19 -0400
changeset 8783 400f1d2b9e52
parent 8776 29aac8b813d9
child 8815 c6d0a457f3b2
child 8927 be64f5daf64b
permissions -rw-r--r--
Added some FIXMEs.
     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 static SDL_bool
   499 ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
   500 {
   501     const char *hint;
   502 
   503     if (!mouse->SetRelativeMouseMode) {
   504         return SDL_TRUE;
   505     }
   506 
   507     hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
   508     if (hint) {
   509         if (*hint == '0') {
   510             return SDL_FALSE;
   511         } else {
   512             return SDL_TRUE;
   513         }
   514     }
   515     return SDL_FALSE;
   516 }
   517 
   518 int
   519 SDL_SetRelativeMouseMode(SDL_bool enabled)
   520 {
   521     SDL_Mouse *mouse = SDL_GetMouse();
   522     SDL_Window *focusWindow = SDL_GetKeyboardFocus();
   523 
   524     if (enabled == mouse->relative_mode) {
   525         return 0;
   526     }
   527 
   528     if (enabled && focusWindow) {
   529         /* Center it in the focused window to prevent clicks from going through
   530          * to background windows.
   531          */
   532         SDL_SetMouseFocus(focusWindow);
   533         SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
   534     }
   535 
   536     /* Set the relative mode */
   537     if (!enabled && mouse->relative_mode_warp) {
   538         mouse->relative_mode_warp = SDL_FALSE;
   539     } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
   540         mouse->relative_mode_warp = SDL_TRUE;
   541     } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
   542         if (enabled) {
   543             /* Fall back to warp mode if native relative mode failed */
   544             mouse->relative_mode_warp = SDL_TRUE;
   545         }
   546     }
   547     mouse->relative_mode = enabled;
   548 
   549     if (mouse->focus) {
   550         SDL_UpdateWindowGrab(mouse->focus);
   551 
   552         /* Put the cursor back to where the application expects it */
   553         if (!enabled) {
   554             SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   555         }
   556     }
   557 
   558     /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
   559     SDL_FlushEvent(SDL_MOUSEMOTION);
   560 
   561     /* Update cursor visibility */
   562     SDL_SetCursor(NULL);
   563 
   564     return 0;
   565 }
   566 
   567 SDL_bool
   568 SDL_GetRelativeMouseMode()
   569 {
   570     SDL_Mouse *mouse = SDL_GetMouse();
   571 
   572     return mouse->relative_mode;
   573 }
   574 
   575 SDL_Cursor *
   576 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   577                  int w, int h, int hot_x, int hot_y)
   578 {
   579     SDL_Surface *surface;
   580     SDL_Cursor *cursor;
   581     int x, y;
   582     Uint32 *pixel;
   583     Uint8 datab = 0, maskb = 0;
   584     const Uint32 black = 0xFF000000;
   585     const Uint32 white = 0xFFFFFFFF;
   586     const Uint32 transparent = 0x00000000;
   587 
   588     /* Make sure the width is a multiple of 8 */
   589     w = ((w + 7) & ~7);
   590 
   591     /* Create the surface from a bitmap */
   592     surface = SDL_CreateRGBSurface(0, w, h, 32,
   593                                    0x00FF0000,
   594                                    0x0000FF00,
   595                                    0x000000FF,
   596                                    0xFF000000);
   597     if (!surface) {
   598         return NULL;
   599     }
   600     for (y = 0; y < h; ++y) {
   601         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   602         for (x = 0; x < w; ++x) {
   603             if ((x % 8) == 0) {
   604                 datab = *data++;
   605                 maskb = *mask++;
   606             }
   607             if (maskb & 0x80) {
   608                 *pixel++ = (datab & 0x80) ? black : white;
   609             } else {
   610                 *pixel++ = (datab & 0x80) ? black : transparent;
   611             }
   612             datab <<= 1;
   613             maskb <<= 1;
   614         }
   615     }
   616 
   617     cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
   618 
   619     SDL_FreeSurface(surface);
   620 
   621     return cursor;
   622 }
   623 
   624 SDL_Cursor *
   625 SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
   626 {
   627     SDL_Mouse *mouse = SDL_GetMouse();
   628     SDL_Surface *temp = NULL;
   629     SDL_Cursor *cursor;
   630 
   631     if (!surface) {
   632         SDL_SetError("Passed NULL cursor surface");
   633         return NULL;
   634     }
   635 
   636     if (!mouse->CreateCursor) {
   637         SDL_SetError("Cursors are not currently supported");
   638         return NULL;
   639     }
   640 
   641     /* Sanity check the hot spot */
   642     if ((hot_x < 0) || (hot_y < 0) ||
   643         (hot_x >= surface->w) || (hot_y >= surface->h)) {
   644         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   645         return NULL;
   646     }
   647 
   648     if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
   649         temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
   650         if (!temp) {
   651             return NULL;
   652         }
   653         surface = temp;
   654     }
   655 
   656     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   657     if (cursor) {
   658         cursor->next = mouse->cursors;
   659         mouse->cursors = cursor;
   660     }
   661 
   662     SDL_FreeSurface(temp);
   663 
   664     return cursor;
   665 }
   666 
   667 SDL_Cursor *
   668 SDL_CreateSystemCursor(SDL_SystemCursor id)
   669 {
   670     SDL_Mouse *mouse = SDL_GetMouse();
   671     SDL_Cursor *cursor;
   672 
   673     if (!mouse->CreateSystemCursor) {
   674         SDL_SetError("CreateSystemCursor is not currently supported");
   675         return NULL;
   676     }
   677 
   678     cursor = mouse->CreateSystemCursor(id);
   679     if (cursor) {
   680         cursor->next = mouse->cursors;
   681         mouse->cursors = cursor;
   682     }
   683 
   684     return cursor;
   685 }
   686 
   687 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   688    if this is desired for any reason.  This is used when setting
   689    the video mode and when the SDL window gains the mouse focus.
   690  */
   691 void
   692 SDL_SetCursor(SDL_Cursor * cursor)
   693 {
   694     SDL_Mouse *mouse = SDL_GetMouse();
   695 
   696     /* Set the new cursor */
   697     if (cursor) {
   698         /* Make sure the cursor is still valid for this mouse */
   699         if (cursor != mouse->def_cursor) {
   700             SDL_Cursor *found;
   701             for (found = mouse->cursors; found; found = found->next) {
   702                 if (found == cursor) {
   703                     break;
   704                 }
   705             }
   706             if (!found) {
   707                 SDL_SetError("Cursor not associated with the current mouse");
   708                 return;
   709             }
   710         }
   711         mouse->cur_cursor = cursor;
   712     } else {
   713         if (mouse->focus) {
   714             cursor = mouse->cur_cursor;
   715         } else {
   716             cursor = mouse->def_cursor;
   717         }
   718     }
   719 
   720     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   721         if (mouse->ShowCursor) {
   722             mouse->ShowCursor(cursor);
   723         }
   724     } else {
   725         if (mouse->ShowCursor) {
   726             mouse->ShowCursor(NULL);
   727         }
   728     }
   729 }
   730 
   731 SDL_Cursor *
   732 SDL_GetCursor(void)
   733 {
   734     SDL_Mouse *mouse = SDL_GetMouse();
   735 
   736     if (!mouse) {
   737         return NULL;
   738     }
   739     return mouse->cur_cursor;
   740 }
   741 
   742 SDL_Cursor *
   743 SDL_GetDefaultCursor(void)
   744 {
   745     SDL_Mouse *mouse = SDL_GetMouse();
   746 
   747     if (!mouse) {
   748         return NULL;
   749     }
   750     return mouse->def_cursor;
   751 }
   752 
   753 void
   754 SDL_FreeCursor(SDL_Cursor * cursor)
   755 {
   756     SDL_Mouse *mouse = SDL_GetMouse();
   757     SDL_Cursor *curr, *prev;
   758 
   759     if (!cursor) {
   760         return;
   761     }
   762 
   763     if (cursor == mouse->def_cursor) {
   764         return;
   765     }
   766     if (cursor == mouse->cur_cursor) {
   767         SDL_SetCursor(mouse->def_cursor);
   768     }
   769 
   770     for (prev = NULL, curr = mouse->cursors; curr;
   771          prev = curr, curr = curr->next) {
   772         if (curr == cursor) {
   773             if (prev) {
   774                 prev->next = curr->next;
   775             } else {
   776                 mouse->cursors = curr->next;
   777             }
   778 
   779             if (mouse->FreeCursor) {
   780                 mouse->FreeCursor(curr);
   781             }
   782             return;
   783         }
   784     }
   785 }
   786 
   787 int
   788 SDL_ShowCursor(int toggle)
   789 {
   790     SDL_Mouse *mouse = SDL_GetMouse();
   791     SDL_bool shown;
   792 
   793     if (!mouse) {
   794         return 0;
   795     }
   796 
   797     shown = mouse->cursor_shown;
   798     if (toggle >= 0) {
   799         if (toggle) {
   800             mouse->cursor_shown = SDL_TRUE;
   801         } else {
   802             mouse->cursor_shown = SDL_FALSE;
   803         }
   804         if (mouse->cursor_shown != shown) {
   805             SDL_SetCursor(NULL);
   806         }
   807     }
   808     return shown;
   809 }
   810 
   811 /* vi: set ts=4 sw=4 expandtab: */