view test/threadwin.c @ 1663:11775724e3fe SDL-1.3

fine tuning indent output
author Sam Lantinga <slouken@libsdl.org>
date Sun, 28 May 2006 13:29:03 +0000
parents 782fd950bd46
children 4da1ee79c9af
line wrap: on
line source


/* 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' has been %s\n",
                        events[i].key.keysym.unicode,
                        (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);
}