1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/* General cursor handling code for SDL */
25
26#include "SDL_mutex.h"
27#include "SDL_video.h"
28#include "SDL_mouse.h"
29#include "SDL_blit.h"
30#include "SDL_sysvideo.h"
31#include "SDL_cursor_c.h"
32#include "SDL_pixels_c.h"
33#include "default_cursor.h"
34#include "../events/SDL_sysevents.h"
35#include "../events/SDL_events_c.h"
36
37/* These are static for our cursor handling code */
38volatile int SDL_cursorstate = CURSOR_VISIBLE;
39SDL_Cursor *SDL_cursor = NULL;
40static SDL_Cursor *SDL_defcursor = NULL;
41SDL_mutex *SDL_cursorlock = NULL;
42
43/* Public functions */
44void SDL_CursorQuit(void)
45{
46	if ( SDL_cursor != NULL ) {
47		SDL_Cursor *cursor;
48
49		SDL_cursorstate &= ~CURSOR_VISIBLE;
50		if ( SDL_cursor != SDL_defcursor ) {
51			SDL_FreeCursor(SDL_cursor);
52		}
53		SDL_cursor = NULL;
54		if ( SDL_defcursor != NULL ) {
55			cursor = SDL_defcursor;
56			SDL_defcursor = NULL;
57			SDL_FreeCursor(cursor);
58		}
59	}
60	if ( SDL_cursorlock != NULL ) {
61		SDL_DestroyMutex(SDL_cursorlock);
62		SDL_cursorlock = NULL;
63	}
64}
65int SDL_CursorInit(Uint32 multithreaded)
66{
67	/* We don't have mouse focus, and the cursor isn't drawn yet */
68#ifndef IPOD
69	SDL_cursorstate = CURSOR_VISIBLE;
70#endif
71
72	/* Create the default cursor */
73	if ( SDL_defcursor == NULL ) {
74		SDL_defcursor = SDL_CreateCursor(default_cdata, default_cmask,
75					DEFAULT_CWIDTH, DEFAULT_CHEIGHT,
76						DEFAULT_CHOTX, DEFAULT_CHOTY);
77		SDL_SetCursor(SDL_defcursor);
78	}
79
80	/* Create a lock if necessary */
81	if ( multithreaded ) {
82		SDL_cursorlock = SDL_CreateMutex();
83	}
84
85	/* That's it! */
86	return(0);
87}
88
89/* Multi-thread support for cursors */
90#ifndef SDL_LockCursor
91void SDL_LockCursor(void)
92{
93	if ( SDL_cursorlock ) {
94		SDL_mutexP(SDL_cursorlock);
95	}
96}
97#endif
98#ifndef SDL_UnlockCursor
99void SDL_UnlockCursor(void)
100{
101	if ( SDL_cursorlock ) {
102		SDL_mutexV(SDL_cursorlock);
103	}
104}
105#endif
106
107/* Software cursor drawing support */
108SDL_Cursor * SDL_CreateCursor (Uint8 *data, Uint8 *mask,
109					int w, int h, int hot_x, int hot_y)
110{
111	SDL_VideoDevice *video = current_video;
112	int savelen;
113	int i;
114	SDL_Cursor *cursor;
115
116	/* Make sure the width is a multiple of 8 */
117	w = ((w+7)&~7);
118
119	/* Sanity check the hot spot */
120	if ( (hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h) ) {
121		SDL_SetError("Cursor hot spot doesn't lie within cursor");
122		return(NULL);
123	}
124
125	/* Allocate memory for the cursor */
126	cursor = (SDL_Cursor *)SDL_malloc(sizeof *cursor);
127	if ( cursor == NULL ) {
128		SDL_OutOfMemory();
129		return(NULL);
130	}
131	savelen = (w*4)*h;
132	cursor->area.x = 0;
133	cursor->area.y = 0;
134	cursor->area.w = w;
135	cursor->area.h = h;
136	cursor->hot_x = hot_x;
137	cursor->hot_y = hot_y;
138	cursor->data = (Uint8 *)SDL_malloc((w/8)*h*2);
139	cursor->mask = cursor->data+((w/8)*h);
140	cursor->save[0] = (Uint8 *)SDL_malloc(savelen*2);
141	cursor->save[1] = cursor->save[0] + savelen;
142	cursor->wm_cursor = NULL;
143	if ( ! cursor->data || ! cursor->save[0] ) {
144		SDL_FreeCursor(cursor);
145		SDL_OutOfMemory();
146		return(NULL);
147	}
148	for ( i=((w/8)*h)-1; i>=0; --i ) {
149		cursor->data[i] = data[i];
150		cursor->mask[i] = mask[i] | data[i];
151	}
152	SDL_memset(cursor->save[0], 0, savelen*2);
153
154	/* If the window manager gives us a good cursor, we're done! */
155	if ( video->CreateWMCursor ) {
156		cursor->wm_cursor = video->CreateWMCursor(video, data, mask,
157							w, h, hot_x, hot_y);
158	} else {
159		cursor->wm_cursor = NULL;
160	}
161	return(cursor);
162}
163
164/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
165   if this is desired for any reason.  This is used when setting
166   the video mode and when the SDL window gains the mouse focus.
167 */
168void SDL_SetCursor (SDL_Cursor *cursor)
169{
170	SDL_VideoDevice *video = current_video;
171	SDL_VideoDevice *this  = current_video;
172
173	/* Make sure that the video subsystem has been initialized */
174	if ( ! video ) {
175		return;
176	}
177
178	/* Prevent the event thread from moving the mouse */
179	SDL_LockCursor();
180
181	/* Set the new cursor */
182	if ( cursor && (cursor != SDL_cursor) ) {
183		/* Erase the current mouse position */
184		if ( SHOULD_DRAWCURSOR(SDL_cursorstate) ) {
185			SDL_EraseCursor(SDL_VideoSurface);
186		} else if ( video->MoveWMCursor ) {
187			/* If the video driver is moving the cursor directly,
188			   it needs to hide the old cursor before (possibly)
189			   showing the new one.  (But don't erase NULL cursor)
190			 */
191			if ( SDL_cursor && video->ShowWMCursor ) {
192				video->ShowWMCursor(this, NULL);
193			}
194		}
195		SDL_cursor = cursor;
196	}
197
198	/* Draw the new mouse cursor */
199	if ( SDL_cursor && (SDL_cursorstate&CURSOR_VISIBLE) ) {
200		/* Use window manager cursor if possible */
201		int show_wm_cursor = 0;
202		if ( SDL_cursor->wm_cursor && video->ShowWMCursor ) {
203			show_wm_cursor = video->ShowWMCursor(this, SDL_cursor->wm_cursor);
204		}
205		if ( show_wm_cursor ) {
206			SDL_cursorstate &= ~CURSOR_USINGSW;
207		} else {
208			SDL_cursorstate |= CURSOR_USINGSW;
209			if ( video->ShowWMCursor ) {
210				video->ShowWMCursor(this, NULL);
211			}
212			{ int x, y;
213				SDL_GetMouseState(&x, &y);
214				SDL_cursor->area.x = (x - SDL_cursor->hot_x);
215				SDL_cursor->area.y = (y - SDL_cursor->hot_y);
216			}
217			SDL_DrawCursor(SDL_VideoSurface);
218		}
219	} else {
220		/* Erase window manager mouse (cursor not visible) */
221		if ( SDL_cursor && (SDL_cursorstate & CURSOR_USINGSW) ) {
222			SDL_EraseCursor(SDL_VideoSurface);
223		} else {
224			if ( video ) {
225				if ( video->ShowWMCursor ) {
226					video->ShowWMCursor(this, NULL);
227				}
228			}
229		}
230	}
231	SDL_UnlockCursor();
232}
233
234SDL_Cursor * SDL_GetCursor (void)
235{
236	return(SDL_cursor);
237}
238
239void SDL_FreeCursor (SDL_Cursor *cursor)
240{
241	if ( cursor ) {
242		if ( cursor == SDL_cursor ) {
243			SDL_SetCursor(SDL_defcursor);
244		}
245		if ( cursor != SDL_defcursor ) {
246			SDL_VideoDevice *video = current_video;
247			SDL_VideoDevice *this  = current_video;
248
249			if ( cursor->data ) {
250				SDL_free(cursor->data);
251			}
252			if ( cursor->save[0] ) {
253				SDL_free(cursor->save[0]);
254			}
255			if ( video && cursor->wm_cursor ) {
256				if ( video->FreeWMCursor ) {
257					video->FreeWMCursor(this, cursor->wm_cursor);
258				}
259			}
260			SDL_free(cursor);
261		}
262	}
263}
264
265int SDL_ShowCursor (int toggle)
266{
267	int showing;
268
269	showing = (SDL_cursorstate & CURSOR_VISIBLE);
270	if ( toggle >= 0 ) {
271		SDL_LockCursor();
272		if ( toggle ) {
273			SDL_cursorstate |= CURSOR_VISIBLE;
274		} else {
275			SDL_cursorstate &= ~CURSOR_VISIBLE;
276		}
277		SDL_UnlockCursor();
278		if ( (SDL_cursorstate & CURSOR_VISIBLE) != showing ) {
279			SDL_VideoDevice *video = current_video;
280			SDL_VideoDevice *this  = current_video;
281
282			SDL_SetCursor(NULL);
283			if ( video && video->CheckMouseMode ) {
284				video->CheckMouseMode(this);
285			}
286		}
287	} else {
288		/* Query current state */ ;
289	}
290	return(showing ? 1 : 0);
291}
292
293void SDL_WarpMouse (Uint16 x, Uint16 y)
294{
295	SDL_VideoDevice *video = current_video;
296	SDL_VideoDevice *this  = current_video;
297
298	if ( !video || !SDL_PublicSurface ) {
299		SDL_SetError("A video mode must be set before warping mouse");
300		return;
301	}
302
303	/* If we have an offset video mode, offset the mouse coordinates */
304	if (this->screen->pitch == 0) {
305		x += this->screen->offset / this->screen->format->BytesPerPixel;
306		y += this->screen->offset;
307	} else {
308		x += (this->screen->offset % this->screen->pitch) /
309		      this->screen->format->BytesPerPixel;
310		y += (this->screen->offset / this->screen->pitch);
311	}
312
313	/* This generates a mouse motion event */
314	if ( video->WarpWMCursor ) {
315		video->WarpWMCursor(this, x, y);
316	} else {
317		SDL_PrivateMouseMotion(0, 0, x, y);
318	}
319}
320
321void SDL_MoveCursor(int x, int y)
322{
323	SDL_VideoDevice *video = current_video;
324
325	/* Erase and update the current mouse position */
326	if ( SHOULD_DRAWCURSOR(SDL_cursorstate) ) {
327		/* Erase and redraw mouse cursor in new position */
328		SDL_LockCursor();
329		SDL_EraseCursor(SDL_VideoSurface);
330		SDL_cursor->area.x = (x - SDL_cursor->hot_x);
331		SDL_cursor->area.y = (y - SDL_cursor->hot_y);
332		SDL_DrawCursor(SDL_VideoSurface);
333		SDL_UnlockCursor();
334	} else if ( video->MoveWMCursor ) {
335		video->MoveWMCursor(video, x, y);
336	}
337}
338
339/* Keep track of the current cursor colors */
340static int palette_changed = 1;
341static Uint8 pixels8[2];
342
343void SDL_CursorPaletteChanged(void)
344{
345	palette_changed = 1;
346}
347
348void SDL_MouseRect(SDL_Rect *area)
349{
350	int clip_diff;
351
352	*area = SDL_cursor->area;
353	if ( area->x < 0 ) {
354		area->w += area->x;
355		area->x = 0;
356	}
357	if ( area->y < 0 ) {
358		area->h += area->y;
359		area->y = 0;
360	}
361	clip_diff = (area->x+area->w)-SDL_VideoSurface->w;
362	if ( clip_diff > 0 ) {
363		area->w = area->w < clip_diff ? 0 : area->w-clip_diff;
364	}
365	clip_diff = (area->y+area->h)-SDL_VideoSurface->h;
366	if ( clip_diff > 0 ) {
367		area->h = area->h < clip_diff ? 0 : area->h-clip_diff;
368	}
369}
370
371static void SDL_DrawCursorFast(SDL_Surface *screen, SDL_Rect *area)
372{
373	const Uint32 pixels[2] = { 0xFFFFFFFF, 0x00000000 };
374	int i, w, h;
375	Uint8 *data, datab;
376	Uint8 *mask, maskb;
377
378	data = SDL_cursor->data + area->y * SDL_cursor->area.w/8;
379	mask = SDL_cursor->mask + area->y * SDL_cursor->area.w/8;
380	switch (screen->format->BytesPerPixel) {
381
382	    case 1: {
383		Uint8 *dst;
384		int dstskip;
385
386		if ( palette_changed ) {
387			pixels8[0] = (Uint8)SDL_MapRGB(screen->format, 255, 255, 255);
388			pixels8[1] = (Uint8)SDL_MapRGB(screen->format, 0, 0, 0);
389			palette_changed = 0;
390		}
391		dst = (Uint8 *)screen->pixels +
392                       (SDL_cursor->area.y+area->y)*screen->pitch +
393                       SDL_cursor->area.x;
394		dstskip = screen->pitch-area->w;
395
396		for ( h=area->h; h; h-- ) {
397			for ( w=area->w/8; w; w-- ) {
398				maskb = *mask++;
399				datab = *data++;
400				for ( i=0; i<8; ++i ) {
401					if ( maskb & 0x80 ) {
402						*dst = pixels8[datab>>7];
403					}
404					maskb <<= 1;
405					datab <<= 1;
406					dst++;
407				}
408			}
409			dst += dstskip;
410		}
411	    }
412	    break;
413
414	    case 2: {
415		Uint16 *dst;
416		int dstskip;
417
418		dst = (Uint16 *)screen->pixels +
419                       (SDL_cursor->area.y+area->y)*screen->pitch/2 +
420                       SDL_cursor->area.x;
421		dstskip = (screen->pitch/2)-area->w;
422
423		for ( h=area->h; h; h-- ) {
424			for ( w=area->w/8; w; w-- ) {
425				maskb = *mask++;
426				datab = *data++;
427				for ( i=0; i<8; ++i ) {
428					if ( maskb & 0x80 ) {
429						*dst = (Uint16)pixels[datab>>7];
430					}
431					maskb <<= 1;
432					datab <<= 1;
433					dst++;
434				}
435			}
436			dst += dstskip;
437		}
438	    }
439	    break;
440
441	    case 3: {
442		Uint8 *dst;
443		int dstskip;
444
445		dst = (Uint8 *)screen->pixels +
446                       (SDL_cursor->area.y+area->y)*screen->pitch +
447                       SDL_cursor->area.x*3;
448		dstskip = screen->pitch-area->w*3;
449
450		for ( h=area->h; h; h-- ) {
451			for ( w=area->w/8; w; w-- ) {
452				maskb = *mask++;
453				datab = *data++;
454				for ( i=0; i<8; ++i ) {
455					if ( maskb & 0x80 ) {
456						SDL_memset(dst,pixels[datab>>7],3);
457					}
458					maskb <<= 1;
459					datab <<= 1;
460					dst += 3;
461				}
462			}
463			dst += dstskip;
464		}
465	    }
466	    break;
467
468	    case 4: {
469		Uint32 *dst;
470		int dstskip;
471
472		dst = (Uint32 *)screen->pixels +
473                       (SDL_cursor->area.y+area->y)*screen->pitch/4 +
474                       SDL_cursor->area.x;
475		dstskip = (screen->pitch/4)-area->w;
476
477		for ( h=area->h; h; h-- ) {
478			for ( w=area->w/8; w; w-- ) {
479				maskb = *mask++;
480				datab = *data++;
481				for ( i=0; i<8; ++i ) {
482					if ( maskb & 0x80 ) {
483						*dst = pixels[datab>>7];
484					}
485					maskb <<= 1;
486					datab <<= 1;
487					dst++;
488				}
489			}
490			dst += dstskip;
491		}
492	    }
493	    break;
494	}
495}
496
497static void SDL_DrawCursorSlow(SDL_Surface *screen, SDL_Rect *area)
498{
499	const Uint32 pixels[2] = { 0xFFFFFF, 0x000000 };
500	int h;
501	int x, minx, maxx;
502	Uint8 *data, datab = 0;
503	Uint8 *mask, maskb = 0;
504	Uint8 *dst;
505	int dstbpp, dstskip;
506
507	data = SDL_cursor->data + area->y * SDL_cursor->area.w/8;
508	mask = SDL_cursor->mask + area->y * SDL_cursor->area.w/8;
509	dstbpp = screen->format->BytesPerPixel;
510	dst = (Uint8 *)screen->pixels +
511                       (SDL_cursor->area.y+area->y)*screen->pitch +
512                       SDL_cursor->area.x*dstbpp;
513	dstskip = screen->pitch-SDL_cursor->area.w*dstbpp;
514
515	minx = area->x;
516	maxx = area->x+area->w;
517	if ( screen->format->BytesPerPixel == 1 ) {
518		if ( palette_changed ) {
519			pixels8[0] = (Uint8)SDL_MapRGB(screen->format, 255, 255, 255);
520			pixels8[1] = (Uint8)SDL_MapRGB(screen->format, 0, 0, 0);
521			palette_changed = 0;
522		}
523		for ( h=area->h; h; h-- ) {
524			for ( x=0; x<SDL_cursor->area.w; ++x ) {
525				if ( (x%8) == 0 ) {
526					maskb = *mask++;
527					datab = *data++;
528				}
529				if ( (x >= minx) && (x < maxx) ) {
530					if ( maskb & 0x80 ) {
531						SDL_memset(dst, pixels8[datab>>7], dstbpp);
532					}
533				}
534				maskb <<= 1;
535				datab <<= 1;
536				dst += dstbpp;
537			}
538			dst += dstskip;
539		}
540	} else {
541		for ( h=area->h; h; h-- ) {
542			for ( x=0; x<SDL_cursor->area.w; ++x ) {
543				if ( (x%8) == 0 ) {
544					maskb = *mask++;
545					datab = *data++;
546				}
547				if ( (x >= minx) && (x < maxx) ) {
548					if ( maskb & 0x80 ) {
549						SDL_memset(dst, pixels[datab>>7], dstbpp);
550					}
551				}
552				maskb <<= 1;
553				datab <<= 1;
554				dst += dstbpp;
555			}
556			dst += dstskip;
557		}
558	}
559}
560
561/* This handles the ugly work of converting the saved cursor background from
562   the pixel format of the shadow surface to that of the video surface.
563   This is only necessary when blitting from a shadow surface of a different
564   pixel format than the video surface, and using a software rendered cursor.
565*/
566static void SDL_ConvertCursorSave(SDL_Surface *screen, int w, int h)
567{
568	SDL_BlitInfo info;
569	SDL_loblit RunBlit;
570
571	/* Make sure we can steal the blit mapping */
572	if ( screen->map->dst != SDL_VideoSurface ) {
573		return;
574	}
575
576	/* Set up the blit information */
577	info.s_pixels = SDL_cursor->save[1];
578	info.s_width = w;
579	info.s_height = h;
580	info.s_skip = 0;
581	info.d_pixels = SDL_cursor->save[0];
582	info.d_width = w;
583	info.d_height = h;
584	info.d_skip = 0;
585	info.aux_data = screen->map->sw_data->aux_data;
586	info.src = screen->format;
587	info.table = screen->map->table;
588	info.dst = SDL_VideoSurface->format;
589	RunBlit = screen->map->sw_data->blit;
590
591	/* Run the actual software blit */
592	RunBlit(&info);
593}
594
595void SDL_DrawCursorNoLock(SDL_Surface *screen)
596{
597	SDL_Rect area;
598
599	/* Get the mouse rectangle, clipped to the screen */
600	SDL_MouseRect(&area);
601	if ( (area.w == 0) || (area.h == 0) ) {
602		return;
603	}
604
605	/* Copy mouse background */
606	{ int w, h, screenbpp;
607	  Uint8 *src, *dst;
608
609	  /* Set up the copy pointers */
610	  screenbpp = screen->format->BytesPerPixel;
611	  if ( (screen == SDL_VideoSurface) ||
612	          FORMAT_EQUAL(screen->format, SDL_VideoSurface->format) ) {
613		dst = SDL_cursor->save[0];
614	  } else {
615		dst = SDL_cursor->save[1];
616	  }
617	  src = (Uint8 *)screen->pixels + area.y * screen->pitch +
618                                          area.x * screenbpp;
619
620	  /* Perform the copy */
621	  w = area.w*screenbpp;
622	  h = area.h;
623	  while ( h-- ) {
624		  SDL_memcpy(dst, src, w);
625		  dst += w;
626		  src += screen->pitch;
627	  }
628	}
629
630	/* Draw the mouse cursor */
631	area.x -= SDL_cursor->area.x;
632	area.y -= SDL_cursor->area.y;
633	if ( (area.x == 0) && (area.w == SDL_cursor->area.w) ) {
634		SDL_DrawCursorFast(screen, &area);
635	} else {
636		SDL_DrawCursorSlow(screen, &area);
637	}
638}
639
640void SDL_DrawCursor(SDL_Surface *screen)
641{
642	/* Lock the screen if necessary */
643	if ( screen == NULL ) {
644		return;
645	}
646	if ( SDL_MUSTLOCK(screen) ) {
647		if ( SDL_LockSurface(screen) < 0 ) {
648			return;
649		}
650	}
651
652	SDL_DrawCursorNoLock(screen);
653
654	/* Unlock the screen and update if necessary */
655	if ( SDL_MUSTLOCK(screen) ) {
656		SDL_UnlockSurface(screen);
657	}
658	if ( (screen == SDL_VideoSurface) &&
659	     ((screen->flags & SDL_HWSURFACE) != SDL_HWSURFACE) ) {
660		SDL_VideoDevice *video = current_video;
661		SDL_VideoDevice *this  = current_video;
662		SDL_Rect area;
663
664		SDL_MouseRect(&area);
665
666		/* This can be called before a video mode is set */
667		if ( video->UpdateRects ) {
668			video->UpdateRects(this, 1, &area);
669		}
670	}
671}
672
673void SDL_EraseCursorNoLock(SDL_Surface *screen)
674{
675	SDL_Rect area;
676
677	/* Get the mouse rectangle, clipped to the screen */
678	SDL_MouseRect(&area);
679	if ( (area.w == 0) || (area.h == 0) ) {
680		return;
681	}
682
683	/* Copy mouse background */
684	{ int w, h, screenbpp;
685	  Uint8 *src, *dst;
686
687	  /* Set up the copy pointers */
688	  screenbpp = screen->format->BytesPerPixel;
689	  if ( (screen == SDL_VideoSurface) ||
690	          FORMAT_EQUAL(screen->format, SDL_VideoSurface->format) ) {
691		src = SDL_cursor->save[0];
692	  } else {
693		src = SDL_cursor->save[1];
694	  }
695	  dst = (Uint8 *)screen->pixels + area.y * screen->pitch +
696                                          area.x * screenbpp;
697
698	  /* Perform the copy */
699	  w = area.w*screenbpp;
700	  h = area.h;
701	  while ( h-- ) {
702		  SDL_memcpy(dst, src, w);
703		  src += w;
704		  dst += screen->pitch;
705	  }
706
707	  /* Perform pixel conversion on cursor background */
708	  if ( src > SDL_cursor->save[1] ) {
709		SDL_ConvertCursorSave(screen, area.w, area.h);
710	  }
711	}
712}
713
714void SDL_EraseCursor(SDL_Surface *screen)
715{
716	/* Lock the screen if necessary */
717	if ( screen == NULL ) {
718		return;
719	}
720	if ( SDL_MUSTLOCK(screen) ) {
721		if ( SDL_LockSurface(screen) < 0 ) {
722			return;
723		}
724	}
725
726	SDL_EraseCursorNoLock(screen);
727
728	/* Unlock the screen and update if necessary */
729	if ( SDL_MUSTLOCK(screen) ) {
730		SDL_UnlockSurface(screen);
731	}
732	if ( (screen == SDL_VideoSurface) &&
733	     ((screen->flags & SDL_HWSURFACE) != SDL_HWSURFACE) ) {
734		SDL_VideoDevice *video = current_video;
735		SDL_VideoDevice *this  = current_video;
736		SDL_Rect area;
737
738		SDL_MouseRect(&area);
739		if ( video->UpdateRects ) {
740			video->UpdateRects(this, 1, &area);
741		}
742	}
743}
744
745/* Reset the cursor on video mode change
746   FIXME:  Keep track of all cursors, and reset them all.
747 */
748void SDL_ResetCursor(void)
749{
750	int savelen;
751
752	if ( SDL_cursor ) {
753		savelen = SDL_cursor->area.w*4*SDL_cursor->area.h;
754		SDL_cursor->area.x = 0;
755		SDL_cursor->area.y = 0;
756		SDL_memset(SDL_cursor->save[0], 0, savelen);
757	}
758}
759