SDL  2.0
SDL_mouse.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 "../video/SDL_sysvideo.h"
31 
32 /* #define DEBUG_MOUSE */
33 
34 /* The mouse state */
36 
37 static int
38 SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
39 
40 static void SDLCALL
41 SDL_MouseDoubleClickTimeChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
42 {
43  SDL_Mouse *mouse = (SDL_Mouse *)userdata;
44 
45  if (hint && *hint) {
46  mouse->double_click_time = SDL_atoi(hint);
47  } else {
48 #ifdef __WIN32__
49  mouse->double_click_time = GetDoubleClickTime();
50 #else
51  mouse->double_click_time = 500;
52 #endif
53  }
54 }
55 
56 static void SDLCALL
57 SDL_MouseDoubleClickRadiusChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
58 {
59  SDL_Mouse *mouse = (SDL_Mouse *)userdata;
60 
61  if (hint && *hint) {
62  mouse->double_click_radius = SDL_atoi(hint);
63  } else {
64  mouse->double_click_radius = 32; /* 32 pixels seems about right for touch interfaces */
65  }
66 }
67 
68 static void SDLCALL
69 SDL_MouseNormalSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
70 {
71  SDL_Mouse *mouse = (SDL_Mouse *)userdata;
72 
73  if (hint && *hint) {
74  mouse->normal_speed_scale = (float)SDL_atof(hint);
75  } else {
76  mouse->normal_speed_scale = 1.0f;
77  }
78 }
79 
80 static void SDLCALL
81 SDL_MouseRelativeSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
82 {
83  SDL_Mouse *mouse = (SDL_Mouse *)userdata;
84 
85  if (hint && *hint) {
86  mouse->relative_speed_scale = (float)SDL_atof(hint);
87  } else {
88  mouse->relative_speed_scale = 1.0f;
89  }
90 }
91 
92 static void SDLCALL
93 SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
94 {
95  SDL_Mouse *mouse = (SDL_Mouse *)userdata;
96 
97  if (hint && (*hint == '0' || SDL_strcasecmp(hint, "false") == 0)) {
99  } else {
100  mouse->touch_mouse_events = SDL_TRUE;
101  }
102 }
103 
104 /* Public functions */
105 int
107 {
108  SDL_Mouse *mouse = SDL_GetMouse();
109 
110  SDL_zerop(mouse);
111 
114 
117 
120 
123 
126 
127  mouse->cursor_shown = SDL_TRUE;
128 
129  return (0);
130 }
131 
132 void
134 {
135  SDL_Mouse *mouse = SDL_GetMouse();
136 
137  mouse->def_cursor = cursor;
138  if (!mouse->cur_cursor) {
139  SDL_SetCursor(cursor);
140  }
141 }
142 
143 SDL_Mouse *
145 {
146  return &SDL_mouse;
147 }
148 
149 SDL_Window *
151 {
152  SDL_Mouse *mouse = SDL_GetMouse();
153 
154  return mouse->focus;
155 }
156 
157 #if 0
158 void
159 SDL_ResetMouse(void)
160 {
161  SDL_Mouse *mouse = SDL_GetMouse();
162  Uint8 i;
163 
164 #ifdef DEBUG_MOUSE
165  printf("Resetting mouse\n");
166 #endif
167  for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
168  if (mouse->buttonstate & SDL_BUTTON(i)) {
169  SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
170  }
171  }
172  SDL_assert(mouse->buttonstate == 0);
173 }
174 #endif
175 
176 void
178 {
179  SDL_Mouse *mouse = SDL_GetMouse();
180 
181  if (mouse->focus == window) {
182  return;
183  }
184 
185  /* Actually, this ends up being a bad idea, because most operating
186  systems have an implicit grab when you press the mouse button down
187  so you can drag things out of the window and then get the mouse up
188  when it happens. So, #if 0...
189  */
190 #if 0
191  if (mouse->focus && !window) {
192  /* We won't get anymore mouse messages, so reset mouse state */
193  SDL_ResetMouse();
194  }
195 #endif
196 
197  /* See if the current window has lost focus */
198  if (mouse->focus) {
200  }
201 
202  mouse->focus = window;
203  mouse->has_position = SDL_FALSE;
204 
205  if (mouse->focus) {
207  }
208 
209  /* Update cursor visibility */
211 }
212 
213 /* Check to see if we need to synthesize focus events */
214 static SDL_bool
215 SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
216 {
217  SDL_Mouse *mouse = SDL_GetMouse();
218  SDL_bool inWindow = SDL_TRUE;
219 
220  if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
221  int w, h;
222  SDL_GetWindowSize(window, &w, &h);
223  if (x < 0 || y < 0 || x >= w || y >= h) {
224  inWindow = SDL_FALSE;
225  }
226  }
227 
228 /* Linux doesn't give you mouse events outside your window unless you grab
229  the pointer.
230 
231  Windows doesn't give you mouse events outside your window unless you call
232  SetCapture().
233 
234  Both of these are slightly scary changes, so for now we'll punt and if the
235  mouse leaves the window you'll lose mouse focus and reset button state.
236 */
237 #ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
238  if (!inWindow && !buttonstate) {
239 #else
240  if (!inWindow) {
241 #endif
242  if (window == mouse->focus) {
243 #ifdef DEBUG_MOUSE
244  printf("Mouse left window, synthesizing move & focus lost event\n");
245 #endif
246  SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
248  }
249  return SDL_FALSE;
250  }
251 
252  if (window != mouse->focus) {
253 #ifdef DEBUG_MOUSE
254  printf("Mouse entered window, synthesizing focus gain & move event\n");
255 #endif
256  SDL_SetMouseFocus(window);
257  SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
258  }
259  return SDL_TRUE;
260 }
261 
262 int
263 SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
264 {
265  if (window && !relative) {
266  SDL_Mouse *mouse = SDL_GetMouse();
267  if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
268  return 0;
269  }
270  }
271 
272  return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
273 }
274 
275 static int
276 GetScaledMouseDelta(float scale, int value, float *accum)
277 {
278  if (scale != 1.0f) {
279  *accum += scale * value;
280  if (*accum >= 0.0f) {
281  value = (int)SDL_floor(*accum);
282  } else {
283  value = (int)SDL_ceil(*accum);
284  }
285  *accum -= value;
286  }
287  return value;
288 }
289 
290 static int
291 SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
292 {
293  SDL_Mouse *mouse = SDL_GetMouse();
294  int posted;
295  int xrel;
296  int yrel;
297 
298  if (mouseID == SDL_TOUCH_MOUSEID && !mouse->touch_mouse_events) {
299  return 0;
300  }
301 
302  if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
303  int center_x = 0, center_y = 0;
304  SDL_GetWindowSize(window, &center_x, &center_y);
305  center_x /= 2;
306  center_y /= 2;
307  if (x == center_x && y == center_y) {
308  mouse->last_x = center_x;
309  mouse->last_y = center_y;
310  return 0;
311  }
312  SDL_WarpMouseInWindow(window, center_x, center_y);
313  }
314 
315  if (relative) {
316  if (mouse->relative_mode) {
319  } else {
320  x = GetScaledMouseDelta(mouse->normal_speed_scale, x, &mouse->scale_accum_x);
321  y = GetScaledMouseDelta(mouse->normal_speed_scale, y, &mouse->scale_accum_y);
322  }
323  xrel = x;
324  yrel = y;
325  x = (mouse->last_x + xrel);
326  y = (mouse->last_y + yrel);
327  } else {
328  xrel = x - mouse->last_x;
329  yrel = y - mouse->last_y;
330  }
331 
332  /* Drop events that don't change state */
333  if (!xrel && !yrel) {
334 #ifdef DEBUG_MOUSE
335  printf("Mouse event didn't change state - dropped!\n");
336 #endif
337  return 0;
338  }
339 
340  /* Ignore relative motion when first positioning the mouse */
341  if (!mouse->has_position) {
342  xrel = 0;
343  yrel = 0;
344  mouse->has_position = SDL_TRUE;
345  }
346 
347  /* Ignore relative motion positioning the first touch */
348  if (mouseID == SDL_TOUCH_MOUSEID && !mouse->buttonstate) {
349  xrel = 0;
350  yrel = 0;
351  }
352 
353  /* Update internal mouse coordinates */
354  if (!mouse->relative_mode) {
355  mouse->x = x;
356  mouse->y = y;
357  } else {
358  mouse->x += xrel;
359  mouse->y += yrel;
360  }
361 
362  /* make sure that the pointers find themselves inside the windows,
363  unless we have the mouse captured. */
364  if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
365  int x_max = 0, y_max = 0;
366 
367  /* !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? */
368  SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
369  --x_max;
370  --y_max;
371 
372  if (mouse->x > x_max) {
373  mouse->x = x_max;
374  }
375  if (mouse->x < 0) {
376  mouse->x = 0;
377  }
378 
379  if (mouse->y > y_max) {
380  mouse->y = y_max;
381  }
382  if (mouse->y < 0) {
383  mouse->y = 0;
384  }
385  }
386 
387  mouse->xdelta += xrel;
388  mouse->ydelta += yrel;
389 
390  /* Move the mouse cursor, if needed */
391  if (mouse->cursor_shown && !mouse->relative_mode &&
392  mouse->MoveCursor && mouse->cur_cursor) {
393  mouse->MoveCursor(mouse->cur_cursor);
394  }
395 
396  /* Post the event, if desired */
397  posted = 0;
400  event.motion.type = SDL_MOUSEMOTION;
401  event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
402  event.motion.which = mouseID;
403  event.motion.state = mouse->buttonstate;
404  event.motion.x = mouse->x;
405  event.motion.y = mouse->y;
406  event.motion.xrel = xrel;
407  event.motion.yrel = yrel;
408  posted = (SDL_PushEvent(&event) > 0);
409  }
410  if (relative) {
411  mouse->last_x = mouse->x;
412  mouse->last_y = mouse->y;
413  } else {
414  /* Use unclamped values if we're getting events outside the window */
415  mouse->last_x = x;
416  mouse->last_y = y;
417  }
418  return posted;
419 }
420 
422 {
423  if (button >= mouse->num_clickstates) {
424  int i, count = button + 1;
425  SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
426  if (!clickstate) {
427  return NULL;
428  }
429  mouse->clickstate = clickstate;
430 
431  for (i = mouse->num_clickstates; i < count; ++i) {
432  SDL_zero(mouse->clickstate[i]);
433  }
434  mouse->num_clickstates = count;
435  }
436  return &mouse->clickstate[button];
437 }
438 
439 static int
441 {
442  SDL_Mouse *mouse = SDL_GetMouse();
443  int posted;
444  Uint32 type;
445  Uint32 buttonstate = mouse->buttonstate;
446 
447  if (mouseID == SDL_TOUCH_MOUSEID && !mouse->touch_mouse_events) {
448  return 0;
449  }
450 
451  /* Figure out which event to perform */
452  switch (state) {
453  case SDL_PRESSED:
454  type = SDL_MOUSEBUTTONDOWN;
455  buttonstate |= SDL_BUTTON(button);
456  break;
457  case SDL_RELEASED:
458  type = SDL_MOUSEBUTTONUP;
459  buttonstate &= ~SDL_BUTTON(button);
460  break;
461  default:
462  /* Invalid state -- bail */
463  return 0;
464  }
465 
466  /* We do this after calculating buttonstate so button presses gain focus */
467  if (window && state == SDL_PRESSED) {
468  SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
469  }
470 
471  if (buttonstate == mouse->buttonstate) {
472  /* Ignore this event, no state change */
473  return 0;
474  }
475  mouse->buttonstate = buttonstate;
476 
477  if (clicks < 0) {
478  SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
479  if (clickstate) {
480  if (state == SDL_PRESSED) {
481  Uint32 now = SDL_GetTicks();
482 
483  if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + mouse->double_click_time) ||
484  SDL_abs(mouse->x - clickstate->last_x) > mouse->double_click_radius ||
485  SDL_abs(mouse->y - clickstate->last_y) > mouse->double_click_radius) {
486  clickstate->click_count = 0;
487  }
488  clickstate->last_timestamp = now;
489  clickstate->last_x = mouse->x;
490  clickstate->last_y = mouse->y;
491  if (clickstate->click_count < 255) {
492  ++clickstate->click_count;
493  }
494  }
495  clicks = clickstate->click_count;
496  } else {
497  clicks = 1;
498  }
499  }
500 
501  /* Post the event, if desired */
502  posted = 0;
503  if (SDL_GetEventState(type) == SDL_ENABLE) {
505  event.type = type;
506  event.button.windowID = mouse->focus ? mouse->focus->id : 0;
507  event.button.which = mouseID;
508  event.button.state = state;
509  event.button.button = button;
510  event.button.clicks = (Uint8) SDL_min(clicks, 255);
511  event.button.x = mouse->x;
512  event.button.y = mouse->y;
513  posted = (SDL_PushEvent(&event) > 0);
514  }
515 
516  /* We do this after dispatching event so button releases can lose focus */
517  if (window && state == SDL_RELEASED) {
518  SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
519  }
520 
521  return posted;
522 }
523 
524 int
526 {
527  clicks = SDL_max(clicks, 0);
528  return SDL_PrivateSendMouseButton(window, mouseID, state, button, clicks);
529 }
530 
531 int
533 {
534  return SDL_PrivateSendMouseButton(window, mouseID, state, button, -1);
535 }
536 
537 int
538 SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
539 {
540  SDL_Mouse *mouse = SDL_GetMouse();
541  int posted;
542  int integral_x, integral_y;
543 
544  if (window) {
545  SDL_SetMouseFocus(window);
546  }
547 
548  if (!x && !y) {
549  return 0;
550  }
551 
552  mouse->accumulated_wheel_x += x;
553  if (mouse->accumulated_wheel_x > 0) {
554  integral_x = (int)SDL_floor(mouse->accumulated_wheel_x);
555  } else if (mouse->accumulated_wheel_x < 0) {
556  integral_x = (int)SDL_ceil(mouse->accumulated_wheel_x);
557  } else {
558  integral_x = 0;
559  }
560  mouse->accumulated_wheel_x -= integral_x;
561 
562  mouse->accumulated_wheel_y += y;
563  if (mouse->accumulated_wheel_y > 0) {
564  integral_y = (int)SDL_floor(mouse->accumulated_wheel_y);
565  } else if (mouse->accumulated_wheel_y < 0) {
566  integral_y = (int)SDL_ceil(mouse->accumulated_wheel_y);
567  } else {
568  integral_y = 0;
569  }
570  mouse->accumulated_wheel_y -= integral_y;
571 
572  /* Post the event, if desired */
573  posted = 0;
576  event.type = SDL_MOUSEWHEEL;
577  event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
578  event.wheel.which = mouseID;
579 #if 0 /* Uncomment this when it goes in for SDL 2.1 */
580  event.wheel.preciseX = x;
581  event.wheel.preciseY = y;
582 #endif
583  event.wheel.x = integral_x;
584  event.wheel.y = integral_y;
585  event.wheel.direction = (Uint32)direction;
586  posted = (SDL_PushEvent(&event) > 0);
587  }
588  return posted;
589 }
590 
591 void
593 {
594  SDL_Cursor *cursor, *next;
595  SDL_Mouse *mouse = SDL_GetMouse();
596 
597  if (mouse->CaptureMouse) {
599  }
601  SDL_ShowCursor(1);
602 
603  cursor = mouse->cursors;
604  while (cursor) {
605  next = cursor->next;
606  SDL_FreeCursor(cursor);
607  cursor = next;
608  }
609  mouse->cursors = NULL;
610 
611  if (mouse->def_cursor && mouse->FreeCursor) {
612  mouse->FreeCursor(mouse->def_cursor);
613  mouse->def_cursor = NULL;
614  }
615 
616  if (mouse->clickstate) {
617  SDL_free(mouse->clickstate);
618  mouse->clickstate = NULL;
619  }
620 
623 
626 }
627 
628 Uint32
629 SDL_GetMouseState(int *x, int *y)
630 {
631  SDL_Mouse *mouse = SDL_GetMouse();
632 
633  if (x) {
634  *x = mouse->x;
635  }
636  if (y) {
637  *y = mouse->y;
638  }
639  return mouse->buttonstate;
640 }
641 
642 Uint32
644 {
645  SDL_Mouse *mouse = SDL_GetMouse();
646 
647  if (x) {
648  *x = mouse->xdelta;
649  }
650  if (y) {
651  *y = mouse->ydelta;
652  }
653  mouse->xdelta = 0;
654  mouse->ydelta = 0;
655  return mouse->buttonstate;
656 }
657 
658 Uint32
659 SDL_GetGlobalMouseState(int *x, int *y)
660 {
661  SDL_Mouse *mouse = SDL_GetMouse();
662  int tmpx, tmpy;
663 
664  /* make sure these are never NULL for the backend implementations... */
665  if (!x) {
666  x = &tmpx;
667  }
668  if (!y) {
669  y = &tmpy;
670  }
671 
672  *x = *y = 0;
673 
674  if (!mouse->GetGlobalMouseState) {
675  return 0;
676  }
677 
678  return mouse->GetGlobalMouseState(x, y);
679 }
680 
681 void
682 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
683 {
684  SDL_Mouse *mouse = SDL_GetMouse();
685 
686  if (window == NULL) {
687  window = mouse->focus;
688  }
689 
690  if (window == NULL) {
691  return;
692  }
693 
694  if (mouse->WarpMouse) {
695  mouse->WarpMouse(window, x, y);
696  } else {
697  SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
698  }
699 }
700 
701 int
702 SDL_WarpMouseGlobal(int x, int y)
703 {
704  SDL_Mouse *mouse = SDL_GetMouse();
705 
706  if (mouse->WarpMouseGlobal) {
707  return mouse->WarpMouseGlobal(x, y);
708  }
709 
710  return SDL_Unsupported();
711 }
712 
713 static SDL_bool
715 {
716  if (!mouse->SetRelativeMouseMode) {
717  SDL_assert(mouse->WarpMouse); /* Need this functionality for relative mode warp implementation */
718  return SDL_TRUE;
719  }
720 
722 }
723 
724 int
726 {
727  SDL_Mouse *mouse = SDL_GetMouse();
728  SDL_Window *focusWindow = SDL_GetKeyboardFocus();
729 
730  if (enabled == mouse->relative_mode) {
731  return 0;
732  }
733 
734  if (enabled && focusWindow) {
735  /* Center it in the focused window to prevent clicks from going through
736  * to background windows.
737  */
738  SDL_SetMouseFocus(focusWindow);
739  SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
740  }
741 
742  /* Set the relative mode */
743  if (!enabled && mouse->relative_mode_warp) {
744  mouse->relative_mode_warp = SDL_FALSE;
745  } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
746  mouse->relative_mode_warp = SDL_TRUE;
747  } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
748  if (enabled) {
749  /* Fall back to warp mode if native relative mode failed */
750  if (!mouse->WarpMouse) {
751  return SDL_SetError("No relative mode implementation available");
752  }
753  mouse->relative_mode_warp = SDL_TRUE;
754  }
755  }
756  mouse->relative_mode = enabled;
757  mouse->scale_accum_x = 0.0f;
758  mouse->scale_accum_y = 0.0f;
759 
760  if (mouse->focus) {
761  SDL_UpdateWindowGrab(mouse->focus);
762 
763  /* Put the cursor back to where the application expects it */
764  if (!enabled) {
765  SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
766  }
767  }
768 
769  /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
771 
772  /* Update cursor visibility */
774 
775  return 0;
776 }
777 
778 SDL_bool
780 {
781  SDL_Mouse *mouse = SDL_GetMouse();
782 
783  return mouse->relative_mode;
784 }
785 
786 int
788 {
789  SDL_Mouse *mouse = SDL_GetMouse();
790  SDL_Window *focusWindow;
791  SDL_bool isCaptured;
792 
793  if (!mouse->CaptureMouse) {
794  return SDL_Unsupported();
795  }
796 
797  focusWindow = SDL_GetKeyboardFocus();
798 
799  isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
800  if (isCaptured == enabled) {
801  return 0; /* already done! */
802  }
803 
804  if (enabled) {
805  if (!focusWindow) {
806  return SDL_SetError("No window has focus");
807  } else if (mouse->CaptureMouse(focusWindow) == -1) {
808  return -1; /* CaptureMouse() should call SetError */
809  }
810  focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
811  } else {
812  if (mouse->CaptureMouse(NULL) == -1) {
813  return -1; /* CaptureMouse() should call SetError */
814  }
815  focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
816  }
817 
818  return 0;
819 }
820 
821 SDL_Cursor *
823  int w, int h, int hot_x, int hot_y)
824 {
827  int x, y;
828  Uint32 *pixel;
829  Uint8 datab = 0, maskb = 0;
830  const Uint32 black = 0xFF000000;
831  const Uint32 white = 0xFFFFFFFF;
832  const Uint32 transparent = 0x00000000;
833 
834  /* Make sure the width is a multiple of 8 */
835  w = ((w + 7) & ~7);
836 
837  /* Create the surface from a bitmap */
838  surface = SDL_CreateRGBSurface(0, w, h, 32,
839  0x00FF0000,
840  0x0000FF00,
841  0x000000FF,
842  0xFF000000);
843  if (!surface) {
844  return NULL;
845  }
846  for (y = 0; y < h; ++y) {
847  pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
848  for (x = 0; x < w; ++x) {
849  if ((x % 8) == 0) {
850  datab = *data++;
851  maskb = *mask++;
852  }
853  if (maskb & 0x80) {
854  *pixel++ = (datab & 0x80) ? black : white;
855  } else {
856  *pixel++ = (datab & 0x80) ? black : transparent;
857  }
858  datab <<= 1;
859  maskb <<= 1;
860  }
861  }
862 
863  cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
864 
865  SDL_FreeSurface(surface);
866 
867  return cursor;
868 }
869 
870 SDL_Cursor *
872 {
873  SDL_Mouse *mouse = SDL_GetMouse();
874  SDL_Surface *temp = NULL;
876 
877  if (!surface) {
878  SDL_SetError("Passed NULL cursor surface");
879  return NULL;
880  }
881 
882  if (!mouse->CreateCursor) {
883  SDL_SetError("Cursors are not currently supported");
884  return NULL;
885  }
886 
887  /* Sanity check the hot spot */
888  if ((hot_x < 0) || (hot_y < 0) ||
889  (hot_x >= surface->w) || (hot_y >= surface->h)) {
890  SDL_SetError("Cursor hot spot doesn't lie within cursor");
891  return NULL;
892  }
893 
894  if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
896  if (!temp) {
897  return NULL;
898  }
899  surface = temp;
900  }
901 
902  cursor = mouse->CreateCursor(surface, hot_x, hot_y);
903  if (cursor) {
904  cursor->next = mouse->cursors;
905  mouse->cursors = cursor;
906  }
907 
908  SDL_FreeSurface(temp);
909 
910  return cursor;
911 }
912 
913 SDL_Cursor *
915 {
916  SDL_Mouse *mouse = SDL_GetMouse();
918 
919  if (!mouse->CreateSystemCursor) {
920  SDL_SetError("CreateSystemCursor is not currently supported");
921  return NULL;
922  }
923 
924  cursor = mouse->CreateSystemCursor(id);
925  if (cursor) {
926  cursor->next = mouse->cursors;
927  mouse->cursors = cursor;
928  }
929 
930  return cursor;
931 }
932 
933 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
934  if this is desired for any reason. This is used when setting
935  the video mode and when the SDL window gains the mouse focus.
936  */
937 void
939 {
940  SDL_Mouse *mouse = SDL_GetMouse();
941 
942  /* Set the new cursor */
943  if (cursor) {
944  /* Make sure the cursor is still valid for this mouse */
945  if (cursor != mouse->def_cursor) {
946  SDL_Cursor *found;
947  for (found = mouse->cursors; found; found = found->next) {
948  if (found == cursor) {
949  break;
950  }
951  }
952  if (!found) {
953  SDL_SetError("Cursor not associated with the current mouse");
954  return;
955  }
956  }
957  mouse->cur_cursor = cursor;
958  } else {
959  if (mouse->focus) {
960  cursor = mouse->cur_cursor;
961  } else {
962  cursor = mouse->def_cursor;
963  }
964  }
965 
966  if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
967  if (mouse->ShowCursor) {
968  mouse->ShowCursor(cursor);
969  }
970  } else {
971  if (mouse->ShowCursor) {
972  mouse->ShowCursor(NULL);
973  }
974  }
975 }
976 
977 SDL_Cursor *
979 {
980  SDL_Mouse *mouse = SDL_GetMouse();
981 
982  if (!mouse) {
983  return NULL;
984  }
985  return mouse->cur_cursor;
986 }
987 
988 SDL_Cursor *
990 {
991  SDL_Mouse *mouse = SDL_GetMouse();
992 
993  if (!mouse) {
994  return NULL;
995  }
996  return mouse->def_cursor;
997 }
998 
999 void
1001 {
1002  SDL_Mouse *mouse = SDL_GetMouse();
1003  SDL_Cursor *curr, *prev;
1004 
1005  if (!cursor) {
1006  return;
1007  }
1008 
1009  if (cursor == mouse->def_cursor) {
1010  return;
1011  }
1012  if (cursor == mouse->cur_cursor) {
1013  SDL_SetCursor(mouse->def_cursor);
1014  }
1015 
1016  for (prev = NULL, curr = mouse->cursors; curr;
1017  prev = curr, curr = curr->next) {
1018  if (curr == cursor) {
1019  if (prev) {
1020  prev->next = curr->next;
1021  } else {
1022  mouse->cursors = curr->next;
1023  }
1024 
1025  if (mouse->FreeCursor) {
1026  mouse->FreeCursor(curr);
1027  }
1028  return;
1029  }
1030  }
1031 }
1032 
1033 int
1034 SDL_ShowCursor(int toggle)
1035 {
1036  SDL_Mouse *mouse = SDL_GetMouse();
1037  SDL_bool shown;
1038 
1039  if (!mouse) {
1040  return 0;
1041  }
1042 
1043  shown = mouse->cursor_shown;
1044  if (toggle >= 0) {
1045  if (toggle) {
1046  mouse->cursor_shown = SDL_TRUE;
1047  } else {
1048  mouse->cursor_shown = SDL_FALSE;
1049  }
1050  if (mouse->cursor_shown != shown) {
1052  }
1053  }
1054  return shown;
1055 }
1056 
1057 /* vi: set ts=4 sw=4 expandtab: */