src/events/SDL_mouse.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 25 Jun 2014 16:16:55 -0400
changeset 8952 4bb098814ec4
parent 8945 04248c700ada
child 8953 dc80dc0bd22e
permissions -rw-r--r--
Changed SDL_GetAbsoluteMouseState() to SDL_GetGlobalMouseState().

This matches naming conventions in the main repository, between
SDL_GetRelativeMouseState() and 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     SDL_bool inWindow = SDL_TRUE;
   144 
   145     if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0) {
   146         int w, h;
   147         SDL_GetWindowSize(window, &w, &h);
   148         if (x < 0 || y < 0 || x >= w || y >= h) {
   149             inWindow = SDL_FALSE;
   150         }
   151     }
   152 
   153     if (!inWindow) {
   154         if (window == mouse->focus) {
   155 #ifdef DEBUG_MOUSE
   156             printf("Mouse left window, synthesizing move & focus lost event\n");
   157 #endif
   158             SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
   159             SDL_SetMouseFocus(NULL);
   160         }
   161         return SDL_FALSE;
   162     }
   163 
   164     if (window != mouse->focus) {
   165 #ifdef DEBUG_MOUSE
   166          printf("Mouse entered window, synthesizing focus gain & move event\n");
   167 #endif
   168          SDL_SetMouseFocus(window);
   169          SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
   170     }
   171     return SDL_TRUE;
   172 }
   173 
   174 int
   175 SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
   176 {
   177     if (window && !relative) {
   178         SDL_Mouse *mouse = SDL_GetMouse();
   179         if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
   180             return 0;
   181         }
   182     }
   183 
   184     return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
   185 }
   186 
   187 static int
   188 SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
   189 {
   190     SDL_Mouse *mouse = SDL_GetMouse();
   191     int posted;
   192     int xrel;
   193     int yrel;
   194 
   195     if (mouse->relative_mode_warp) {
   196         int center_x = 0, center_y = 0;
   197         SDL_GetWindowSize(window, &center_x, &center_y);
   198         center_x /= 2;
   199         center_y /= 2;
   200         if (x == center_x && y == center_y) {
   201             mouse->last_x = center_x;
   202             mouse->last_y = center_y;
   203             return 0;
   204         }
   205         SDL_WarpMouseInWindow(window, center_x, center_y);
   206     }
   207 
   208     if (relative) {
   209         xrel = x;
   210         yrel = y;
   211         x = (mouse->last_x + xrel);
   212         y = (mouse->last_y + yrel);
   213     } else {
   214         xrel = x - mouse->last_x;
   215         yrel = y - mouse->last_y;
   216     }
   217 
   218     /* Drop events that don't change state */
   219     if (!xrel && !yrel) {
   220 #ifdef DEBUG_MOUSE
   221         printf("Mouse event didn't change state - dropped!\n");
   222 #endif
   223         return 0;
   224     }
   225 
   226     /* Update internal mouse coordinates */
   227     if (!mouse->relative_mode) {
   228         mouse->x = x;
   229         mouse->y = y;
   230     } else {
   231         mouse->x += xrel;
   232         mouse->y += yrel;
   233     }
   234 
   235     /* make sure that the pointers find themselves inside the windows,
   236        unless we have the mouse captured. */
   237     if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0) {
   238         int x_max = 0, y_max = 0;
   239 
   240         // !!! FIXME: shouldn't this be (window) instead of (mouse->focus)?
   241         SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
   242         --x_max;
   243         --y_max;
   244 
   245         if (mouse->x > x_max) {
   246             mouse->x = x_max;
   247         }
   248         if (mouse->x < 0) {
   249             mouse->x = 0;
   250         }
   251 
   252         if (mouse->y > y_max) {
   253             mouse->y = y_max;
   254         }
   255         if (mouse->y < 0) {
   256             mouse->y = 0;
   257         }
   258     }
   259 
   260     mouse->xdelta += xrel;
   261     mouse->ydelta += yrel;
   262 
   263     /* Move the mouse cursor, if needed */
   264     if (mouse->cursor_shown && !mouse->relative_mode &&
   265         mouse->MoveCursor && mouse->cur_cursor) {
   266         mouse->MoveCursor(mouse->cur_cursor);
   267     }
   268 
   269     /* Post the event, if desired */
   270     posted = 0;
   271     if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
   272         SDL_Event event;
   273         event.motion.type = SDL_MOUSEMOTION;
   274         event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
   275         event.motion.which = mouseID;
   276         event.motion.state = mouse->buttonstate;
   277         event.motion.x = mouse->x;
   278         event.motion.y = mouse->y;
   279         event.motion.xrel = xrel;
   280         event.motion.yrel = yrel;
   281         posted = (SDL_PushEvent(&event) > 0);
   282     }
   283     /* Use unclamped values if we're getting events outside the window */
   284     mouse->last_x = x;
   285     mouse->last_y = y;
   286     return posted;
   287 }
   288 
   289 static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
   290 {
   291     if (button >= mouse->num_clickstates) {
   292         int i, count = button + 1;
   293         mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
   294         if (!mouse->clickstate) {
   295             return NULL;
   296         }
   297 
   298         for (i = mouse->num_clickstates; i < count; ++i) {
   299             SDL_zero(mouse->clickstate[i]);
   300         }
   301         mouse->num_clickstates = count;
   302     }
   303     return &mouse->clickstate[button];
   304 }
   305 
   306 int
   307 SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
   308 {
   309     SDL_Mouse *mouse = SDL_GetMouse();
   310     int posted;
   311     Uint32 type;
   312     Uint32 buttonstate = mouse->buttonstate;
   313     SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
   314     Uint8 click_count;
   315 
   316     /* Figure out which event to perform */
   317     switch (state) {
   318     case SDL_PRESSED:
   319         type = SDL_MOUSEBUTTONDOWN;
   320         buttonstate |= SDL_BUTTON(button);
   321         break;
   322     case SDL_RELEASED:
   323         type = SDL_MOUSEBUTTONUP;
   324         buttonstate &= ~SDL_BUTTON(button);
   325         break;
   326     default:
   327         /* Invalid state -- bail */
   328         return 0;
   329     }
   330 
   331     /* We do this after calculating buttonstate so button presses gain focus */
   332     if (window && state == SDL_PRESSED) {
   333         SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   334     }
   335 
   336     if (buttonstate == mouse->buttonstate) {
   337         /* Ignore this event, no state change */
   338         return 0;
   339     }
   340     mouse->buttonstate = buttonstate;
   341 
   342     if (clickstate) {
   343         if (state == SDL_PRESSED) {
   344             Uint32 now = SDL_GetTicks();
   345 
   346             if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
   347                 SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
   348                 SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
   349                 clickstate->click_count = 0;
   350             }
   351             clickstate->last_timestamp = now;
   352             clickstate->last_x = mouse->x;
   353             clickstate->last_y = mouse->y;
   354             if (clickstate->click_count < 255) {
   355                 ++clickstate->click_count;
   356             }
   357         }
   358         click_count = clickstate->click_count;
   359     } else {
   360         click_count = 1;
   361     }
   362 
   363     /* Post the event, if desired */
   364     posted = 0;
   365     if (SDL_GetEventState(type) == SDL_ENABLE) {
   366         SDL_Event event;
   367         event.type = type;
   368         event.button.windowID = mouse->focus ? mouse->focus->id : 0;
   369         event.button.which = mouseID;
   370         event.button.state = state;
   371         event.button.button = button;
   372         event.button.clicks = click_count;
   373         event.button.x = mouse->x;
   374         event.button.y = mouse->y;
   375         posted = (SDL_PushEvent(&event) > 0);
   376     }
   377 
   378     /* We do this after dispatching event so button releases can lose focus */
   379     if (window && state == SDL_RELEASED) {
   380         SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   381     }
   382 
   383     return posted;
   384 }
   385 
   386 int
   387 SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y)
   388 {
   389     SDL_Mouse *mouse = SDL_GetMouse();
   390     int posted;
   391 
   392     if (window) {
   393         SDL_SetMouseFocus(window);
   394     }
   395 
   396     if (!x && !y) {
   397         return 0;
   398     }
   399 
   400     /* Post the event, if desired */
   401     posted = 0;
   402     if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
   403         SDL_Event event;
   404         event.type = SDL_MOUSEWHEEL;
   405         event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
   406         event.wheel.which = mouseID;
   407         event.wheel.x = x;
   408         event.wheel.y = y;
   409         posted = (SDL_PushEvent(&event) > 0);
   410     }
   411     return posted;
   412 }
   413 
   414 void
   415 SDL_MouseQuit(void)
   416 {
   417     SDL_Cursor *cursor, *next;
   418     SDL_Mouse *mouse = SDL_GetMouse();
   419 
   420     SDL_CaptureMouse(SDL_FALSE);
   421     SDL_SetRelativeMouseMode(SDL_FALSE);
   422     SDL_ShowCursor(1);
   423 
   424     cursor = mouse->cursors;
   425     while (cursor) {
   426         next = cursor->next;
   427         SDL_FreeCursor(cursor);
   428         cursor = next;
   429     }
   430 
   431     if (mouse->def_cursor && mouse->FreeCursor) {
   432         mouse->FreeCursor(mouse->def_cursor);
   433     }
   434 
   435     if (mouse->clickstate) {
   436         SDL_free(mouse->clickstate);
   437     }
   438 
   439     SDL_zerop(mouse);
   440 }
   441 
   442 Uint32
   443 SDL_GetMouseState(int *x, int *y)
   444 {
   445     SDL_Mouse *mouse = SDL_GetMouse();
   446 
   447     if (x) {
   448         *x = mouse->x;
   449     }
   450     if (y) {
   451         *y = mouse->y;
   452     }
   453     return mouse->buttonstate;
   454 }
   455 
   456 Uint32
   457 SDL_GetRelativeMouseState(int *x, int *y)
   458 {
   459     SDL_Mouse *mouse = SDL_GetMouse();
   460 
   461     if (x) {
   462         *x = mouse->xdelta;
   463     }
   464     if (y) {
   465         *y = mouse->ydelta;
   466     }
   467     mouse->xdelta = 0;
   468     mouse->ydelta = 0;
   469     return mouse->buttonstate;
   470 }
   471 
   472 Uint32
   473 SDL_GetGlobalMouseState(int *x, int *y)
   474 {
   475     SDL_Mouse *mouse = SDL_GetMouse();
   476     int tmpx, tmpy;
   477 
   478     /* make sure these are never NULL for the backend implementations... */
   479     if (!x) {
   480         x = &tmpx;
   481     }
   482     if (!y) {
   483         y = &tmpy;
   484     }
   485 
   486     *x = *y = 0;
   487 
   488     if (!mouse->GetGlobalMouseState) {
   489         SDL_assert(0 && "This should really be implemented for every target.");
   490         return 0;
   491     }
   492 
   493     return mouse->GetGlobalMouseState(x, y);
   494 }
   495 
   496 void
   497 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
   498 {
   499     SDL_Mouse *mouse = SDL_GetMouse();
   500 
   501     if ( window == NULL ) {
   502         window = mouse->focus;
   503     }
   504 
   505     if ( window == NULL ) {
   506         return;
   507     }
   508 
   509     if (mouse->WarpMouse) {
   510         mouse->WarpMouse(window, x, y);
   511     } else {
   512         SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
   513     }
   514 }
   515 
   516 static SDL_bool
   517 ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
   518 {
   519     const char *hint;
   520 
   521     if (!mouse->SetRelativeMouseMode) {
   522         return SDL_TRUE;
   523     }
   524 
   525     hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
   526     if (hint) {
   527         if (*hint == '0') {
   528             return SDL_FALSE;
   529         } else {
   530             return SDL_TRUE;
   531         }
   532     }
   533     return SDL_FALSE;
   534 }
   535 
   536 int
   537 SDL_SetRelativeMouseMode(SDL_bool enabled)
   538 {
   539     SDL_Mouse *mouse = SDL_GetMouse();
   540     SDL_Window *focusWindow = SDL_GetKeyboardFocus();
   541 
   542     if (enabled == mouse->relative_mode) {
   543         return 0;
   544     }
   545 
   546     if (enabled && focusWindow) {
   547         /* Center it in the focused window to prevent clicks from going through
   548          * to background windows.
   549          */
   550         SDL_SetMouseFocus(focusWindow);
   551         SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
   552     }
   553 
   554     /* Set the relative mode */
   555     if (!enabled && mouse->relative_mode_warp) {
   556         mouse->relative_mode_warp = SDL_FALSE;
   557     } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
   558         mouse->relative_mode_warp = SDL_TRUE;
   559     } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
   560         if (enabled) {
   561             /* Fall back to warp mode if native relative mode failed */
   562             mouse->relative_mode_warp = SDL_TRUE;
   563         }
   564     }
   565     mouse->relative_mode = enabled;
   566 
   567     if (mouse->focus) {
   568         SDL_UpdateWindowGrab(mouse->focus);
   569 
   570         /* Put the cursor back to where the application expects it */
   571         if (!enabled) {
   572             SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   573         }
   574     }
   575 
   576     /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
   577     SDL_FlushEvent(SDL_MOUSEMOTION);
   578 
   579     /* Update cursor visibility */
   580     SDL_SetCursor(NULL);
   581 
   582     return 0;
   583 }
   584 
   585 SDL_bool
   586 SDL_GetRelativeMouseMode()
   587 {
   588     SDL_Mouse *mouse = SDL_GetMouse();
   589 
   590     return mouse->relative_mode;
   591 }
   592 
   593 int
   594 SDL_CaptureMouse(SDL_bool enabled)
   595 {
   596     SDL_Mouse *mouse = SDL_GetMouse();
   597     SDL_Window *focusWindow;
   598     SDL_bool isCaptured;
   599 
   600     if (!mouse->CaptureMouse) {
   601         return SDL_Unsupported();
   602     }
   603 
   604     focusWindow = SDL_GetKeyboardFocus();
   605 
   606     isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
   607     if (isCaptured == enabled) {
   608         return 0;  /* already done! */
   609     }
   610 
   611     if (enabled) {
   612         if (!focusWindow) {
   613             return SDL_SetError("No window has focus");
   614         } else if (mouse->CaptureMouse(focusWindow) == -1) {
   615             return -1;  /* CaptureMouse() should call SetError */
   616         }
   617         focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
   618     } else {
   619         if (mouse->CaptureMouse(NULL) == -1) {
   620             return -1;  /* CaptureMouse() should call SetError */
   621         }
   622         focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
   623     }
   624 
   625     return 0;
   626 }
   627 
   628 
   629 SDL_Cursor *
   630 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   631                  int w, int h, int hot_x, int hot_y)
   632 {
   633     SDL_Surface *surface;
   634     SDL_Cursor *cursor;
   635     int x, y;
   636     Uint32 *pixel;
   637     Uint8 datab = 0, maskb = 0;
   638     const Uint32 black = 0xFF000000;
   639     const Uint32 white = 0xFFFFFFFF;
   640     const Uint32 transparent = 0x00000000;
   641 
   642     /* Make sure the width is a multiple of 8 */
   643     w = ((w + 7) & ~7);
   644 
   645     /* Create the surface from a bitmap */
   646     surface = SDL_CreateRGBSurface(0, w, h, 32,
   647                                    0x00FF0000,
   648                                    0x0000FF00,
   649                                    0x000000FF,
   650                                    0xFF000000);
   651     if (!surface) {
   652         return NULL;
   653     }
   654     for (y = 0; y < h; ++y) {
   655         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   656         for (x = 0; x < w; ++x) {
   657             if ((x % 8) == 0) {
   658                 datab = *data++;
   659                 maskb = *mask++;
   660             }
   661             if (maskb & 0x80) {
   662                 *pixel++ = (datab & 0x80) ? black : white;
   663             } else {
   664                 *pixel++ = (datab & 0x80) ? black : transparent;
   665             }
   666             datab <<= 1;
   667             maskb <<= 1;
   668         }
   669     }
   670 
   671     cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
   672 
   673     SDL_FreeSurface(surface);
   674 
   675     return cursor;
   676 }
   677 
   678 SDL_Cursor *
   679 SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
   680 {
   681     SDL_Mouse *mouse = SDL_GetMouse();
   682     SDL_Surface *temp = NULL;
   683     SDL_Cursor *cursor;
   684 
   685     if (!surface) {
   686         SDL_SetError("Passed NULL cursor surface");
   687         return NULL;
   688     }
   689 
   690     if (!mouse->CreateCursor) {
   691         SDL_SetError("Cursors are not currently supported");
   692         return NULL;
   693     }
   694 
   695     /* Sanity check the hot spot */
   696     if ((hot_x < 0) || (hot_y < 0) ||
   697         (hot_x >= surface->w) || (hot_y >= surface->h)) {
   698         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   699         return NULL;
   700     }
   701 
   702     if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
   703         temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
   704         if (!temp) {
   705             return NULL;
   706         }
   707         surface = temp;
   708     }
   709 
   710     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   711     if (cursor) {
   712         cursor->next = mouse->cursors;
   713         mouse->cursors = cursor;
   714     }
   715 
   716     SDL_FreeSurface(temp);
   717 
   718     return cursor;
   719 }
   720 
   721 SDL_Cursor *
   722 SDL_CreateSystemCursor(SDL_SystemCursor id)
   723 {
   724     SDL_Mouse *mouse = SDL_GetMouse();
   725     SDL_Cursor *cursor;
   726 
   727     if (!mouse->CreateSystemCursor) {
   728         SDL_SetError("CreateSystemCursor is not currently supported");
   729         return NULL;
   730     }
   731 
   732     cursor = mouse->CreateSystemCursor(id);
   733     if (cursor) {
   734         cursor->next = mouse->cursors;
   735         mouse->cursors = cursor;
   736     }
   737 
   738     return cursor;
   739 }
   740 
   741 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   742    if this is desired for any reason.  This is used when setting
   743    the video mode and when the SDL window gains the mouse focus.
   744  */
   745 void
   746 SDL_SetCursor(SDL_Cursor * cursor)
   747 {
   748     SDL_Mouse *mouse = SDL_GetMouse();
   749 
   750     /* Set the new cursor */
   751     if (cursor) {
   752         /* Make sure the cursor is still valid for this mouse */
   753         if (cursor != mouse->def_cursor) {
   754             SDL_Cursor *found;
   755             for (found = mouse->cursors; found; found = found->next) {
   756                 if (found == cursor) {
   757                     break;
   758                 }
   759             }
   760             if (!found) {
   761                 SDL_SetError("Cursor not associated with the current mouse");
   762                 return;
   763             }
   764         }
   765         mouse->cur_cursor = cursor;
   766     } else {
   767         if (mouse->focus) {
   768             cursor = mouse->cur_cursor;
   769         } else {
   770             cursor = mouse->def_cursor;
   771         }
   772     }
   773 
   774     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   775         if (mouse->ShowCursor) {
   776             mouse->ShowCursor(cursor);
   777         }
   778     } else {
   779         if (mouse->ShowCursor) {
   780             mouse->ShowCursor(NULL);
   781         }
   782     }
   783 }
   784 
   785 SDL_Cursor *
   786 SDL_GetCursor(void)
   787 {
   788     SDL_Mouse *mouse = SDL_GetMouse();
   789 
   790     if (!mouse) {
   791         return NULL;
   792     }
   793     return mouse->cur_cursor;
   794 }
   795 
   796 SDL_Cursor *
   797 SDL_GetDefaultCursor(void)
   798 {
   799     SDL_Mouse *mouse = SDL_GetMouse();
   800 
   801     if (!mouse) {
   802         return NULL;
   803     }
   804     return mouse->def_cursor;
   805 }
   806 
   807 void
   808 SDL_FreeCursor(SDL_Cursor * cursor)
   809 {
   810     SDL_Mouse *mouse = SDL_GetMouse();
   811     SDL_Cursor *curr, *prev;
   812 
   813     if (!cursor) {
   814         return;
   815     }
   816 
   817     if (cursor == mouse->def_cursor) {
   818         return;
   819     }
   820     if (cursor == mouse->cur_cursor) {
   821         SDL_SetCursor(mouse->def_cursor);
   822     }
   823 
   824     for (prev = NULL, curr = mouse->cursors; curr;
   825          prev = curr, curr = curr->next) {
   826         if (curr == cursor) {
   827             if (prev) {
   828                 prev->next = curr->next;
   829             } else {
   830                 mouse->cursors = curr->next;
   831             }
   832 
   833             if (mouse->FreeCursor) {
   834                 mouse->FreeCursor(curr);
   835             }
   836             return;
   837         }
   838     }
   839 }
   840 
   841 int
   842 SDL_ShowCursor(int toggle)
   843 {
   844     SDL_Mouse *mouse = SDL_GetMouse();
   845     SDL_bool shown;
   846 
   847     if (!mouse) {
   848         return 0;
   849     }
   850 
   851     shown = mouse->cursor_shown;
   852     if (toggle >= 0) {
   853         if (toggle) {
   854             mouse->cursor_shown = SDL_TRUE;
   855         } else {
   856             mouse->cursor_shown = SDL_FALSE;
   857         }
   858         if (mouse->cursor_shown != shown) {
   859             SDL_SetCursor(NULL);
   860         }
   861     }
   862     return shown;
   863 }
   864 
   865 /* vi: set ts=4 sw=4 expandtab: */