Mercurial > sdl-ios-xcode
annotate src/video/SDL_cursor.c @ 1192:54aa9aa32327
To: sdl@libsdl.org
From: Christian Walther <cwalther@gmx.ch>
Date: Fri, 18 Nov 2005 23:39:02 +0100
Subject: [SDL] Mouse position bugs on Mac OS X
The attached patch fixes a few bugs in SDL related to the mouse position
in windowed mode on Mac OS X, reproduced using the attached minimal test
program - at least here on 10.3.9, with SDL CVS from today. Could anyone
test whether the bugs exist and are fixed by the patch on 10.2 and 10.4?
1. When using OpenGL, the vertical mouse positions obtained through
events or SDL_GetMouseState() are off by one.
2. When using OpenGL, SDL_WarpMouse() inverts the y coordinate.
3. Clicks on the topmost pixel row of the window are not recognized.
1 and 2 do not occur in non-OpenGL mode, while 3 does. All three only
occur in windowed mode, not in fullscreen.
The cause for 1 and 3 is that in Cocoa, "the location of the mouse"
seems to be defined as "the location of the top left corner of the mouse
pointer's hot pixel" (this is not documented, it's just what I found out
here), which together with the fact that Cocoa's usual y coordinates
start at the bottom and increase upwards means that the y coordinate of
the mouse runs from 1 to h, not from 0 to h-1, in a window of height h.
If it does work on 10.2 and 10.4 (I'll try to test it as soon as I can,
but at the moment all I have at hand is 10.3.9), can this be applied to
the CVS?
-Christian
To: sdl@libsdl.org
From: Christian Walther <cwalther@gmx.ch>
Date: Mon, 28 Nov 2005 10:41:51 +0100
Subject: [SDL] Re: Mouse position bugs on Mac OS X
I wrote:
> I'll try to test it as soon as I can, but at the moment all I have at hand is 10.3.9
So, here are the results of my tests (with patched and unpatched
frameworks compiled with Xcode 1.5 (gcc 3.3) on 10.3.9):
On 10.1.5, my test program doesn't run because of "Undefined symbols:
SDL undefined reference to _CGMainDisplayID expected to be defined in
Carbon". I guess not supporting 10.1 was a deliberate decision then and
that's OK with me.
On 10.2.8, 10.3.9, and 10.4.0, the bugs exist as described in my
original post and are fixed by my patch. That is, there is no difference
between pre/post 10.3 and the patched version works correctly in all
combinations of GL/non-GL and windowed/fullscreen.
I therefore recommend the patch for inclusion.
-Christian
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Mon, 28 Nov 2005 13:58:26 +0000 |
parents | 96ef83467667 |
children | f418917e0b7a |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
769
b8d311d90021
Updated copyright information for 2004 (Happy New Year!)
Sam Lantinga <slouken@libsdl.org>
parents:
595
diff
changeset
|
3 Copyright (C) 1997-2004 Sam Lantinga |
0 | 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 | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
113
diff
changeset
|
20 slouken@libsdl.org |
0 | 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 */ | |
1140
af8b0f9ac2f4
iPod Linux framebuffer support.
Ryan C. Gordon <icculus@icculus.org>
parents:
769
diff
changeset
|
77 #ifndef IPOD |
0 | 78 SDL_cursorstate = CURSOR_VISIBLE; |
1140
af8b0f9ac2f4
iPod Linux framebuffer support.
Ryan C. Gordon <icculus@icculus.org>
parents:
769
diff
changeset
|
79 #endif |
0 | 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 ) { | |
77
1e7e61b9b0f9
Don't crash if freeing a cursor after quit...
Sam Lantinga <slouken@lokigames.com>
parents:
1
diff
changeset
|
250 SDL_VideoDevice *video = current_video; |
1e7e61b9b0f9
Don't crash if freeing a cursor after quit...
Sam Lantinga <slouken@lokigames.com>
parents:
1
diff
changeset
|
251 SDL_VideoDevice *this = current_video; |
1e7e61b9b0f9
Don't crash if freeing a cursor after quit...
Sam Lantinga <slouken@lokigames.com>
parents:
1
diff
changeset
|
252 |
0 | 253 if ( cursor->data ) { |
254 free(cursor->data); | |
255 } | |
256 if ( cursor->save[0] ) { | |
257 free(cursor->save[0]); | |
258 } | |
77
1e7e61b9b0f9
Don't crash if freeing a cursor after quit...
Sam Lantinga <slouken@lokigames.com>
parents:
1
diff
changeset
|
259 if ( video && cursor->wm_cursor ) { |
0 | 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 | |
595
591b438ab94a
Don't warp the mouse when a video mode hasn't been set
Sam Lantinga <slouken@libsdl.org>
parents:
527
diff
changeset
|
300 if ( !video || !SDL_PublicSurface ) { |
591b438ab94a
Don't warp the mouse when a video mode hasn't been set
Sam Lantinga <slouken@libsdl.org>
parents:
527
diff
changeset
|
301 SDL_SetError("A video mode must be set before warping mouse"); |
591b438ab94a
Don't warp the mouse when a video mode hasn't been set
Sam Lantinga <slouken@libsdl.org>
parents:
527
diff
changeset
|
302 return; |
591b438ab94a
Don't warp the mouse when a video mode hasn't been set
Sam Lantinga <slouken@libsdl.org>
parents:
527
diff
changeset
|
303 } |
591b438ab94a
Don't warp the mouse when a video mode hasn't been set
Sam Lantinga <slouken@libsdl.org>
parents:
527
diff
changeset
|
304 |
527
5c74ac147358
Fixed mouse warp position bug with offset video modes
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
305 /* If we have an offset video mode, offset the mouse coordinates */ |
1163
96ef83467667
Prevent division-by-zero in WarpMouse if surface's pitch is zero (a GL surface?).
Ryan C. Gordon <icculus@icculus.org>
parents:
1140
diff
changeset
|
306 if (this->screen->pitch == 0) { |
96ef83467667
Prevent division-by-zero in WarpMouse if surface's pitch is zero (a GL surface?).
Ryan C. Gordon <icculus@icculus.org>
parents:
1140
diff
changeset
|
307 x += this->screen->offset / this->screen->format->BytesPerPixel; |
96ef83467667
Prevent division-by-zero in WarpMouse if surface's pitch is zero (a GL surface?).
Ryan C. Gordon <icculus@icculus.org>
parents:
1140
diff
changeset
|
308 y += this->screen->offset; |
96ef83467667
Prevent division-by-zero in WarpMouse if surface's pitch is zero (a GL surface?).
Ryan C. Gordon <icculus@icculus.org>
parents:
1140
diff
changeset
|
309 } else { |
96ef83467667
Prevent division-by-zero in WarpMouse if surface's pitch is zero (a GL surface?).
Ryan C. Gordon <icculus@icculus.org>
parents:
1140
diff
changeset
|
310 x += (this->screen->offset % this->screen->pitch) / |
96ef83467667
Prevent division-by-zero in WarpMouse if surface's pitch is zero (a GL surface?).
Ryan C. Gordon <icculus@icculus.org>
parents:
1140
diff
changeset
|
311 this->screen->format->BytesPerPixel; |
96ef83467667
Prevent division-by-zero in WarpMouse if surface's pitch is zero (a GL surface?).
Ryan C. Gordon <icculus@icculus.org>
parents:
1140
diff
changeset
|
312 y += (this->screen->offset / this->screen->pitch); |
96ef83467667
Prevent division-by-zero in WarpMouse if surface's pitch is zero (a GL surface?).
Ryan C. Gordon <icculus@icculus.org>
parents:
1140
diff
changeset
|
313 } |
527
5c74ac147358
Fixed mouse warp position bug with offset video modes
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
314 |
0 | 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 ) { | |
113
e21ac1dd30f1
Fixed crash if mouse is outside of the screen bounds for some reason
Sam Lantinga <slouken@lokigames.com>
parents:
77
diff
changeset
|
365 area->w = area->w < clip_diff ? 0 : area->w-clip_diff; |
0 | 366 } |
367 clip_diff = (area->y+area->h)-SDL_VideoSurface->h; | |
368 if ( clip_diff > 0 ) { | |
113
e21ac1dd30f1
Fixed crash if mouse is outside of the screen bounds for some reason
Sam Lantinga <slouken@lokigames.com>
parents:
77
diff
changeset
|
369 area->h = area->h < clip_diff ? 0 : area->h-clip_diff; |
0 | 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); | |
1
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
741 if ( video->UpdateRects ) { |
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
742 video->UpdateRects(this, 1, &area); |
cf2af46e9e2a
Changes since SDL 1.2.0 release
Sam Lantinga <slouken@lokigames.com>
parents:
0
diff
changeset
|
743 } |
0 | 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 } |