For sanity's sake, removed the '&' when passing copy_row array to asm.
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2004 Sam Lantinga
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.
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.
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
28 /* General cursor handling code for SDL */
34 #include "SDL_mutex.h"
35 #include "SDL_error.h"
36 #include "SDL_video.h"
37 #include "SDL_mouse.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"
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;
52 /* Public functions */
53 void SDL_CursorQuit(void)
55 if ( SDL_cursor != NULL ) {
58 SDL_cursorstate &= ~CURSOR_VISIBLE;
59 if ( SDL_cursor != SDL_defcursor ) {
60 SDL_FreeCursor(SDL_cursor);
63 if ( SDL_defcursor != NULL ) {
64 cursor = SDL_defcursor;
66 SDL_FreeCursor(cursor);
69 if ( SDL_cursorlock != NULL ) {
70 SDL_DestroyMutex(SDL_cursorlock);
71 SDL_cursorlock = NULL;
74 int SDL_CursorInit(Uint32 multithreaded)
76 /* We don't have mouse focus, and the cursor isn't drawn yet */
78 SDL_cursorstate = CURSOR_VISIBLE;
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);
89 /* Create a lock if necessary */
90 if ( multithreaded ) {
91 SDL_cursorlock = SDL_CreateMutex();
98 /* Multi-thread support for cursors */
99 #ifndef SDL_LockCursor
100 void SDL_LockCursor(void)
102 if ( SDL_cursorlock ) {
103 SDL_mutexP(SDL_cursorlock);
107 #ifndef SDL_UnlockCursor
108 void SDL_UnlockCursor(void)
110 if ( SDL_cursorlock ) {
111 SDL_mutexV(SDL_cursorlock);
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)
120 SDL_VideoDevice *video = current_video;
125 /* Make sure the width is a multiple of 8 */
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");
134 /* Allocate memory for the cursor */
135 cursor = (SDL_Cursor *)malloc(sizeof *cursor);
136 if ( cursor == NULL ) {
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);
157 for ( i=((w/8)*h)-1; i>=0; --i ) {
158 cursor->data[i] = data[i];
159 cursor->mask[i] = mask[i] | data[i];
161 memset(cursor->save[0], 0, savelen*2);
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,
168 cursor->wm_cursor = NULL;
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.
177 void SDL_SetCursor (SDL_Cursor *cursor)
179 SDL_VideoDevice *video = current_video;
180 SDL_VideoDevice *this = current_video;
182 /* Make sure that the video subsystem has been initialized */
187 /* Prevent the event thread from moving the mouse */
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)
201 video->ShowWMCursor(this, NULL);
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;
214 SDL_cursorstate |= CURSOR_USINGSW;
215 if ( video->ShowWMCursor ) {
216 video->ShowWMCursor(this, NULL);
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);
223 SDL_DrawCursor(SDL_VideoSurface);
226 /* Erase window manager mouse (cursor not visible) */
227 if ( SDL_cursor && (SDL_cursorstate & CURSOR_USINGSW) ) {
228 SDL_EraseCursor(SDL_VideoSurface);
231 video->ShowWMCursor(this, NULL);
238 SDL_Cursor * SDL_GetCursor (void)
243 void SDL_FreeCursor (SDL_Cursor *cursor)
246 if ( cursor == SDL_cursor ) {
247 SDL_SetCursor(SDL_defcursor);
249 if ( cursor != SDL_defcursor ) {
250 SDL_VideoDevice *video = current_video;
251 SDL_VideoDevice *this = current_video;
253 if ( cursor->data ) {
256 if ( cursor->save[0] ) {
257 free(cursor->save[0]);
259 if ( video && cursor->wm_cursor ) {
260 video->FreeWMCursor(this, cursor->wm_cursor);
267 int SDL_ShowCursor (int toggle)
271 showing = (SDL_cursorstate & CURSOR_VISIBLE);
275 SDL_cursorstate |= CURSOR_VISIBLE;
277 SDL_cursorstate &= ~CURSOR_VISIBLE;
280 if ( (SDL_cursorstate & CURSOR_VISIBLE) != showing ) {
281 SDL_VideoDevice *video = current_video;
282 SDL_VideoDevice *this = current_video;
285 if ( video && video->CheckMouseMode ) {
286 video->CheckMouseMode(this);
290 /* Query current state */ ;
292 return(showing ? 1 : 0);
295 void SDL_WarpMouse (Uint16 x, Uint16 y)
297 SDL_VideoDevice *video = current_video;
298 SDL_VideoDevice *this = current_video;
300 if ( !video || !SDL_PublicSurface ) {
301 SDL_SetError("A video mode must be set before warping mouse");
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;
310 x += (this->screen->offset % this->screen->pitch) /
311 this->screen->format->BytesPerPixel;
312 y += (this->screen->offset / this->screen->pitch);
315 /* This generates a mouse motion event */
316 if ( video->WarpWMCursor ) {
317 video->WarpWMCursor(this, x, y);
319 SDL_PrivateMouseMotion(0, 0, x, y);
323 void SDL_MoveCursor(int x, int y)
325 SDL_VideoDevice *video = current_video;
327 /* Erase and update the current mouse position */
328 if ( SHOULD_DRAWCURSOR(SDL_cursorstate) ) {
329 /* Erase and redraw mouse cursor in new position */
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);
336 } else if ( video->MoveWMCursor ) {
337 video->MoveWMCursor(video, x, y);
341 /* Keep track of the current cursor colors */
342 static int palette_changed = 1;
343 static Uint32 pixels8[2];
345 void SDL_CursorPaletteChanged(void)
350 void SDL_MouseRect(SDL_Rect *area)
354 *area = SDL_cursor->area;
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;
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;
373 static void SDL_DrawCursorFast(SDL_Surface *screen, SDL_Rect *area)
375 const Uint32 pixels[2] = { 0xFFFFFFFF, 0x00000000 };
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) {
388 if ( palette_changed ) {
389 pixels8[0] = SDL_MapRGB(screen->format, 255, 255, 255);
390 pixels8[1] = SDL_MapRGB(screen->format, 0, 0, 0);
393 dst = (Uint8 *)screen->pixels +
394 (SDL_cursor->area.y+area->y)*screen->pitch +
396 dstskip = screen->pitch-area->w;
398 for ( h=area->h; h; h-- ) {
399 for ( w=area->w/8; w; w-- ) {
402 for ( i=0; i<8; ++i ) {
403 if ( maskb & 0x80 ) {
404 *dst = pixels8[datab>>7];
420 dst = (Uint16 *)screen->pixels +
421 (SDL_cursor->area.y+area->y)*screen->pitch/2 +
423 dstskip = (screen->pitch/2)-area->w;
425 for ( h=area->h; h; h-- ) {
426 for ( w=area->w/8; w; w-- ) {
429 for ( i=0; i<8; ++i ) {
430 if ( maskb & 0x80 ) {
431 *dst = pixels[datab>>7];
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;
452 for ( h=area->h; h; h-- ) {
453 for ( w=area->w/8; w; w-- ) {
456 for ( i=0; i<8; ++i ) {
457 if ( maskb & 0x80 ) {
458 memset(dst,pixels[datab>>7],3);
474 dst = (Uint32 *)screen->pixels +
475 (SDL_cursor->area.y+area->y)*screen->pitch/4 +
477 dstskip = (screen->pitch/4)-area->w;
479 for ( h=area->h; h; h-- ) {
480 for ( w=area->w/8; w; w-- ) {
483 for ( i=0; i<8; ++i ) {
484 if ( maskb & 0x80 ) {
485 *dst = pixels[datab>>7];
499 static void SDL_DrawCursorSlow(SDL_Surface *screen, SDL_Rect *area)
501 const Uint32 pixels[2] = { 0xFFFFFF, 0x000000 };
504 Uint8 *data, datab = 0;
505 Uint8 *mask, maskb = 0;
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;
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);
525 for ( h=area->h; h; h-- ) {
526 for ( x=0; x<SDL_cursor->area.w; ++x ) {
531 if ( (x >= minx) && (x < maxx) ) {
532 if ( maskb & 0x80 ) {
533 memset(dst, pixels8[datab>>7], dstbpp);
543 for ( h=area->h; h; h-- ) {
544 for ( x=0; x<SDL_cursor->area.w; ++x ) {
549 if ( (x >= minx) && (x < maxx) ) {
550 if ( maskb & 0x80 ) {
551 memset(dst, pixels[datab>>7], dstbpp);
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.
568 static void SDL_ConvertCursorSave(SDL_Surface *screen, int w, int h)
573 /* Make sure we can steal the blit mapping */
574 if ( screen->map->dst != SDL_VideoSurface ) {
578 /* Set up the blit information */
579 info.s_pixels = SDL_cursor->save[1];
583 info.d_pixels = SDL_cursor->save[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;
593 /* Run the actual software blit */
597 void SDL_DrawCursorNoLock(SDL_Surface *screen)
601 /* Get the mouse rectangle, clipped to the screen */
602 SDL_MouseRect(&area);
603 if ( (area.w == 0) || (area.h == 0) ) {
607 /* Copy mouse background */
608 { int w, h, screenbpp;
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];
617 dst = SDL_cursor->save[1];
619 src = (Uint8 *)screen->pixels + area.y * screen->pitch +
622 /* Perform the copy */
623 w = area.w*screenbpp;
628 src += screen->pitch;
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);
638 SDL_DrawCursorSlow(screen, &area);
642 void SDL_DrawCursor(SDL_Surface *screen)
644 /* Lock the screen if necessary */
645 if ( screen == NULL ) {
648 if ( SDL_MUSTLOCK(screen) ) {
649 if ( SDL_LockSurface(screen) < 0 ) {
654 SDL_DrawCursorNoLock(screen);
656 /* Unlock the screen and update if necessary */
657 if ( SDL_MUSTLOCK(screen) ) {
658 SDL_UnlockSurface(screen);
660 if ( (screen == SDL_VideoSurface) &&
661 ((screen->flags & SDL_HWSURFACE) != SDL_HWSURFACE) ) {
662 SDL_VideoDevice *video = current_video;
663 SDL_VideoDevice *this = current_video;
666 SDL_MouseRect(&area);
668 /* This can be called before a video mode is set */
669 if ( video->UpdateRects ) {
670 video->UpdateRects(this, 1, &area);
675 void SDL_EraseCursorNoLock(SDL_Surface *screen)
679 /* Get the mouse rectangle, clipped to the screen */
680 SDL_MouseRect(&area);
681 if ( (area.w == 0) || (area.h == 0) ) {
685 /* Copy mouse background */
686 { int w, h, screenbpp;
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];
695 src = SDL_cursor->save[1];
697 dst = (Uint8 *)screen->pixels + area.y * screen->pitch +
700 /* Perform the copy */
701 w = area.w*screenbpp;
706 dst += screen->pitch;
709 /* Perform pixel conversion on cursor background */
710 if ( src > SDL_cursor->save[1] ) {
711 SDL_ConvertCursorSave(screen, area.w, area.h);
716 void SDL_EraseCursor(SDL_Surface *screen)
718 /* Lock the screen if necessary */
719 if ( screen == NULL ) {
722 if ( SDL_MUSTLOCK(screen) ) {
723 if ( SDL_LockSurface(screen) < 0 ) {
728 SDL_EraseCursorNoLock(screen);
730 /* Unlock the screen and update if necessary */
731 if ( SDL_MUSTLOCK(screen) ) {
732 SDL_UnlockSurface(screen);
734 if ( (screen == SDL_VideoSurface) &&
735 ((screen->flags & SDL_HWSURFACE) != SDL_HWSURFACE) ) {
736 SDL_VideoDevice *video = current_video;
737 SDL_VideoDevice *this = current_video;
740 SDL_MouseRect(&area);
741 if ( video->UpdateRects ) {
742 video->UpdateRects(this, 1, &area);
747 /* Reset the cursor on video mode change
748 FIXME: Keep track of all cursors, and reset them all.
750 void SDL_ResetCursor(void)
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);