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