| 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 | |
| 17 | /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ |
| 18 | static void quit(int rc) |
| 19 | { |
| 20 | SDL_Quit(); |
| 21 | exit(rc); |
| 22 | } |
| 23 | |
| 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 SDLCALL 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 SDLCALL 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 SDLCALL 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: |
| 182 | printf("Key '%c' (keysym==%d) has been %s\n", |
| 183 | events[i].key.keysym.unicode, |
| 184 | (int) events[i].key.keysym.sym, |
| 185 | (events[i].key.state == SDL_PRESSED) ? |
| 186 | "pressed" : "released"); |
| 187 | |
| 188 | /* Allow hitting <ESC> to quit the app */ |
| 189 | if ( events[i].key.keysym.sym == SDLK_ESCAPE ) { |
| 190 | done = 1; |
| 191 | } |
| 192 | |
| 193 | /* skip events now that aren't KEYUPs... */ |
| 194 | if (events[i].key.state == SDL_PRESSED) |
| 195 | break; |
| 196 | |
| 197 | if ( events[i].key.keysym.sym == SDLK_f ) { |
| 198 | int rc = 0; |
| 199 | printf("attempting to toggle fullscreen...\n"); |
| 200 | rc = SDL_WM_ToggleFullScreen(SDL_GetVideoSurface()); |
| 201 | printf("SDL_WM_ToggleFullScreen returned %d.\n", rc); |
| 202 | } |
| 203 | |
| 204 | if ( events[i].key.keysym.sym == SDLK_g ) { |
| 205 | SDL_GrabMode m; |
| 206 | m = SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON ? |
| 207 | SDL_GRAB_OFF : SDL_GRAB_ON; |
| 208 | printf("attempting to toggle input grab to %s...\n", |
| 209 | m == SDL_GRAB_ON ? "ON" : "OFF"); |
| 210 | SDL_WM_GrabInput(m); |
| 211 | printf("attempt finished.\n"); |
| 212 | } |
| 213 | |
| 214 | break; |
| 215 | } |
| 216 | } |
| 217 | /* Give up some CPU to allow events to arrive */ |
| 218 | SDL_Delay(20); |
| 219 | } |
| 220 | return(0); |
| 221 | } |
| 222 | |
| 223 | int main(int argc, char *argv[]) |
| 224 | { |
| 225 | SDL_Surface *screen; |
| 226 | SDL_Surface *icon; |
| 227 | Uint8 *icon_mask; |
| 228 | int i, parsed; |
| 229 | Uint8 *buffer; |
| 230 | SDL_Color palette[256]; |
| 231 | Uint32 init_flags; |
| 232 | Uint8 video_bpp; |
| 233 | Uint32 video_flags; |
| 234 | SDL_Thread *mouse_thread; |
| 235 | SDL_Thread *keybd_thread; |
| 236 | |
| 237 | /* Set the options, based on command line arguments */ |
| 238 | init_flags = SDL_INIT_VIDEO; |
| 239 | video_bpp = 8; |
| 240 | video_flags = SDL_SWSURFACE; |
| 241 | parsed = 1; |
| 242 | while ( parsed ) { |
| 243 | /* If the threaded option is enabled, and the SDL library hasn't |
| 244 | been compiled with threaded events enabled, then the mouse and |
| 245 | keyboard won't respond. |
| 246 | */ |
| 247 | if ( (argc >= 2) && (strcmp(argv[1], "-threaded") == 0) ) { |
| 248 | init_flags |= SDL_INIT_EVENTTHREAD; |
| 249 | argc -= 1; |
| 250 | argv += 1; |
| 251 | printf("Running with threaded events\n"); |
| 252 | } else |
| 253 | if ( (argc >= 2) && (strcmp(argv[1], "-fullscreen") == 0) ) { |
| 254 | video_flags |= SDL_FULLSCREEN; |
| 255 | argc -= 1; |
| 256 | argv += 1; |
| 257 | } else |
| 258 | if ( (argc >= 3) && (strcmp(argv[1], "-bpp") == 0) ) { |
| 259 | video_bpp = atoi(argv[2]); |
| 260 | argc -= 2; |
| 261 | argv += 2; |
| 262 | } else { |
| 263 | parsed = 0; |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | /* Initialize SDL with the requested flags */ |
| 268 | if ( SDL_Init(init_flags) < 0 ) { |
| 269 | fprintf(stderr, |
| 270 | "Couldn't initialize SDL: %s\n", SDL_GetError()); |
| 271 | return(1); |
| 272 | } |
| 273 | |
| 274 | /* Set the icon -- this must be done before the first mode set */ |
| 275 | icon = LoadIconSurface("icon.bmp", &icon_mask); |
| 276 | if ( icon != NULL ) { |
| 277 | SDL_WM_SetIcon(icon, icon_mask); |
| 278 | } |
| 279 | if ( icon_mask != NULL ) |
| 280 | free(icon_mask); |
| 281 | |
| 282 | /* Initialize the display */ |
| 283 | screen = SDL_SetVideoMode(640, 480, video_bpp, video_flags); |
| 284 | if ( screen == NULL ) { |
| 285 | fprintf(stderr, "Couldn't set 640x480x%d video mode: %s\n", |
| 286 | video_bpp, SDL_GetError()); |
| 287 | quit(1); |
| 288 | } |
| 289 | printf("Running in %s mode\n", screen->flags & SDL_FULLSCREEN ? |
| 290 | "fullscreen" : "windowed"); |
| 291 | |
| 292 | /* Enable printable characters */ |
| 293 | SDL_EnableUNICODE(1); |
| 294 | |
| 295 | /* Set an event filter that discards everything but QUIT */ |
| 296 | SDL_SetEventFilter(FilterEvents); |
| 297 | |
| 298 | /* Create the event handling threads */ |
| 299 | mouse_thread = SDL_CreateThread(HandleMouse, NULL); |
| 300 | keybd_thread = SDL_CreateThread(HandleKeyboard, NULL); |
| 301 | |
| 302 | /* Set the surface pixels and refresh! */ |
| 303 | for ( i=0; i<256; ++i ) { |
| 304 | palette[i].r = 255-i; |
| 305 | palette[i].g = 255-i; |
| 306 | palette[i].b = 255-i; |
| 307 | } |
| 308 | SDL_SetColors(screen, palette, 0, 256); |
| 309 | if ( SDL_LockSurface(screen) < 0 ) { |
| 310 | fprintf(stderr, "Couldn't lock display surface: %s\n", |
| 311 | SDL_GetError()); |
| 312 | quit(2); |
| 313 | } |
| 314 | buffer = (Uint8 *)screen->pixels; |
| 315 | for ( i=0; i<screen->h; ++i ) { |
| 316 | memset(buffer,(i*255)/screen->h, |
| 317 | screen->w*screen->format->BytesPerPixel); |
| 318 | buffer += screen->pitch; |
| 319 | } |
| 320 | SDL_UnlockSurface(screen); |
| 321 | SDL_UpdateRect(screen, 0, 0, 0, 0); |
| 322 | |
| 323 | /* Loop, waiting for QUIT */ |
| 324 | while ( ! done ) { |
| 325 | if ( ! (init_flags & SDL_INIT_EVENTTHREAD) ) { |
| 326 | SDL_PumpEvents(); /* Needed when event thread is off */ |
| 327 | } |
| 328 | if ( SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_QUITMASK) ) { |
| 329 | done = 1; |
| 330 | } |
| 331 | /* Give up some CPU so the events can accumulate */ |
| 332 | SDL_Delay(20); |
| 333 | } |
| 334 | SDL_WaitThread(mouse_thread, NULL); |
| 335 | SDL_WaitThread(keybd_thread, NULL); |
| 336 | SDL_Quit(); |
| 337 | return(0); |
| 338 | } |