src/events/SDL_mouse.c
author Sam Lantinga
Sat, 06 Dec 2008 17:50:50 +0000
changeset 2842 97ba0be8b565
parent 2794 f7872b7a8732
child 2849 523b10db69f8
permissions -rw-r--r--
Date: Sat, 06 Dec 2008 15:27:00 +0100
From: Couriersud
Subject: SDL: Relative mouse movements

The patch below will reenable processing of relative mouse movements.
The DirectFB drivers generates those in "grabbed" mode. These ensure,
that even in fullscreen mode relative movements are reported. SDLMAME
depends on this for games with trackballs.

Looking at the code I ask myself whether relative movements should be
handled in the drivers (x11, directfb). Both x11 and directfb are able
to report relative movements. This would leave it to the driver to use
the most appropriate method for relative movements when at the border of
a fullscreen window or being "grabbed".
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* General mouse handling code for SDL */
    25 
    26 #include "SDL_events.h"
    27 #include "SDL_events_c.h"
    28 #include "default_cursor.h"
    29 
    30 
    31 static int SDL_num_mice = 0;
    32 static int SDL_current_mouse = -1;
    33 static SDL_Mouse **SDL_mice = NULL;
    34 static int *SDL_IdIndex = NULL;
    35 static int SDL_highestId = -1;
    36 static int last_x, last_y;      /* the last reported x and y coordinates by the system cursor */
    37 
    38 
    39 /* Public functions */
    40 int
    41 SDL_MouseInit(void)
    42 {
    43     return (0);
    44 }
    45 
    46 SDL_Mouse *
    47 SDL_GetMouse(int index)
    48 {
    49     if (index < 0 || index >= SDL_num_mice) {
    50         return NULL;
    51     }
    52     return SDL_mice[index];
    53 }
    54 
    55 int
    56 SDL_SetMouseIndexId(int id, int index)
    57 {
    58     if (id < 0) {
    59         SDL_SetError("Invalid Mouse ID");
    60         return -1;
    61     }
    62     if (id > SDL_highestId) {
    63         int *indexes;
    64         indexes = (int *) SDL_realloc(SDL_IdIndex, (id + 1) * sizeof(int));
    65         if (!indexes) {
    66             SDL_OutOfMemory();
    67             return -1;
    68         }
    69         SDL_IdIndex = indexes;
    70         SDL_IdIndex[id] = index;
    71         SDL_highestId = id;
    72     } else {
    73         SDL_IdIndex[id] = index;
    74     }
    75     return 1;
    76 }
    77 
    78 int
    79 SDL_GetMouseIndexId(int id)
    80 {
    81     if (id < 0 || id > SDL_highestId) {
    82         return -1;
    83     }
    84     return SDL_IdIndex[id];
    85 }
    86 
    87 int
    88 SDL_AddMouse(const SDL_Mouse * mouse, int index, char *name, int pressure_max,
    89              int pressure_min, int ends)
    90 {
    91     SDL_Mouse **mice;
    92     int selected_mouse;
    93     int length;
    94 
    95     /* Add the mouse to the list of mice */
    96     if (index < 0 || index >= SDL_num_mice || SDL_mice[index]) {
    97         mice =
    98             (SDL_Mouse **) SDL_realloc(SDL_mice,
    99                                        (SDL_num_mice + 1) * sizeof(*mice));
   100         if (!mice) {
   101             SDL_OutOfMemory();
   102             return -1;
   103         }
   104 
   105         SDL_mice = mice;
   106         index = SDL_num_mice++;
   107     }
   108     SDL_mice[index] = (SDL_Mouse *) SDL_malloc(sizeof(*SDL_mice[index]));
   109     if (!SDL_mice[index]) {
   110         SDL_OutOfMemory();
   111         return -1;
   112     }
   113     *SDL_mice[index] = *mouse;
   114 
   115     /* we're setting the mouse properties */
   116     length = 0;
   117     length = SDL_strlen(name);
   118     SDL_mice[index]->name = SDL_malloc((length + 2) * sizeof(char));
   119     SDL_strlcpy(SDL_mice[index]->name, name, length + 1);
   120     SDL_mice[index]->pressure_max = pressure_max;
   121     SDL_mice[index]->pressure_min = pressure_min;
   122     SDL_mice[index]->cursor_shown = SDL_TRUE;
   123     selected_mouse = SDL_SelectMouse(index);
   124     SDL_mice[index]->cur_cursor = NULL;
   125     SDL_mice[index]->def_cursor =
   126         SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH,
   127                          DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
   128     SDL_SetCursor(SDL_mice[index]->def_cursor);
   129     /* we're assuming that all mice are in the computer sensing zone */
   130     SDL_mice[index]->proximity = SDL_TRUE;
   131     /* we're assuming that all mice are working in the absolute position mode
   132        thanx to that, the users that don't want to use many mice don't have to
   133        worry about anything */
   134     SDL_mice[index]->relative_mode = SDL_FALSE;
   135     SDL_mice[index]->current_end = 0;
   136     SDL_mice[index]->total_ends = ends;
   137     SDL_SelectMouse(selected_mouse);
   138 
   139     return index;
   140 }
   141 
   142 void
   143 SDL_DelMouse(int index)
   144 {
   145     SDL_Mouse *mouse = SDL_GetMouse(index);
   146 
   147     if (!mouse) {
   148         return;
   149     }
   150 
   151     mouse->def_cursor = NULL;
   152     SDL_free(mouse->name);
   153     while (mouse->cursors) {
   154         SDL_FreeCursor(mouse->cursors);
   155     }
   156 
   157     if (mouse->FreeMouse) {
   158         mouse->FreeMouse(mouse);
   159     }
   160     SDL_free(mouse);
   161 
   162     SDL_mice[index] = NULL;
   163 }
   164 
   165 void
   166 SDL_ResetMouse(int index)
   167 {
   168     SDL_Mouse *mouse = SDL_GetMouse(index);
   169 
   170     if (!mouse) {
   171         return;
   172     }
   173 
   174     /* FIXME */
   175 }
   176 
   177 void
   178 SDL_MouseQuit(void)
   179 {
   180     int i;
   181 
   182     for (i = 0; i < SDL_num_mice; ++i) {
   183         SDL_DelMouse(i);
   184     }
   185     SDL_num_mice = 0;
   186     SDL_current_mouse = -1;
   187 
   188     if (SDL_mice) {
   189         SDL_free(SDL_mice);
   190         SDL_mice = NULL;
   191     }
   192 }
   193 
   194 int
   195 SDL_GetNumMice(void)
   196 {
   197     return SDL_num_mice;
   198 }
   199 
   200 int
   201 SDL_SelectMouse(int index)
   202 {
   203     if (index >= 0 && index < SDL_num_mice) {
   204         SDL_current_mouse = index;
   205     }
   206     return SDL_current_mouse;
   207 }
   208 
   209 SDL_WindowID
   210 SDL_GetMouseFocusWindow(int index)
   211 {
   212     SDL_Mouse *mouse = SDL_GetMouse(index);
   213 
   214     if (!mouse) {
   215         return 0;
   216     }
   217     return mouse->focus;
   218 }
   219 
   220 static int SDLCALL
   221 FlushMouseMotion(void *param, SDL_Event * event)
   222 {
   223     if (event->type == SDL_MOUSEMOTION
   224         && event->motion.which == (Uint8) SDL_current_mouse) {
   225         return 0;
   226     } else {
   227         return 1;
   228     }
   229 }
   230 
   231 int
   232 SDL_SetRelativeMouseMode(int index, SDL_bool enabled)
   233 {
   234     SDL_Mouse *mouse = SDL_GetMouse(index);
   235 
   236     if (!mouse) {
   237         return -1;
   238     }
   239 
   240     /* Flush pending mouse motion */
   241     mouse->flush_motion = SDL_TRUE;
   242     SDL_PumpEvents();
   243     mouse->flush_motion = SDL_FALSE;
   244     SDL_FilterEvents(FlushMouseMotion, mouse);
   245 
   246     /* Set the relative mode */
   247     mouse->relative_mode = enabled;
   248 
   249     /* Update cursor visibility */
   250     SDL_SetCursor(NULL);
   251 
   252     if (!enabled) {
   253         /* Restore the expected mouse position */
   254         SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   255     }
   256     return 0;
   257 }
   258 
   259 SDL_bool
   260 SDL_GetRelativeMouseMode(int index)
   261 {
   262     SDL_Mouse *mouse = SDL_GetMouse(index);
   263 
   264     if (!mouse) {
   265         return SDL_FALSE;
   266     }
   267     return mouse->relative_mode;
   268 }
   269 
   270 Uint8
   271 SDL_GetMouseState(int index, int *x, int *y)
   272 {
   273     SDL_Mouse *mouse = SDL_GetMouse(index);
   274 
   275     if (!mouse) {
   276         if (x) {
   277             *x = 0;
   278         }
   279         if (y) {
   280             *y = 0;
   281         }
   282         return 0;
   283     }
   284 
   285     if (x) {
   286         *x = mouse->x;
   287     }
   288     if (y) {
   289         *y = mouse->y;
   290     }
   291     return mouse->buttonstate;
   292 }
   293 
   294 Uint8
   295 SDL_GetRelativeMouseState(int index, int *x, int *y)
   296 {
   297     SDL_Mouse *mouse = SDL_GetMouse(index);
   298 
   299     if (!mouse) {
   300         if (x) {
   301             *x = 0;
   302         }
   303         if (y) {
   304             *y = 0;
   305         }
   306         return 0;
   307     }
   308 
   309     if (x) {
   310         *x = mouse->xdelta;
   311     }
   312     if (y) {
   313         *y = mouse->ydelta;
   314     }
   315     mouse->xdelta = 0;
   316     mouse->ydelta = 0;
   317     return mouse->buttonstate;
   318 }
   319 
   320 void
   321 SDL_SetMouseFocus(int id, SDL_WindowID windowID)
   322 {
   323     int index = SDL_GetMouseIndexId(id);
   324     SDL_Mouse *mouse = SDL_GetMouse(index);
   325     int i;
   326     SDL_bool focus;
   327 
   328     if (!mouse || (mouse->focus == windowID)) {
   329         return;
   330     }
   331 
   332     /* See if the current window has lost focus */
   333     if (mouse->focus) {
   334         focus = SDL_FALSE;
   335         for (i = 0; i < SDL_num_mice; ++i) {
   336             SDL_Mouse *check;
   337             if (i != index) {
   338                 check = SDL_GetMouse(i);
   339                 if (check && check->focus == mouse->focus) {
   340                     focus = SDL_TRUE;
   341                     break;
   342                 }
   343             }
   344         }
   345         if (!focus) {
   346             SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   347         }
   348     }
   349 
   350     mouse->focus = windowID;
   351 
   352     if (mouse->focus) {
   353         focus = SDL_FALSE;
   354         for (i = 0; i < SDL_num_mice; ++i) {
   355             SDL_Mouse *check;
   356             if (i != index) {
   357                 check = SDL_GetMouse(i);
   358                 if (check && check->focus == mouse->focus) {
   359                     focus = SDL_TRUE;
   360                     break;
   361                 }
   362             }
   363         }
   364         if (!focus) {
   365             SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   366         }
   367         SDL_GetWindowSize(windowID, &mouse->x_max, &mouse->y_max);
   368     }
   369 }
   370 
   371 void
   372 SDL_SetMouseFocusSize(SDL_WindowID windowID, int w, int h)
   373 {
   374     int i;
   375 
   376     for (i = 0; i < SDL_num_mice; ++i) {
   377         SDL_Mouse *mouse = SDL_GetMouse(i);
   378         if (mouse && mouse->focus == windowID) {
   379             mouse->x_max = w;
   380             mouse->y_max = h;
   381         }
   382     }
   383 }
   384 
   385 int
   386 SDL_SendProximity(int id, int x, int y, int type)
   387 {
   388     int index = SDL_GetMouseIndexId(id);
   389     SDL_Mouse *mouse = SDL_GetMouse(index);
   390     int posted = 0;
   391 
   392     if (!mouse) {
   393         return 0;
   394     }
   395 
   396     last_x = x;
   397     last_y = y;
   398     if (SDL_ProcessEvents[type] == SDL_ENABLE) {
   399         SDL_Event event;
   400         event.proximity.which = (Uint8) index;
   401         event.proximity.x = x;
   402         event.proximity.y = y;
   403         event.proximity.cursor = mouse->current_end;
   404         event.proximity.type = type;
   405         posted = (SDL_PushEvent(&event) > 0);
   406         if (type == SDL_PROXIMITYIN) {
   407             mouse->proximity = SDL_TRUE;
   408         } else {
   409             mouse->proximity = SDL_FALSE;
   410         }
   411     }
   412     return posted;
   413 }
   414 
   415 int
   416 SDL_SendMouseMotion(int id, int relative, int x, int y, int pressure)
   417 {
   418     int index = SDL_GetMouseIndexId(id);
   419     SDL_Mouse *mouse = SDL_GetMouse(index);
   420     int posted;
   421     int xrel;
   422     int yrel;
   423 
   424     if (!mouse || mouse->flush_motion) {
   425         return 0;
   426     }
   427 
   428     /* if the mouse is out of proximity we don't to want to have any motion from it */
   429     if (mouse->proximity == SDL_FALSE) {
   430         last_x = x;
   431         last_y = y;
   432         return 0;
   433     }
   434 
   435     /* the relative motion is calculated regarding the system cursor last position */
   436     if (relative) {
   437         xrel = x;
   438         yrel = y;
   439         x = (last_x + x);
   440         y = (last_y + y);
   441     } else {
   442         xrel = x - last_x;
   443         yrel = y - last_y;
   444     }
   445 
   446     /* Drop events that don't change state */
   447     if (!xrel && !yrel) {
   448 #if 0
   449         printf("Mouse event didn't change state - dropped!\n");
   450 #endif
   451         return 0;
   452     }
   453 
   454     /* Update internal mouse coordinates */
   455     if (mouse->relative_mode == SDL_FALSE) {
   456         mouse->x = x;
   457         mouse->y = y;
   458     } else {
   459         /* while using the relative mode and many windows, we have to be
   460            sure that the pointers find themselves inside the windows */
   461         if (mouse->x + xrel > mouse->x_max) {
   462             mouse->x = mouse->x_max;
   463         } else if (mouse->x + xrel < 0) {
   464             mouse->x = 0;
   465         } else {
   466             mouse->x += xrel;
   467         }
   468         if (mouse->y + yrel > mouse->y_max) {
   469             mouse->y = mouse->y_max;
   470         } else if (mouse->y + yrel < 0) {
   471             mouse->y = 0;
   472         } else {
   473             mouse->y += yrel;
   474         }
   475     }
   476     mouse->xdelta += xrel;
   477     mouse->ydelta += yrel;
   478     mouse->pressure = pressure;
   479 
   480     /* Move the mouse cursor, if needed */
   481     if (mouse->cursor_shown && !mouse->relative_mode &&
   482         mouse->MoveCursor && mouse->cur_cursor) {
   483         mouse->MoveCursor(mouse->cur_cursor);
   484     }
   485 
   486     /* Post the event, if desired */
   487     posted = 0;
   488     if (SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE &&
   489         mouse->proximity == SDL_TRUE) {
   490         SDL_Event event;
   491         event.motion.type = SDL_MOUSEMOTION;
   492         event.motion.which = (Uint8) index;
   493         event.motion.state = mouse->buttonstate;
   494         event.motion.x = mouse->x;
   495         event.motion.y = mouse->y;
   496         event.motion.pressure = mouse->pressure;
   497         event.motion.xrel = xrel;
   498         event.motion.yrel = yrel;
   499         event.motion.windowID = mouse->focus;
   500         event.motion.pressure_max = mouse->pressure_max;
   501         event.motion.pressure_min = mouse->pressure_min;
   502         event.motion.cursor = mouse->current_end;
   503         posted = (SDL_PushEvent(&event) > 0);
   504     }
   505     last_x = x;
   506     last_y = y;
   507     return posted;
   508 }
   509 
   510 int
   511 SDL_SendMouseButton(int id, Uint8 state, Uint8 button)
   512 {
   513     int index = SDL_GetMouseIndexId(id);
   514     SDL_Mouse *mouse = SDL_GetMouse(index);
   515     int posted;
   516     Uint8 type;
   517 
   518     if (!mouse) {
   519         return 0;
   520     }
   521 
   522     /* Figure out which event to perform */
   523     switch (state) {
   524     case SDL_PRESSED:
   525         if (mouse->buttonstate & SDL_BUTTON(button)) {
   526             /* Ignore this event, no state change */
   527             return 0;
   528         }
   529         type = SDL_MOUSEBUTTONDOWN;
   530         mouse->buttonstate |= SDL_BUTTON(button);
   531         break;
   532     case SDL_RELEASED:
   533         if (!(mouse->buttonstate & SDL_BUTTON(button))) {
   534             /* Ignore this event, no state change */
   535             return 0;
   536         }
   537         type = SDL_MOUSEBUTTONUP;
   538         mouse->buttonstate &= ~SDL_BUTTON(button);
   539         break;
   540     default:
   541         /* Invalid state -- bail */
   542         return 0;
   543     }
   544 
   545     /* Post the event, if desired */
   546     posted = 0;
   547     if (SDL_ProcessEvents[type] == SDL_ENABLE) {
   548         SDL_Event event;
   549         event.type = type;
   550         event.button.which = (Uint8) index;
   551         event.button.state = state;
   552         event.button.button = button;
   553         event.button.x = mouse->x;
   554         event.button.y = mouse->y;
   555         event.button.windowID = mouse->focus;
   556         posted = (SDL_PushEvent(&event) > 0);
   557     }
   558     return posted;
   559 }
   560 
   561 int
   562 SDL_SendMouseWheel(int index, int x, int y)
   563 {
   564     SDL_Mouse *mouse = SDL_GetMouse(index);
   565     int posted;
   566 
   567     if (!mouse || (!x && !y)) {
   568         return 0;
   569     }
   570 
   571     /* Post the event, if desired */
   572     posted = 0;
   573     if (SDL_ProcessEvents[SDL_MOUSEWHEEL] == SDL_ENABLE) {
   574         SDL_Event event;
   575         event.type = SDL_MOUSEWHEEL;
   576         event.wheel.which = (Uint8) index;
   577         event.wheel.x = x;
   578         event.wheel.y = y;
   579         event.wheel.windowID = mouse->focus;
   580         posted = (SDL_PushEvent(&event) > 0);
   581     }
   582     return posted;
   583 }
   584 
   585 void
   586 SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y)
   587 {
   588     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   589 
   590     if (!mouse) {
   591         return;
   592     }
   593 
   594     if (mouse->WarpMouse) {
   595         mouse->WarpMouse(mouse, windowID, x, y);
   596     } else {
   597         SDL_SetMouseFocus(SDL_current_mouse, windowID);
   598         SDL_SendMouseMotion(SDL_current_mouse, 0, x, y, 0);
   599     }
   600 }
   601 
   602 SDL_Cursor *
   603 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   604                  int w, int h, int hot_x, int hot_y)
   605 {
   606     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   607     SDL_Surface *surface;
   608     SDL_Cursor *cursor;
   609     int x, y;
   610     Uint32 *pixel;
   611     Uint8 datab, maskb;
   612     const Uint32 black = 0xFF000000;
   613     const Uint32 white = 0xFFFFFFFF;
   614     const Uint32 transparent = 0x00000000;
   615 
   616     if (!mouse) {
   617         SDL_SetError("No mice are initialized");
   618         return NULL;
   619     }
   620 
   621     if (!mouse->CreateCursor) {
   622         SDL_SetError("Current mouse doesn't have cursor support");
   623         return NULL;
   624     }
   625 
   626     /* Sanity check the hot spot */
   627     if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) {
   628         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   629         return NULL;
   630     }
   631 
   632     /* Make sure the width is a multiple of 8 */
   633     w = ((w + 7) & ~7);
   634 
   635     /* Create the surface from a bitmap */
   636     surface =
   637         SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
   638                              0xFF000000);
   639     if (!surface) {
   640         return NULL;
   641     }
   642     for (y = 0; y < h; ++y) {
   643         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   644         for (x = 0; x < w; ++x) {
   645             if ((x % 8) == 0) {
   646                 datab = *data++;
   647                 maskb = *mask++;
   648             }
   649             if (maskb & 0x80) {
   650                 *pixel++ = (datab & 0x80) ? black : white;
   651             } else {
   652                 *pixel++ = (datab & 0x80) ? black : transparent;
   653             }
   654             datab <<= 1;
   655             maskb <<= 1;
   656         }
   657     }
   658 
   659     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   660     if (cursor) {
   661         cursor->mouse = mouse;
   662         cursor->next = mouse->cursors;
   663         mouse->cursors = cursor;
   664     }
   665 
   666     SDL_FreeSurface(surface);
   667 
   668     return cursor;
   669 }
   670 
   671 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   672    if this is desired for any reason.  This is used when setting
   673    the video mode and when the SDL window gains the mouse focus.
   674  */
   675 void
   676 SDL_SetCursor(SDL_Cursor * cursor)
   677 {
   678     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   679 
   680     if (!mouse) {
   681         SDL_SetError("No mice are initialized");
   682         return;
   683     }
   684 
   685     /* Set the new cursor */
   686     if (cursor) {
   687         /* Make sure the cursor is still valid for this mouse */
   688         SDL_Cursor *found;
   689         for (found = mouse->cursors; found; found = found->next) {
   690             if (found == cursor) {
   691                 break;
   692             }
   693         }
   694         if (!found) {
   695             SDL_SetError("Cursor not associated with the current mouse");
   696             return;
   697         }
   698         mouse->cur_cursor = cursor;
   699     } else {
   700         cursor = mouse->cur_cursor;
   701     }
   702 
   703     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   704         if (mouse->ShowCursor) {
   705             mouse->ShowCursor(cursor);
   706         }
   707     } else {
   708         if (mouse->ShowCursor) {
   709             mouse->ShowCursor(NULL);
   710         }
   711     }
   712 }
   713 
   714 SDL_Cursor *
   715 SDL_GetCursor(void)
   716 {
   717     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   718 
   719     if (!mouse) {
   720         return NULL;
   721     }
   722     return mouse->cur_cursor;
   723 }
   724 
   725 void
   726 SDL_FreeCursor(SDL_Cursor * cursor)
   727 {
   728     SDL_Mouse *mouse;
   729     SDL_Cursor *curr, *prev;
   730 
   731     if (!cursor) {
   732         return;
   733     }
   734     mouse = cursor->mouse;
   735 
   736     if (cursor == mouse->def_cursor) {
   737         return;
   738     }
   739     if (cursor == mouse->cur_cursor) {
   740         SDL_SetCursor(mouse->def_cursor);
   741     }
   742 
   743     for (prev = NULL, curr = mouse->cursors; curr;
   744          prev = curr, curr = curr->next) {
   745         if (curr == cursor) {
   746             if (prev) {
   747                 prev->next = curr->next;
   748             } else {
   749                 mouse->cursors = curr->next;
   750             }
   751 
   752             if (mouse->FreeCursor) {
   753                 mouse->FreeCursor(curr);
   754             }
   755             return;
   756         }
   757     }
   758 }
   759 
   760 int
   761 SDL_ShowCursor(int toggle)
   762 {
   763     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   764     SDL_bool shown;
   765 
   766     if (!mouse) {
   767         return 0;
   768     }
   769 
   770     shown = mouse->cursor_shown;
   771     if (toggle >= 0) {
   772         if (toggle) {
   773             mouse->cursor_shown = SDL_TRUE;
   774         } else {
   775             mouse->cursor_shown = SDL_FALSE;
   776         }
   777         if (mouse->cursor_shown != shown) {
   778             SDL_SetCursor(NULL);
   779         }
   780     }
   781     return shown;
   782 }
   783 
   784 char *
   785 SDL_GetMouseName(int index)
   786 {
   787     SDL_Mouse *mouse = SDL_GetMouse(index);
   788     if (!mouse) {
   789         return NULL;
   790     }
   791     return mouse->name;
   792 }
   793 
   794 void
   795 SDL_ChangeEnd(int id, int end)
   796 {
   797     int index = SDL_GetMouseIndexId(id);
   798     SDL_Mouse *mouse = SDL_GetMouse(index);
   799 
   800     if (mouse) {
   801         mouse->current_end = end;
   802     }
   803 }
   804 
   805 int
   806 SDL_GetCursorsNumber(int index)
   807 {
   808     SDL_Mouse *mouse = SDL_GetMouse(index);
   809 
   810     if (!mouse) {
   811         return -1;
   812     }
   813     return mouse->total_ends;
   814 }
   815 
   816 int
   817 SDL_GetCurrentCursor(int index)
   818 {
   819     SDL_Mouse *mouse = SDL_GetMouse(index);
   820 
   821     if (!mouse) {
   822         return -1;
   823     }
   824     return mouse->current_end;
   825 }
   826 
   827 /* vi: set ts=4 sw=4 expandtab: */