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