src/video/SDL_cursor.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 08 Sep 2005 07:33:22 +0000
changeset 1140 af8b0f9ac2f4
parent 769 b8d311d90021
child 1163 96ef83467667
permissions -rw-r--r--
iPod Linux framebuffer support.

--ryan.


Date: Sun, 19 Jun 2005 15:53:22 -0700
From: Joshua Oreman <oremanj@gmail.com>
To: sdl@libsdl.org
Subject: [SDL] [PATCH] iPod framebuffer video driver

Hi SDL-list,

I've been working on a port of SDL to iPodLinux
(http://www.ipodlinux.org). I've created a patch for both the
standard 2-bit iPod screen (using an unchangeable palette) and the
16-bit iPod photo. The patch is attached, against version 1.2.8.

I've created two pages on the iPodLinux wiki about this patch:
http://www.ipodlinux.org/Building_SDL and
http://www.ipodlinux.org/SDL_Programming. See those pages if you're
curious.

Comments? Questions? Is this something that might be able to get into SDL 1.2.9?

Thanks for your feedback!
-- Josh
     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 	x += (this->screen->offset % this->screen->pitch) /
   307 	      this->screen->format->BytesPerPixel;
   308 	y += (this->screen->offset / this->screen->pitch);
   309 
   310 	/* This generates a mouse motion event */
   311 	if ( video->WarpWMCursor ) {
   312 		video->WarpWMCursor(this, x, y);
   313 	} else {
   314 		SDL_PrivateMouseMotion(0, 0, x, y);
   315 	}
   316 }
   317 
   318 void SDL_MoveCursor(int x, int y)
   319 {
   320 	SDL_VideoDevice *video = current_video;
   321 
   322 	/* Erase and update the current mouse position */
   323 	if ( SHOULD_DRAWCURSOR(SDL_cursorstate) ) {
   324 		/* Erase and redraw mouse cursor in new position */
   325 		SDL_LockCursor();
   326 		SDL_EraseCursor(SDL_VideoSurface);
   327 		SDL_cursor->area.x = (x - SDL_cursor->hot_x);
   328 		SDL_cursor->area.y = (y - SDL_cursor->hot_y);
   329 		SDL_DrawCursor(SDL_VideoSurface);
   330 		SDL_UnlockCursor();
   331 	} else if ( video->MoveWMCursor ) {
   332 		video->MoveWMCursor(video, x, y);
   333 	}
   334 }
   335 
   336 /* Keep track of the current cursor colors */
   337 static int palette_changed = 1;
   338 static Uint32 pixels8[2];
   339 
   340 void SDL_CursorPaletteChanged(void)
   341 {
   342 	palette_changed = 1;
   343 }
   344 
   345 void SDL_MouseRect(SDL_Rect *area)
   346 {
   347 	int clip_diff;
   348 
   349 	*area = SDL_cursor->area;
   350 	if ( area->x < 0 ) {
   351 		area->w += area->x;
   352 		area->x = 0;
   353 	}
   354 	if ( area->y < 0 ) {
   355 		area->h += area->y;
   356 		area->y = 0;
   357 	}
   358 	clip_diff = (area->x+area->w)-SDL_VideoSurface->w;
   359 	if ( clip_diff > 0 ) {
   360 		area->w = area->w < clip_diff ? 0 : area->w-clip_diff;
   361 	}
   362 	clip_diff = (area->y+area->h)-SDL_VideoSurface->h;
   363 	if ( clip_diff > 0 ) {
   364 		area->h = area->h < clip_diff ? 0 : area->h-clip_diff;
   365 	}
   366 }
   367 
   368 static void SDL_DrawCursorFast(SDL_Surface *screen, SDL_Rect *area)
   369 {
   370 	const Uint32 pixels[2] = { 0xFFFFFFFF, 0x00000000 };
   371 	int i, w, h;
   372 	Uint8 *data, datab;
   373 	Uint8 *mask, maskb;
   374 
   375 	data = SDL_cursor->data + area->y * SDL_cursor->area.w/8;
   376 	mask = SDL_cursor->mask + area->y * SDL_cursor->area.w/8;
   377 	switch (screen->format->BytesPerPixel) {
   378 
   379 	    case 1: {
   380 		Uint8 *dst;
   381 		int dstskip;
   382 
   383 		if ( palette_changed ) {
   384 			pixels8[0] = SDL_MapRGB(screen->format, 255, 255, 255);
   385 			pixels8[1] = SDL_MapRGB(screen->format, 0, 0, 0);
   386 			palette_changed = 0;
   387 		}
   388 		dst = (Uint8 *)screen->pixels +
   389                        (SDL_cursor->area.y+area->y)*screen->pitch +
   390                        SDL_cursor->area.x;
   391 		dstskip = screen->pitch-area->w;
   392 
   393 		for ( h=area->h; h; h-- ) {
   394 			for ( w=area->w/8; w; w-- ) {
   395 				maskb = *mask++;
   396 				datab = *data++;
   397 				for ( i=0; i<8; ++i ) {
   398 					if ( maskb & 0x80 ) {
   399 						*dst = pixels8[datab>>7];
   400 					}
   401 					maskb <<= 1;
   402 					datab <<= 1;
   403 					dst++;
   404 				}
   405 			}
   406 			dst += dstskip;
   407 		}
   408 	    }
   409 	    break;
   410 
   411 	    case 2: {
   412 		Uint16 *dst;
   413 		int dstskip;
   414 
   415 		dst = (Uint16 *)screen->pixels +
   416                        (SDL_cursor->area.y+area->y)*screen->pitch/2 +
   417                        SDL_cursor->area.x;
   418 		dstskip = (screen->pitch/2)-area->w;
   419 
   420 		for ( h=area->h; h; h-- ) {
   421 			for ( w=area->w/8; w; w-- ) {
   422 				maskb = *mask++;
   423 				datab = *data++;
   424 				for ( i=0; i<8; ++i ) {
   425 					if ( maskb & 0x80 ) {
   426 						*dst = pixels[datab>>7];
   427 					}
   428 					maskb <<= 1;
   429 					datab <<= 1;
   430 					dst++;
   431 				}
   432 			}
   433 			dst += dstskip;
   434 		}
   435 	    }
   436 	    break;
   437 
   438 	    case 3: {
   439 		Uint8 *dst;
   440 		int dstskip;
   441 
   442 		dst = (Uint8 *)screen->pixels +
   443                        (SDL_cursor->area.y+area->y)*screen->pitch +
   444                        SDL_cursor->area.x*3;
   445 		dstskip = screen->pitch-area->w*3;
   446 
   447 		for ( h=area->h; h; h-- ) {
   448 			for ( w=area->w/8; w; w-- ) {
   449 				maskb = *mask++;
   450 				datab = *data++;
   451 				for ( i=0; i<8; ++i ) {
   452 					if ( maskb & 0x80 ) {
   453 						memset(dst,pixels[datab>>7],3);
   454 					}
   455 					maskb <<= 1;
   456 					datab <<= 1;
   457 					dst += 3;
   458 				}
   459 			}
   460 			dst += dstskip;
   461 		}
   462 	    }
   463 	    break;
   464 
   465 	    case 4: {
   466 		Uint32 *dst;
   467 		int dstskip;
   468 
   469 		dst = (Uint32 *)screen->pixels +
   470                        (SDL_cursor->area.y+area->y)*screen->pitch/4 +
   471                        SDL_cursor->area.x;
   472 		dstskip = (screen->pitch/4)-area->w;
   473 
   474 		for ( h=area->h; h; h-- ) {
   475 			for ( w=area->w/8; w; w-- ) {
   476 				maskb = *mask++;
   477 				datab = *data++;
   478 				for ( i=0; i<8; ++i ) {
   479 					if ( maskb & 0x80 ) {
   480 						*dst = pixels[datab>>7];
   481 					}
   482 					maskb <<= 1;
   483 					datab <<= 1;
   484 					dst++;
   485 				}
   486 			}
   487 			dst += dstskip;
   488 		}
   489 	    }
   490 	    break;
   491 	}
   492 }
   493 
   494 static void SDL_DrawCursorSlow(SDL_Surface *screen, SDL_Rect *area)
   495 {
   496 	const Uint32 pixels[2] = { 0xFFFFFF, 0x000000 };
   497 	int h;
   498 	int x, minx, maxx;
   499 	Uint8 *data, datab = 0;
   500 	Uint8 *mask, maskb = 0;
   501 	Uint8 *dst;
   502 	int dstbpp, dstskip;
   503 
   504 	data = SDL_cursor->data + area->y * SDL_cursor->area.w/8;
   505 	mask = SDL_cursor->mask + area->y * SDL_cursor->area.w/8;
   506 	dstbpp = screen->format->BytesPerPixel;
   507 	dst = (Uint8 *)screen->pixels +
   508                        (SDL_cursor->area.y+area->y)*screen->pitch +
   509                        SDL_cursor->area.x*dstbpp;
   510 	dstskip = screen->pitch-SDL_cursor->area.w*dstbpp;
   511 
   512 	minx = area->x;
   513 	maxx = area->x+area->w;
   514 	if ( screen->format->BytesPerPixel == 1 ) {
   515 		if ( palette_changed ) {
   516 			pixels8[0] = SDL_MapRGB(screen->format, 255, 255, 255);
   517 			pixels8[1] = SDL_MapRGB(screen->format, 0, 0, 0);
   518 			palette_changed = 0;
   519 		}
   520 		for ( h=area->h; h; h-- ) {
   521 			for ( x=0; x<SDL_cursor->area.w; ++x ) {
   522 				if ( (x%8) == 0 ) {
   523 					maskb = *mask++;
   524 					datab = *data++;
   525 				}
   526 				if ( (x >= minx) && (x < maxx) ) {
   527 					if ( maskb & 0x80 ) {
   528 						memset(dst, pixels8[datab>>7], dstbpp);
   529 					}
   530 				}
   531 				maskb <<= 1;
   532 				datab <<= 1;
   533 				dst += dstbpp;
   534 			}
   535 			dst += dstskip;
   536 		}
   537 	} else {
   538 		for ( h=area->h; h; h-- ) {
   539 			for ( x=0; x<SDL_cursor->area.w; ++x ) {
   540 				if ( (x%8) == 0 ) {
   541 					maskb = *mask++;
   542 					datab = *data++;
   543 				}
   544 				if ( (x >= minx) && (x < maxx) ) {
   545 					if ( maskb & 0x80 ) {
   546 						memset(dst, pixels[datab>>7], dstbpp);
   547 					}
   548 				}
   549 				maskb <<= 1;
   550 				datab <<= 1;
   551 				dst += dstbpp;
   552 			}
   553 			dst += dstskip;
   554 		}
   555 	}
   556 }
   557 
   558 /* This handles the ugly work of converting the saved cursor background from
   559    the pixel format of the shadow surface to that of the video surface.
   560    This is only necessary when blitting from a shadow surface of a different
   561    pixel format than the video surface, and using a software rendered cursor.
   562 */
   563 static void SDL_ConvertCursorSave(SDL_Surface *screen, int w, int h)
   564 {
   565 	SDL_BlitInfo info;
   566 	SDL_loblit RunBlit;
   567 
   568 	/* Make sure we can steal the blit mapping */
   569 	if ( screen->map->dst != SDL_VideoSurface ) {
   570 		return;
   571 	}
   572 
   573 	/* Set up the blit information */
   574 	info.s_pixels = SDL_cursor->save[1];
   575 	info.s_width = w;
   576 	info.s_height = h;
   577 	info.s_skip = 0;
   578 	info.d_pixels = SDL_cursor->save[0];
   579 	info.d_width = w;
   580 	info.d_height = h;
   581 	info.d_skip = 0;
   582 	info.aux_data = screen->map->sw_data->aux_data;
   583 	info.src = screen->format;
   584 	info.table = screen->map->table;
   585 	info.dst = SDL_VideoSurface->format;
   586 	RunBlit = screen->map->sw_data->blit;
   587 
   588 	/* Run the actual software blit */
   589 	RunBlit(&info);
   590 }
   591 
   592 void SDL_DrawCursorNoLock(SDL_Surface *screen)
   593 {
   594 	SDL_Rect area;
   595 
   596 	/* Get the mouse rectangle, clipped to the screen */
   597 	SDL_MouseRect(&area);
   598 	if ( (area.w == 0) || (area.h == 0) ) {
   599 		return;
   600 	}
   601 
   602 	/* Copy mouse background */
   603 	{ int w, h, screenbpp;
   604 	  Uint8 *src, *dst;
   605 
   606 	  /* Set up the copy pointers */
   607 	  screenbpp = screen->format->BytesPerPixel;
   608 	  if ( (screen == SDL_VideoSurface) ||
   609 	          FORMAT_EQUAL(screen->format, SDL_VideoSurface->format) ) {
   610 		dst = SDL_cursor->save[0];
   611 	  } else {
   612 		dst = SDL_cursor->save[1];
   613 	  }
   614 	  src = (Uint8 *)screen->pixels + area.y * screen->pitch +
   615                                           area.x * screenbpp;
   616 
   617 	  /* Perform the copy */
   618 	  w = area.w*screenbpp;
   619 	  h = area.h;
   620 	  while ( h-- ) {
   621 		  memcpy(dst, src, w);
   622 		  dst += w;
   623 		  src += screen->pitch;
   624 	  }
   625 	}
   626 
   627 	/* Draw the mouse cursor */
   628 	area.x -= SDL_cursor->area.x;
   629 	area.y -= SDL_cursor->area.y;
   630 	if ( (area.x == 0) && (area.w == SDL_cursor->area.w) ) {
   631 		SDL_DrawCursorFast(screen, &area);
   632 	} else {
   633 		SDL_DrawCursorSlow(screen, &area);
   634 	}
   635 }
   636 
   637 void SDL_DrawCursor(SDL_Surface *screen)
   638 {
   639 	/* Lock the screen if necessary */
   640 	if ( screen == NULL ) {
   641 		return;
   642 	}
   643 	if ( SDL_MUSTLOCK(screen) ) {
   644 		if ( SDL_LockSurface(screen) < 0 ) {
   645 			return;
   646 		}
   647 	}
   648 
   649 	SDL_DrawCursorNoLock(screen);
   650 
   651 	/* Unlock the screen and update if necessary */
   652 	if ( SDL_MUSTLOCK(screen) ) {
   653 		SDL_UnlockSurface(screen);
   654 	}
   655 	if ( (screen == SDL_VideoSurface) &&
   656 	     ((screen->flags & SDL_HWSURFACE) != SDL_HWSURFACE) ) {
   657 		SDL_VideoDevice *video = current_video;
   658 		SDL_VideoDevice *this  = current_video;
   659 		SDL_Rect area;
   660 
   661 		SDL_MouseRect(&area);
   662 
   663 		/* This can be called before a video mode is set */
   664 		if ( video->UpdateRects ) {
   665 			video->UpdateRects(this, 1, &area);
   666 		}
   667 	}
   668 }
   669 
   670 void SDL_EraseCursorNoLock(SDL_Surface *screen)
   671 {
   672 	SDL_Rect area;
   673 
   674 	/* Get the mouse rectangle, clipped to the screen */
   675 	SDL_MouseRect(&area);
   676 	if ( (area.w == 0) || (area.h == 0) ) {
   677 		return;
   678 	}
   679 
   680 	/* Copy mouse background */
   681 	{ int w, h, screenbpp;
   682 	  Uint8 *src, *dst;
   683 
   684 	  /* Set up the copy pointers */
   685 	  screenbpp = screen->format->BytesPerPixel;
   686 	  if ( (screen == SDL_VideoSurface) ||
   687 	          FORMAT_EQUAL(screen->format, SDL_VideoSurface->format) ) {
   688 		src = SDL_cursor->save[0];
   689 	  } else {
   690 		src = SDL_cursor->save[1];
   691 	  }
   692 	  dst = (Uint8 *)screen->pixels + area.y * screen->pitch +
   693                                           area.x * screenbpp;
   694 
   695 	  /* Perform the copy */
   696 	  w = area.w*screenbpp;
   697 	  h = area.h;
   698 	  while ( h-- ) {
   699 		  memcpy(dst, src, w);
   700 		  src += w;
   701 		  dst += screen->pitch;
   702 	  }
   703 
   704 	  /* Perform pixel conversion on cursor background */
   705 	  if ( src > SDL_cursor->save[1] ) {
   706 		SDL_ConvertCursorSave(screen, area.w, area.h);
   707 	  }
   708 	}
   709 }
   710 
   711 void SDL_EraseCursor(SDL_Surface *screen)
   712 {
   713 	/* Lock the screen if necessary */
   714 	if ( screen == NULL ) {
   715 		return;
   716 	}
   717 	if ( SDL_MUSTLOCK(screen) ) {
   718 		if ( SDL_LockSurface(screen) < 0 ) {
   719 			return;
   720 		}
   721 	}
   722 
   723 	SDL_EraseCursorNoLock(screen);
   724 
   725 	/* Unlock the screen and update if necessary */
   726 	if ( SDL_MUSTLOCK(screen) ) {
   727 		SDL_UnlockSurface(screen);
   728 	}
   729 	if ( (screen == SDL_VideoSurface) &&
   730 	     ((screen->flags & SDL_HWSURFACE) != SDL_HWSURFACE) ) {
   731 		SDL_VideoDevice *video = current_video;
   732 		SDL_VideoDevice *this  = current_video;
   733 		SDL_Rect area;
   734 
   735 		SDL_MouseRect(&area);
   736 		if ( video->UpdateRects ) {
   737 			video->UpdateRects(this, 1, &area);
   738 		}
   739 	}
   740 }
   741 
   742 /* Reset the cursor on video mode change
   743    FIXME:  Keep track of all cursors, and reset them all.
   744  */
   745 void SDL_ResetCursor(void)
   746 {
   747 	int savelen;
   748 
   749 	if ( SDL_cursor ) {
   750 		savelen = SDL_cursor->area.w*4*SDL_cursor->area.h;
   751 		SDL_cursor->area.x = 0;
   752 		SDL_cursor->area.y = 0;
   753 		memset(SDL_cursor->save[0], 0, savelen);
   754 	}
   755 }