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