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