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? */ 12static int done = 0; 13 14/* Is the cursor visible? */ 15static int visible = 1; 16 17/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 18static void quit(int rc) 19{ 20 SDL_Quit(); 21 exit(rc); 22} 23 24SDL_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 80int 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 130int 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 167int 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 223int 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} 339