Mercurial > sdl-ios-xcode
annotate test/threadwin.c @ 1629:ef4a796e7f24
Fixed bug #55
From Christian Walther:
When writing my patch for #12, I ended up doing all sorts of changes to the way
application/window activating/deactivating is handled in the Quartz backend,
resulting in the attached patch. It does make the code a bit cleaner IMHO, but
as it might be regarded as a case of "if it ain't broken, don't fix it" I'd
like to hear other people's opinion about it. Please shout if some change
strikes you as unnecessary or wrong, and I'll explain the reasons behind it. As
far as I tested it, it does not introduce any new bugs, but I may well have
missed some.
- The most fundamental change (that triggered most of the others) is irrelevant
for the usual single-window SDL applications, it only affects the people who
are crazy enough to display other Cocoa windows alongside the SDL window (I'm
actually doing this currently, although the additional window only displays
debugging info and won't be present in the final product): Before, some things
were done on the application becoming active, some on the window becoming key,
and some on the window becoming main. Conceptually, all these actions belong to
the window becoming key, so that's what I implemented. However, since in a
single-window application these three events always happen together, the
previous implementation "ain't broken".
- This slightly changed the meaning of the SDL_APPMOUSEFOCUS flag from
SDL_GetAppState(): Before, it meant "window is main and mouse is inside window
(or mode is fullscreen)". Now, it means "window is key and mouse is inside
window (or mode is fullscreen)". It makes more sense to me that way. (See
http://developer.apple.com/documentation/Cocoa/Conceptual/WinPanel/Concepts/ChangingMainKeyWindow.html
for a discussion of what key and main windows are.) The other two flags are
unchanged: SDL_APPACTIVE = application is not hidden and window is not
minimized, SDL_APPINPUTFOCUS = window is key (or mode is fullscreen).
- As a side effect, the reorganization fixes the following two issues (and
maybe others) (but they could also be fixed in less invasive ways):
* A regression that was introduced in revision 1.42 of SDL_QuartzVideo.m
(http://libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzVideo.m.diff?r1=1.41&r2=1.42)
(from half-desirable to undesirable behavior):
Situation: While in windowed mode, hide the cursor using
SDL_ShowCursor(SDL_DISABLE), move the mouse outside of the window so that the
cursor becomes visible again, and SDL_SetVideoMode() to a fullscreen mode.
What happened before revision 1.42: The cursor is visible, but becomes
invisible as soon as the mouse is moved (half-desirable).
What happens in revision 1.42 and after (including current CVS): The cursor is
visible and stays visible (undesirable).
What happens after my patch: The cursor is invisible from the beginning
(desirable).
* When the cursor is hidden and grabbed, switch away from the application using
cmd-tab (which ungrabs and makes the cursor visible), move the cursor outside
of the SDL window, then cmd-tab back to the application. In 1.2.8 and in the
current CVS, the cursor is re-grabbed, but it stays visible (immovable in the
middle of the window). With my patch, the cursor is correctly re-grabbed and
hidden. (For some reason, it still doesn't work correctly if you switch back to
the application using the dock instead of cmd-tab. I haven't been able to
figure out why. I can step over [NSCursor hide] being called in the debugger,
but it seems to have no effect.)
- The patch includes my patch for #12 (it was easier to obtain using cvs diff
that way). If you apply both of them, you will end up with 6 duplicate lines in
SDL_QuartzEvents.m.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 13 Apr 2006 14:17:48 +0000 |
parents | be9c9c8f6d53 |
children | 14717b52abc0 |
rev | line source |
---|---|
0 | 1 |
2 /* Test out the multi-threaded event handling functions */ | |
3 | |
4 #include <stdlib.h> | |
5 #include <stdio.h> | |
6 #include <string.h> | |
7 | |
8 #include "SDL.h" | |
9 #include "SDL_thread.h" | |
10 | |
11 /* Are we done yet? */ | |
12 static int done = 0; | |
13 | |
14 /* Is the cursor visible? */ | |
15 static int visible = 1; | |
16 | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
17 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
18 static void quit(int rc) |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
19 { |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
20 SDL_Quit(); |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
21 exit(rc); |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
22 } |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
23 |
0 | 24 SDL_Surface *LoadIconSurface(char *file, Uint8 **maskp) |
25 { | |
26 SDL_Surface *icon; | |
27 Uint8 *pixels; | |
28 Uint8 *mask; | |
29 int mlen, i; | |
30 | |
31 *maskp = NULL; | |
32 | |
33 /* Load the icon surface */ | |
34 icon = SDL_LoadBMP(file); | |
35 if ( icon == NULL ) { | |
36 fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError()); | |
37 return(NULL); | |
38 } | |
39 | |
40 /* Check width and height */ | |
41 if ( (icon->w%8) != 0 ) { | |
42 fprintf(stderr, "Icon width must be a multiple of 8!\n"); | |
43 SDL_FreeSurface(icon); | |
44 return(NULL); | |
45 } | |
46 if ( icon->format->palette == NULL ) { | |
47 fprintf(stderr, "Icon must have a palette!\n"); | |
48 SDL_FreeSurface(icon); | |
49 return(NULL); | |
50 } | |
51 | |
52 /* Set the colorkey */ | |
53 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, *((Uint8 *)icon->pixels)); | |
54 | |
55 /* Create the mask */ | |
56 pixels = (Uint8 *)icon->pixels; | |
57 printf("Transparent pixel: (%d,%d,%d)\n", | |
58 icon->format->palette->colors[*pixels].r, | |
59 icon->format->palette->colors[*pixels].g, | |
60 icon->format->palette->colors[*pixels].b); | |
61 mlen = icon->w*icon->h; | |
62 mask = (Uint8 *)malloc(mlen/8); | |
63 if ( mask == NULL ) { | |
64 fprintf(stderr, "Out of memory!\n"); | |
65 SDL_FreeSurface(icon); | |
66 return(NULL); | |
67 } | |
68 memset(mask, 0, mlen/8); | |
69 for ( i=0; i<mlen; ) { | |
70 if ( pixels[i] != *pixels ) | |
71 mask[i/8] |= 0x01; | |
72 ++i; | |
73 if ( (i%8) != 0 ) | |
74 mask[i/8] <<= 1; | |
75 } | |
76 *maskp = mask; | |
77 return(icon); | |
78 } | |
79 | |
80 int FilterEvents(const SDL_Event *event) | |
81 { | |
82 static int reallyquit = 0; | |
83 | |
84 switch (event->type) { | |
85 | |
86 case SDL_ACTIVEEVENT: | |
87 /* See what happened */ | |
88 printf("App %s ", | |
89 event->active.gain ? "gained" : "lost"); | |
90 if ( event->active.state & SDL_APPACTIVE ) | |
91 printf("active "); | |
92 if ( event->active.state & SDL_APPMOUSEFOCUS ) | |
93 printf("mouse "); | |
94 if ( event->active.state & SDL_APPINPUTFOCUS ) | |
95 printf("input "); | |
96 printf("focus\n"); | |
97 | |
98 /* See if we are iconified or restored */ | |
99 if ( event->active.state & SDL_APPACTIVE ) { | |
100 printf("App has been %s\n", | |
101 event->active.gain ? | |
102 "restored" : "iconified"); | |
103 } | |
104 return(0); | |
105 | |
106 /* This is important! Queue it if we want to quit. */ | |
107 case SDL_QUIT: | |
108 if ( ! reallyquit ) { | |
109 reallyquit = 1; | |
110 printf("Quit requested\n"); | |
111 return(0); | |
112 } | |
113 printf("Quit demanded\n"); | |
114 return(1); | |
115 | |
116 /* Mouse and keyboard events go to threads */ | |
117 case SDL_MOUSEMOTION: | |
118 case SDL_MOUSEBUTTONDOWN: | |
119 case SDL_MOUSEBUTTONUP: | |
120 case SDL_KEYDOWN: | |
121 case SDL_KEYUP: | |
122 return(1); | |
123 | |
124 /* Drop all other events */ | |
125 default: | |
126 return(0); | |
127 } | |
128 } | |
129 | |
130 int HandleMouse(void *unused) | |
131 { | |
132 SDL_Event events[10]; | |
133 int i, found; | |
134 Uint32 mask; | |
135 | |
136 /* Handle mouse events here */ | |
137 mask = (SDL_MOUSEMOTIONMASK|SDL_MOUSEBUTTONDOWNMASK|SDL_MOUSEBUTTONUPMASK); | |
138 while ( ! done ) { | |
139 found = SDL_PeepEvents(events, 10, SDL_GETEVENT, mask); | |
140 for ( i=0; i<found; ++i ) { | |
141 switch(events[i].type) { | |
142 /* We want to toggle visibility on buttonpress */ | |
143 case SDL_MOUSEBUTTONDOWN: | |
144 case SDL_MOUSEBUTTONUP: | |
145 if ( events[i].button.state == SDL_PRESSED ) { | |
146 visible = !visible; | |
147 SDL_ShowCursor(visible); | |
148 } | |
149 printf("Mouse button %d has been %s\n", | |
150 events[i].button.button, | |
151 (events[i].button.state == SDL_PRESSED) ? | |
152 "pressed" : "released"); | |
153 break; | |
154 /* Show relative mouse motion */ | |
155 case SDL_MOUSEMOTION: | |
156 printf("Mouse relative motion: {%d,%d}\n", | |
157 events[i].motion.xrel, events[i].motion.yrel); | |
158 break; | |
159 } | |
160 } | |
161 /* Give up some CPU to allow events to arrive */ | |
162 SDL_Delay(20); | |
163 } | |
164 return(0); | |
165 } | |
166 | |
167 int HandleKeyboard(void *unused) | |
168 { | |
169 SDL_Event events[10]; | |
170 int i, found; | |
171 Uint32 mask; | |
172 | |
173 /* Handle mouse events here */ | |
174 mask = (SDL_KEYDOWNMASK|SDL_KEYUPMASK); | |
175 while ( ! done ) { | |
176 found = SDL_PeepEvents(events, 10, SDL_GETEVENT, mask); | |
177 for ( i=0; i<found; ++i ) { | |
178 switch(events[i].type) { | |
179 /* We want to toggle visibility on buttonpress */ | |
180 case SDL_KEYDOWN: | |
181 case SDL_KEYUP: | |
562
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
182 printf("Key '%c' has been %s\n", |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
183 events[i].key.keysym.unicode, |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
184 (events[i].key.state == SDL_PRESSED) ? |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
185 "pressed" : "released"); |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
186 |
0 | 187 /* Allow hitting <ESC> to quit the app */ |
188 if ( events[i].key.keysym.sym == SDLK_ESCAPE ) { | |
189 done = 1; | |
190 } | |
562
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
191 |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
192 /* skip events now that aren't KEYUPs... */ |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
193 if (events[i].key.state == SDL_PRESSED) |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
194 break; |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
195 |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
196 if ( events[i].key.keysym.sym == SDLK_f ) { |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
197 int rc = 0; |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
198 printf("attempting to toggle fullscreen...\n"); |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
199 rc = SDL_WM_ToggleFullScreen(SDL_GetVideoSurface()); |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
200 printf("SDL_WM_ToggleFullScreen returned %d.\n", rc); |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
201 } |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
202 |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
203 if ( events[i].key.keysym.sym == SDLK_g ) { |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
204 SDL_GrabMode m; |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
205 m = SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON ? |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
206 SDL_GRAB_OFF : SDL_GRAB_ON; |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
207 printf("attempting to toggle input grab to %s...\n", |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
208 m == SDL_GRAB_ON ? "ON" : "OFF"); |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
209 SDL_WM_GrabInput(m); |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
210 printf("attempt finished.\n"); |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
211 } |
cb40b26523a5
Added some code to toggle fullscreen and input grab for testing... --ryan.
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
212 |
0 | 213 break; |
214 } | |
215 } | |
216 /* Give up some CPU to allow events to arrive */ | |
217 SDL_Delay(20); | |
218 } | |
219 return(0); | |
220 } | |
221 | |
222 int main(int argc, char *argv[]) | |
223 { | |
224 SDL_Surface *screen; | |
225 SDL_Surface *icon; | |
226 Uint8 *icon_mask; | |
227 int i, parsed; | |
228 Uint8 *buffer; | |
229 SDL_Color palette[256]; | |
230 Uint32 init_flags; | |
231 Uint8 video_bpp; | |
232 Uint32 video_flags; | |
233 SDL_Thread *mouse_thread; | |
234 SDL_Thread *keybd_thread; | |
235 | |
236 /* Set the options, based on command line arguments */ | |
237 init_flags = SDL_INIT_VIDEO; | |
238 video_bpp = 8; | |
239 video_flags = SDL_SWSURFACE; | |
240 parsed = 1; | |
241 while ( parsed ) { | |
242 /* If the threaded option is enabled, and the SDL library hasn't | |
243 been compiled with threaded events enabled, then the mouse and | |
244 keyboard won't respond. | |
245 */ | |
246 if ( (argc >= 2) && (strcmp(argv[1], "-threaded") == 0) ) { | |
247 init_flags |= SDL_INIT_EVENTTHREAD; | |
248 argc -= 1; | |
249 argv += 1; | |
250 printf("Running with threaded events\n"); | |
251 } else | |
252 if ( (argc >= 2) && (strcmp(argv[1], "-fullscreen") == 0) ) { | |
253 video_flags |= SDL_FULLSCREEN; | |
254 argc -= 1; | |
255 argv += 1; | |
256 } else | |
257 if ( (argc >= 3) && (strcmp(argv[1], "-bpp") == 0) ) { | |
258 video_bpp = atoi(argv[2]); | |
259 argc -= 2; | |
260 argv += 2; | |
261 } else { | |
262 parsed = 0; | |
263 } | |
264 } | |
265 | |
266 /* Initialize SDL with the requested flags */ | |
267 if ( SDL_Init(init_flags) < 0 ) { | |
268 fprintf(stderr, | |
269 "Couldn't initialize SDL: %s\n", SDL_GetError()); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
270 return(1); |
0 | 271 } |
272 | |
273 /* Set the icon -- this must be done before the first mode set */ | |
274 icon = LoadIconSurface("icon.bmp", &icon_mask); | |
275 if ( icon != NULL ) { | |
276 SDL_WM_SetIcon(icon, icon_mask); | |
277 } | |
278 if ( icon_mask != NULL ) | |
279 free(icon_mask); | |
280 | |
281 /* Initialize the display */ | |
282 screen = SDL_SetVideoMode(640, 480, video_bpp, video_flags); | |
283 if ( screen == NULL ) { | |
284 fprintf(stderr, "Couldn't set 640x480x%d video mode: %s\n", | |
285 video_bpp, SDL_GetError()); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
286 quit(1); |
0 | 287 } |
288 printf("Running in %s mode\n", screen->flags & SDL_FULLSCREEN ? | |
289 "fullscreen" : "windowed"); | |
290 | |
291 /* Enable printable characters */ | |
292 SDL_EnableUNICODE(1); | |
293 | |
294 /* Set an event filter that discards everything but QUIT */ | |
295 SDL_SetEventFilter(FilterEvents); | |
296 | |
297 /* Create the event handling threads */ | |
298 mouse_thread = SDL_CreateThread(HandleMouse, NULL); | |
299 keybd_thread = SDL_CreateThread(HandleKeyboard, NULL); | |
300 | |
301 /* Set the surface pixels and refresh! */ | |
302 for ( i=0; i<256; ++i ) { | |
303 palette[i].r = 255-i; | |
304 palette[i].g = 255-i; | |
305 palette[i].b = 255-i; | |
306 } | |
307 SDL_SetColors(screen, palette, 0, 256); | |
308 if ( SDL_LockSurface(screen) < 0 ) { | |
309 fprintf(stderr, "Couldn't lock display surface: %s\n", | |
310 SDL_GetError()); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
311 quit(2); |
0 | 312 } |
313 buffer = (Uint8 *)screen->pixels; | |
314 for ( i=0; i<screen->h; ++i ) { | |
315 memset(buffer,(i*255)/screen->h, | |
316 screen->w*screen->format->BytesPerPixel); | |
317 buffer += screen->pitch; | |
318 } | |
319 SDL_UnlockSurface(screen); | |
320 SDL_UpdateRect(screen, 0, 0, 0, 0); | |
321 | |
322 /* Loop, waiting for QUIT */ | |
323 while ( ! done ) { | |
324 if ( ! (init_flags & SDL_INIT_EVENTTHREAD) ) { | |
325 SDL_PumpEvents(); /* Needed when event thread is off */ | |
326 } | |
327 if ( SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_QUITMASK) ) { | |
328 done = 1; | |
329 } | |
330 /* Give up some CPU so the events can accumulate */ | |
331 SDL_Delay(20); | |
332 } | |
333 SDL_WaitThread(mouse_thread, NULL); | |
334 SDL_WaitThread(keybd_thread, NULL); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
562
diff
changeset
|
335 SDL_Quit(); |
0 | 336 return(0); |
337 } |