src/events/SDL_mouse.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 17 Jul 2015 21:03:58 -0400
changeset 9807 57b448735f48
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rw-r--r--
SDL_WarpMouseGlobal() should return non-void.

There are platforms it isn't implemented on (and currently can't be
implemented on!), and there's currently no way for an app to know this.

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