Home | History | Annotate | Download | only in video
      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 (at) 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 }
    759