Home | History | Annotate | Download | only in test
      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 }
    339