SDL-1.2.14
[sdl_omap.git] / src / video / SDL_cursor.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 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 */
38 volatile int SDL_cursorstate = CURSOR_VISIBLE;
39 SDL_Cursor *SDL_cursor = NULL;
40 static SDL_Cursor *SDL_defcursor = NULL;
41 SDL_mutex *SDL_cursorlock = NULL;
42
43 /* Public functions */
44 void 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 }
65 int 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
91 void SDL_LockCursor(void)
92 {
93         if ( SDL_cursorlock ) {
94                 SDL_mutexP(SDL_cursorlock);
95         }
96 }
97 #endif
98 #ifndef SDL_UnlockCursor
99 void SDL_UnlockCursor(void)
100 {
101         if ( SDL_cursorlock ) {
102                 SDL_mutexV(SDL_cursorlock);
103         }
104 }
105 #endif
106
107 /* Software cursor drawing support */
108 SDL_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  */
168 void 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
234 SDL_Cursor * SDL_GetCursor (void)
235 {
236         return(SDL_cursor);
237 }
238
239 void 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
265 int 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
293 void 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
321 void 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 */
340 static int palette_changed = 1;
341 static Uint8 pixels8[2];
342
343 void SDL_CursorPaletteChanged(void)
344 {
345         palette_changed = 1;
346 }
347
348 void 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
371 static 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
497 static 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 */
566 static 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
595 void 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
640 void 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
673 void 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
714 void 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  */
748 void 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 }