| |
| /* Test out the multi-threaded event handling functions */ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "SDL.h" |
| #include "SDL_thread.h" |
| |
| /* Are we done yet? */ |
| static int done = 0; |
| |
| /* Is the cursor visible? */ |
| static int visible = 1; |
| |
| /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ |
| static void quit(int rc) |
| { |
| SDL_Quit(); |
| exit(rc); |
| } |
| |
| SDL_Surface *LoadIconSurface(char *file, Uint8 **maskp) |
| { |
| SDL_Surface *icon; |
| Uint8 *pixels; |
| Uint8 *mask; |
| int mlen, i; |
| |
| *maskp = NULL; |
| |
| /* Load the icon surface */ |
| icon = SDL_LoadBMP(file); |
| if ( icon == NULL ) { |
| fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError()); |
| return(NULL); |
| } |
| |
| /* Check width and height */ |
| if ( (icon->w%8) != 0 ) { |
| fprintf(stderr, "Icon width must be a multiple of 8!\n"); |
| SDL_FreeSurface(icon); |
| return(NULL); |
| } |
| if ( icon->format->palette == NULL ) { |
| fprintf(stderr, "Icon must have a palette!\n"); |
| SDL_FreeSurface(icon); |
| return(NULL); |
| } |
| |
| /* Set the colorkey */ |
| SDL_SetColorKey(icon, SDL_SRCCOLORKEY, *((Uint8 *)icon->pixels)); |
| |
| /* Create the mask */ |
| pixels = (Uint8 *)icon->pixels; |
| printf("Transparent pixel: (%d,%d,%d)\n", |
| icon->format->palette->colors[*pixels].r, |
| icon->format->palette->colors[*pixels].g, |
| icon->format->palette->colors[*pixels].b); |
| mlen = icon->w*icon->h; |
| mask = (Uint8 *)malloc(mlen/8); |
| if ( mask == NULL ) { |
| fprintf(stderr, "Out of memory!\n"); |
| SDL_FreeSurface(icon); |
| return(NULL); |
| } |
| memset(mask, 0, mlen/8); |
| for ( i=0; i<mlen; ) { |
| if ( pixels[i] != *pixels ) |
| mask[i/8] |= 0x01; |
| ++i; |
| if ( (i%8) != 0 ) |
| mask[i/8] <<= 1; |
| } |
| *maskp = mask; |
| return(icon); |
| } |
| |
| int SDLCALL FilterEvents(const SDL_Event *event) |
| { |
| static int reallyquit = 0; |
| |
| switch (event->type) { |
| |
| case SDL_ACTIVEEVENT: |
| /* See what happened */ |
| printf("App %s ", |
| event->active.gain ? "gained" : "lost"); |
| if ( event->active.state & SDL_APPACTIVE ) |
| printf("active "); |
| if ( event->active.state & SDL_APPMOUSEFOCUS ) |
| printf("mouse "); |
| if ( event->active.state & SDL_APPINPUTFOCUS ) |
| printf("input "); |
| printf("focus\n"); |
| |
| /* See if we are iconified or restored */ |
| if ( event->active.state & SDL_APPACTIVE ) { |
| printf("App has been %s\n", |
| event->active.gain ? |
| "restored" : "iconified"); |
| } |
| return(0); |
| |
| /* This is important! Queue it if we want to quit. */ |
| case SDL_QUIT: |
| if ( ! reallyquit ) { |
| reallyquit = 1; |
| printf("Quit requested\n"); |
| return(0); |
| } |
| printf("Quit demanded\n"); |
| return(1); |
| |
| /* Mouse and keyboard events go to threads */ |
| case SDL_MOUSEMOTION: |
| case SDL_MOUSEBUTTONDOWN: |
| case SDL_MOUSEBUTTONUP: |
| case SDL_KEYDOWN: |
| case SDL_KEYUP: |
| return(1); |
| |
| /* Drop all other events */ |
| default: |
| return(0); |
| } |
| } |
| |
| int SDLCALL HandleMouse(void *unused) |
| { |
| SDL_Event events[10]; |
| int i, found; |
| Uint32 mask; |
| |
| /* Handle mouse events here */ |
| mask = (SDL_MOUSEMOTIONMASK|SDL_MOUSEBUTTONDOWNMASK|SDL_MOUSEBUTTONUPMASK); |
| while ( ! done ) { |
| found = SDL_PeepEvents(events, 10, SDL_GETEVENT, mask); |
| for ( i=0; i<found; ++i ) { |
| switch(events[i].type) { |
| /* We want to toggle visibility on buttonpress */ |
| case SDL_MOUSEBUTTONDOWN: |
| case SDL_MOUSEBUTTONUP: |
| if ( events[i].button.state == SDL_PRESSED ) { |
| visible = !visible; |
| SDL_ShowCursor(visible); |
| } |
| printf("Mouse button %d has been %s\n", |
| events[i].button.button, |
| (events[i].button.state == SDL_PRESSED) ? |
| "pressed" : "released"); |
| break; |
| /* Show relative mouse motion */ |
| case SDL_MOUSEMOTION: |
| printf("Mouse relative motion: {%d,%d}\n", |
| events[i].motion.xrel, events[i].motion.yrel); |
| break; |
| } |
| } |
| /* Give up some CPU to allow events to arrive */ |
| SDL_Delay(20); |
| } |
| return(0); |
| } |
| |
| int SDLCALL HandleKeyboard(void *unused) |
| { |
| SDL_Event events[10]; |
| int i, found; |
| Uint32 mask; |
| |
| /* Handle mouse events here */ |
| mask = (SDL_KEYDOWNMASK|SDL_KEYUPMASK); |
| while ( ! done ) { |
| found = SDL_PeepEvents(events, 10, SDL_GETEVENT, mask); |
| for ( i=0; i<found; ++i ) { |
| switch(events[i].type) { |
| /* We want to toggle visibility on buttonpress */ |
| case SDL_KEYDOWN: |
| case SDL_KEYUP: |
| printf("Key '%c' (keysym==%d) has been %s\n", |
| events[i].key.keysym.unicode, |
| (int) events[i].key.keysym.sym, |
| (events[i].key.state == SDL_PRESSED) ? |
| "pressed" : "released"); |
| |
| /* Allow hitting <ESC> to quit the app */ |
| if ( events[i].key.keysym.sym == SDLK_ESCAPE ) { |
| done = 1; |
| } |
| |
| /* skip events now that aren't KEYUPs... */ |
| if (events[i].key.state == SDL_PRESSED) |
| break; |
| |
| if ( events[i].key.keysym.sym == SDLK_f ) { |
| int rc = 0; |
| printf("attempting to toggle fullscreen...\n"); |
| rc = SDL_WM_ToggleFullScreen(SDL_GetVideoSurface()); |
| printf("SDL_WM_ToggleFullScreen returned %d.\n", rc); |
| } |
| |
| if ( events[i].key.keysym.sym == SDLK_g ) { |
| SDL_GrabMode m; |
| m = SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON ? |
| SDL_GRAB_OFF : SDL_GRAB_ON; |
| printf("attempting to toggle input grab to %s...\n", |
| m == SDL_GRAB_ON ? "ON" : "OFF"); |
| SDL_WM_GrabInput(m); |
| printf("attempt finished.\n"); |
| } |
| |
| break; |
| } |
| } |
| /* Give up some CPU to allow events to arrive */ |
| SDL_Delay(20); |
| } |
| return(0); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| SDL_Surface *screen; |
| SDL_Surface *icon; |
| Uint8 *icon_mask; |
| int i, parsed; |
| Uint8 *buffer; |
| SDL_Color palette[256]; |
| Uint32 init_flags; |
| Uint8 video_bpp; |
| Uint32 video_flags; |
| SDL_Thread *mouse_thread; |
| SDL_Thread *keybd_thread; |
| |
| /* Set the options, based on command line arguments */ |
| init_flags = SDL_INIT_VIDEO; |
| video_bpp = 8; |
| video_flags = SDL_SWSURFACE; |
| parsed = 1; |
| while ( parsed ) { |
| /* If the threaded option is enabled, and the SDL library hasn't |
| been compiled with threaded events enabled, then the mouse and |
| keyboard won't respond. |
| */ |
| if ( (argc >= 2) && (strcmp(argv[1], "-threaded") == 0) ) { |
| init_flags |= SDL_INIT_EVENTTHREAD; |
| argc -= 1; |
| argv += 1; |
| printf("Running with threaded events\n"); |
| } else |
| if ( (argc >= 2) && (strcmp(argv[1], "-fullscreen") == 0) ) { |
| video_flags |= SDL_FULLSCREEN; |
| argc -= 1; |
| argv += 1; |
| } else |
| if ( (argc >= 3) && (strcmp(argv[1], "-bpp") == 0) ) { |
| video_bpp = atoi(argv[2]); |
| argc -= 2; |
| argv += 2; |
| } else { |
| parsed = 0; |
| } |
| } |
| |
| /* Initialize SDL with the requested flags */ |
| if ( SDL_Init(init_flags) < 0 ) { |
| fprintf(stderr, |
| "Couldn't initialize SDL: %s\n", SDL_GetError()); |
| return(1); |
| } |
| |
| /* Set the icon -- this must be done before the first mode set */ |
| icon = LoadIconSurface("icon.bmp", &icon_mask); |
| if ( icon != NULL ) { |
| SDL_WM_SetIcon(icon, icon_mask); |
| } |
| if ( icon_mask != NULL ) |
| free(icon_mask); |
| |
| /* Initialize the display */ |
| screen = SDL_SetVideoMode(640, 480, video_bpp, video_flags); |
| if ( screen == NULL ) { |
| fprintf(stderr, "Couldn't set 640x480x%d video mode: %s\n", |
| video_bpp, SDL_GetError()); |
| quit(1); |
| } |
| printf("Running in %s mode\n", screen->flags & SDL_FULLSCREEN ? |
| "fullscreen" : "windowed"); |
| |
| /* Enable printable characters */ |
| SDL_EnableUNICODE(1); |
| |
| /* Set an event filter that discards everything but QUIT */ |
| SDL_SetEventFilter(FilterEvents); |
| |
| /* Create the event handling threads */ |
| mouse_thread = SDL_CreateThread(HandleMouse, NULL); |
| keybd_thread = SDL_CreateThread(HandleKeyboard, NULL); |
| |
| /* Set the surface pixels and refresh! */ |
| for ( i=0; i<256; ++i ) { |
| palette[i].r = 255-i; |
| palette[i].g = 255-i; |
| palette[i].b = 255-i; |
| } |
| SDL_SetColors(screen, palette, 0, 256); |
| if ( SDL_LockSurface(screen) < 0 ) { |
| fprintf(stderr, "Couldn't lock display surface: %s\n", |
| SDL_GetError()); |
| quit(2); |
| } |
| buffer = (Uint8 *)screen->pixels; |
| for ( i=0; i<screen->h; ++i ) { |
| memset(buffer,(i*255)/screen->h, |
| screen->w*screen->format->BytesPerPixel); |
| buffer += screen->pitch; |
| } |
| SDL_UnlockSurface(screen); |
| SDL_UpdateRect(screen, 0, 0, 0, 0); |
| |
| /* Loop, waiting for QUIT */ |
| while ( ! done ) { |
| if ( ! (init_flags & SDL_INIT_EVENTTHREAD) ) { |
| SDL_PumpEvents(); /* Needed when event thread is off */ |
| } |
| if ( SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_QUITMASK) ) { |
| done = 1; |
| } |
| /* Give up some CPU so the events can accumulate */ |
| SDL_Delay(20); |
| } |
| SDL_WaitThread(mouse_thread, NULL); |
| SDL_WaitThread(keybd_thread, NULL); |
| SDL_Quit(); |
| return(0); |
| } |