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