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