test/threadwin.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
child 1712 931d111e737a
permissions -rw-r--r--
more tweaking indent options
slouken@0
     1
slouken@0
     2
/* Test out the multi-threaded event handling functions */
slouken@0
     3
slouken@0
     4
#include <stdlib.h>
slouken@0
     5
#include <stdio.h>
slouken@0
     6
#include <string.h>
slouken@0
     7
slouken@0
     8
#include "SDL.h"
slouken@0
     9
#include "SDL_thread.h"
slouken@0
    10
slouken@0
    11
/* Are we done yet? */
slouken@0
    12
static int done = 0;
slouken@0
    13
slouken@0
    14
/* Is the cursor visible? */
slouken@0
    15
static int visible = 1;
slouken@0
    16
icculus@1151
    17
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
slouken@1662
    18
static void
slouken@1668
    19
quit(int rc)
icculus@1151
    20
{
slouken@1668
    21
    SDL_Quit();
slouken@1668
    22
    exit(rc);
icculus@1151
    23
}
icculus@1151
    24
slouken@1662
    25
SDL_Surface *
slouken@1668
    26
LoadIconSurface(char *file, Uint8 ** maskp)
slouken@0
    27
{
slouken@1662
    28
    SDL_Surface *icon;
slouken@1662
    29
    Uint8 *pixels;
slouken@1662
    30
    Uint8 *mask;
slouken@1662
    31
    int mlen, i;
slouken@0
    32
slouken@1662
    33
    *maskp = NULL;
slouken@0
    34
slouken@1662
    35
    /* Load the icon surface */
slouken@1668
    36
    icon = SDL_LoadBMP(file);
slouken@1662
    37
    if (icon == NULL) {
slouken@1668
    38
        fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError());
slouken@1662
    39
        return (NULL);
slouken@1662
    40
    }
slouken@0
    41
slouken@1662
    42
    /* Check width and height */
slouken@1662
    43
    if ((icon->w % 8) != 0) {
slouken@1668
    44
        fprintf(stderr, "Icon width must be a multiple of 8!\n");
slouken@1668
    45
        SDL_FreeSurface(icon);
slouken@1662
    46
        return (NULL);
slouken@1662
    47
    }
slouken@1662
    48
    if (icon->format->palette == NULL) {
slouken@1668
    49
        fprintf(stderr, "Icon must have a palette!\n");
slouken@1668
    50
        SDL_FreeSurface(icon);
slouken@1662
    51
        return (NULL);
slouken@1662
    52
    }
slouken@0
    53
slouken@1662
    54
    /* Set the colorkey */
slouken@1668
    55
    SDL_SetColorKey(icon, SDL_SRCCOLORKEY, *((Uint8 *) icon->pixels));
slouken@0
    56
slouken@1662
    57
    /* Create the mask */
slouken@1662
    58
    pixels = (Uint8 *) icon->pixels;
slouken@1668
    59
    printf("Transparent pixel: (%d,%d,%d)\n",
slouken@1668
    60
           icon->format->palette->colors[*pixels].r,
slouken@1668
    61
           icon->format->palette->colors[*pixels].g,
slouken@1668
    62
           icon->format->palette->colors[*pixels].b);
slouken@1662
    63
    mlen = icon->w * icon->h;
slouken@1668
    64
    mask = (Uint8 *) malloc(mlen / 8);
slouken@1662
    65
    if (mask == NULL) {
slouken@1668
    66
        fprintf(stderr, "Out of memory!\n");
slouken@1668
    67
        SDL_FreeSurface(icon);
slouken@1662
    68
        return (NULL);
slouken@1662
    69
    }
slouken@1668
    70
    memset(mask, 0, mlen / 8);
slouken@1662
    71
    for (i = 0; i < mlen;) {
slouken@1662
    72
        if (pixels[i] != *pixels)
slouken@1662
    73
            mask[i / 8] |= 0x01;
slouken@1662
    74
        ++i;
slouken@1662
    75
        if ((i % 8) != 0)
slouken@1662
    76
            mask[i / 8] <<= 1;
slouken@1662
    77
    }
slouken@1662
    78
    *maskp = mask;
slouken@1662
    79
    return (icon);
slouken@0
    80
}
slouken@0
    81
slouken@1662
    82
int SDLCALL
slouken@1668
    83
FilterEvents(const SDL_Event * event)
slouken@0
    84
{
slouken@1662
    85
    static int reallyquit = 0;
slouken@0
    86
slouken@1662
    87
    switch (event->type) {
slouken@0
    88
slouken@1662
    89
    case SDL_ACTIVEEVENT:
slouken@1662
    90
        /* See what happened */
slouken@1668
    91
        printf("App %s ", event->active.gain ? "gained" : "lost");
slouken@1662
    92
        if (event->active.state & SDL_APPACTIVE)
slouken@1668
    93
            printf("active ");
slouken@1662
    94
        if (event->active.state & SDL_APPMOUSEFOCUS)
slouken@1668
    95
            printf("mouse ");
slouken@1662
    96
        if (event->active.state & SDL_APPINPUTFOCUS)
slouken@1668
    97
            printf("input ");
slouken@1668
    98
        printf("focus\n");
slouken@0
    99
slouken@1662
   100
        /* See if we are iconified or restored */
slouken@1662
   101
        if (event->active.state & SDL_APPACTIVE) {
slouken@1668
   102
            printf("App has been %s\n",
slouken@1668
   103
                   event->active.gain ? "restored" : "iconified");
slouken@1662
   104
        }
slouken@1662
   105
        return (0);
slouken@0
   106
slouken@1662
   107
        /* This is important!  Queue it if we want to quit. */
slouken@1662
   108
    case SDL_QUIT:
slouken@1662
   109
        if (!reallyquit) {
slouken@1662
   110
            reallyquit = 1;
slouken@1668
   111
            printf("Quit requested\n");
slouken@1662
   112
            return (0);
slouken@1662
   113
        }
slouken@1668
   114
        printf("Quit demanded\n");
slouken@1662
   115
        return (1);
slouken@0
   116
slouken@1662
   117
        /* Mouse and keyboard events go to threads */
slouken@1662
   118
    case SDL_MOUSEMOTION:
slouken@1662
   119
    case SDL_MOUSEBUTTONDOWN:
slouken@1662
   120
    case SDL_MOUSEBUTTONUP:
slouken@1662
   121
    case SDL_KEYDOWN:
slouken@1662
   122
    case SDL_KEYUP:
slouken@1662
   123
        return (1);
slouken@0
   124
slouken@1662
   125
        /* Drop all other events */
slouken@1662
   126
    default:
slouken@1662
   127
        return (0);
slouken@1662
   128
    }
slouken@0
   129
}
slouken@0
   130
slouken@1662
   131
int SDLCALL
slouken@1668
   132
HandleMouse(void *unused)
slouken@0
   133
{
slouken@1662
   134
    SDL_Event events[10];
slouken@1662
   135
    int i, found;
slouken@1662
   136
    Uint32 mask;
slouken@0
   137
slouken@1662
   138
    /* Handle mouse events here */
slouken@1662
   139
    mask =
slouken@1662
   140
        (SDL_MOUSEMOTIONMASK | SDL_MOUSEBUTTONDOWNMASK |
slouken@1662
   141
         SDL_MOUSEBUTTONUPMASK);
slouken@1662
   142
    while (!done) {
slouken@1668
   143
        found = SDL_PeepEvents(events, 10, SDL_GETEVENT, mask);
slouken@1662
   144
        for (i = 0; i < found; ++i) {
slouken@1662
   145
            switch (events[i].type) {
slouken@1662
   146
                /* We want to toggle visibility on buttonpress */
slouken@1662
   147
            case SDL_MOUSEBUTTONDOWN:
slouken@1662
   148
            case SDL_MOUSEBUTTONUP:
slouken@1662
   149
                if (events[i].button.state == SDL_PRESSED) {
slouken@1662
   150
                    visible = !visible;
slouken@1668
   151
                    SDL_ShowCursor(visible);
slouken@1662
   152
                }
slouken@1668
   153
                printf("Mouse button %d has been %s\n",
slouken@1668
   154
                       events[i].button.button,
slouken@1668
   155
                       (events[i].button.state == SDL_PRESSED) ?
slouken@1668
   156
                       "pressed" : "released");
slouken@1662
   157
                break;
slouken@1662
   158
                /* Show relative mouse motion */
slouken@1662
   159
            case SDL_MOUSEMOTION:
slouken@1668
   160
                printf("Mouse relative motion: {%d,%d}\n",
slouken@1668
   161
                       events[i].motion.xrel, events[i].motion.yrel);
slouken@1662
   162
                break;
slouken@1662
   163
            }
slouken@1662
   164
        }
slouken@1662
   165
        /* Give up some CPU to allow events to arrive */
slouken@1668
   166
        SDL_Delay(20);
slouken@1662
   167
    }
slouken@1662
   168
    return (0);
slouken@0
   169
}
slouken@0
   170
slouken@1662
   171
int SDLCALL
slouken@1668
   172
HandleKeyboard(void *unused)
slouken@0
   173
{
slouken@1662
   174
    SDL_Event events[10];
slouken@1662
   175
    int i, found;
slouken@1662
   176
    Uint32 mask;
slouken@0
   177
slouken@1662
   178
    /* Handle mouse events here */
slouken@1662
   179
    mask = (SDL_KEYDOWNMASK | SDL_KEYUPMASK);
slouken@1662
   180
    while (!done) {
slouken@1668
   181
        found = SDL_PeepEvents(events, 10, SDL_GETEVENT, mask);
slouken@1662
   182
        for (i = 0; i < found; ++i) {
slouken@1662
   183
            switch (events[i].type) {
slouken@1662
   184
                /* We want to toggle visibility on buttonpress */
slouken@1662
   185
            case SDL_KEYDOWN:
slouken@1662
   186
            case SDL_KEYUP:
slouken@1668
   187
                printf("Key '%c' has been %s\n",
slouken@1668
   188
                       events[i].key.keysym.unicode,
slouken@1668
   189
                       (events[i].key.state == SDL_PRESSED) ?
slouken@1668
   190
                       "pressed" : "released");
icculus@562
   191
slouken@1662
   192
                /* Allow hitting <ESC> to quit the app */
slouken@1662
   193
                if (events[i].key.keysym.sym == SDLK_ESCAPE) {
slouken@1662
   194
                    done = 1;
slouken@1662
   195
                }
icculus@562
   196
slouken@1662
   197
                /* skip events now that aren't KEYUPs... */
slouken@1662
   198
                if (events[i].key.state == SDL_PRESSED)
slouken@1662
   199
                    break;
icculus@562
   200
slouken@1662
   201
                if (events[i].key.keysym.sym == SDLK_f) {
slouken@1662
   202
                    int rc = 0;
slouken@1668
   203
                    printf("attempting to toggle fullscreen...\n");
slouken@1668
   204
                    rc = SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
slouken@1668
   205
                    printf("SDL_WM_ToggleFullScreen returned %d.\n", rc);
slouken@1662
   206
                }
icculus@562
   207
slouken@1662
   208
                if (events[i].key.keysym.sym == SDLK_g) {
slouken@1662
   209
                    SDL_GrabMode m;
slouken@1668
   210
                    m = SDL_WM_GrabInput(SDL_GRAB_QUERY) ==
slouken@1662
   211
                        SDL_GRAB_ON ? SDL_GRAB_OFF : SDL_GRAB_ON;
slouken@1662
   212
                    printf
slouken@1662
   213
                        ("attempting to toggle input grab to %s...\n",
slouken@1662
   214
                         m == SDL_GRAB_ON ? "ON" : "OFF");
slouken@1668
   215
                    SDL_WM_GrabInput(m);
slouken@1668
   216
                    printf("attempt finished.\n");
slouken@1662
   217
                }
icculus@562
   218
slouken@1662
   219
                break;
slouken@1662
   220
            }
slouken@1662
   221
        }
slouken@1662
   222
        /* Give up some CPU to allow events to arrive */
slouken@1668
   223
        SDL_Delay(20);
slouken@1662
   224
    }
slouken@1662
   225
    return (0);
slouken@0
   226
}
slouken@0
   227
slouken@1662
   228
int
slouken@1668
   229
main(int argc, char *argv[])
slouken@0
   230
{
slouken@1662
   231
    SDL_Surface *screen;
slouken@1662
   232
    SDL_Surface *icon;
slouken@1662
   233
    Uint8 *icon_mask;
slouken@1662
   234
    int i, parsed;
slouken@1662
   235
    Uint8 *buffer;
slouken@1662
   236
    SDL_Color palette[256];
slouken@1662
   237
    Uint32 init_flags;
slouken@1662
   238
    Uint8 video_bpp;
slouken@1662
   239
    Uint32 video_flags;
slouken@1662
   240
    SDL_Thread *mouse_thread;
slouken@1662
   241
    SDL_Thread *keybd_thread;
slouken@0
   242
slouken@1662
   243
    /* Set the options, based on command line arguments */
slouken@1662
   244
    init_flags = SDL_INIT_VIDEO;
slouken@1662
   245
    video_bpp = 8;
slouken@1662
   246
    video_flags = SDL_SWSURFACE;
slouken@1662
   247
    parsed = 1;
slouken@1662
   248
    while (parsed) {
slouken@1662
   249
        /* If the threaded option is enabled, and the SDL library hasn't
slouken@1662
   250
           been compiled with threaded events enabled, then the mouse and
slouken@1662
   251
           keyboard won't respond.
slouken@1662
   252
         */
slouken@1668
   253
        if ((argc >= 2) && (strcmp(argv[1], "-threaded") == 0)) {
slouken@1662
   254
            init_flags |= SDL_INIT_EVENTTHREAD;
slouken@1662
   255
            argc -= 1;
slouken@1662
   256
            argv += 1;
slouken@1668
   257
            printf("Running with threaded events\n");
slouken@1668
   258
        } else if ((argc >= 2) && (strcmp(argv[1], "-fullscreen") == 0)) {
slouken@1662
   259
            video_flags |= SDL_FULLSCREEN;
slouken@1662
   260
            argc -= 1;
slouken@1662
   261
            argv += 1;
slouken@1668
   262
        } else if ((argc >= 3) && (strcmp(argv[1], "-bpp") == 0)) {
slouken@1668
   263
            video_bpp = atoi(argv[2]);
slouken@1662
   264
            argc -= 2;
slouken@1662
   265
            argv += 2;
slouken@1662
   266
        } else {
slouken@1662
   267
            parsed = 0;
slouken@1662
   268
        }
slouken@1662
   269
    }
slouken@0
   270
slouken@1662
   271
    /* Initialize SDL with the requested flags */
slouken@1668
   272
    if (SDL_Init(init_flags) < 0) {
slouken@1668
   273
        fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
slouken@1662
   274
        return (1);
slouken@1662
   275
    }
slouken@0
   276
slouken@1662
   277
    /* Set the icon -- this must be done before the first mode set */
slouken@1668
   278
    icon = LoadIconSurface("icon.bmp", &icon_mask);
slouken@1662
   279
    if (icon != NULL) {
slouken@1668
   280
        SDL_WM_SetIcon(icon, icon_mask);
slouken@1662
   281
    }
slouken@1662
   282
    if (icon_mask != NULL)
slouken@1668
   283
        free(icon_mask);
slouken@0
   284
slouken@1662
   285
    /* Initialize the display */
slouken@1668
   286
    screen = SDL_SetVideoMode(640, 480, video_bpp, video_flags);
slouken@1662
   287
    if (screen == NULL) {
slouken@1668
   288
        fprintf(stderr, "Couldn't set 640x480x%d video mode: %s\n",
slouken@1668
   289
                video_bpp, SDL_GetError());
slouken@1668
   290
        quit(1);
slouken@1662
   291
    }
slouken@1668
   292
    printf("Running in %s mode\n", screen->flags & SDL_FULLSCREEN ?
slouken@1668
   293
           "fullscreen" : "windowed");
slouken@0
   294
slouken@1662
   295
    /* Enable printable characters */
slouken@1668
   296
    SDL_EnableUNICODE(1);
slouken@0
   297
slouken@1662
   298
    /* Set an event filter that discards everything but QUIT */
slouken@1668
   299
    SDL_SetEventFilter(FilterEvents);
slouken@0
   300
slouken@1662
   301
    /* Create the event handling threads */
slouken@1668
   302
    mouse_thread = SDL_CreateThread(HandleMouse, NULL);
slouken@1668
   303
    keybd_thread = SDL_CreateThread(HandleKeyboard, NULL);
slouken@0
   304
slouken@1662
   305
    /* Set the surface pixels and refresh! */
slouken@1662
   306
    for (i = 0; i < 256; ++i) {
slouken@1662
   307
        palette[i].r = 255 - i;
slouken@1662
   308
        palette[i].g = 255 - i;
slouken@1662
   309
        palette[i].b = 255 - i;
slouken@1662
   310
    }
slouken@1668
   311
    SDL_SetColors(screen, palette, 0, 256);
slouken@1668
   312
    if (SDL_LockSurface(screen) < 0) {
slouken@1668
   313
        fprintf(stderr, "Couldn't lock display surface: %s\n",
slouken@1668
   314
                SDL_GetError());
slouken@1668
   315
        quit(2);
slouken@1662
   316
    }
slouken@1662
   317
    buffer = (Uint8 *) screen->pixels;
slouken@1662
   318
    for (i = 0; i < screen->h; ++i) {
slouken@1668
   319
        memset(buffer, (i * 255) / screen->h,
slouken@1668
   320
               screen->w * screen->format->BytesPerPixel);
slouken@1662
   321
        buffer += screen->pitch;
slouken@1662
   322
    }
slouken@1668
   323
    SDL_UnlockSurface(screen);
slouken@1668
   324
    SDL_UpdateRect(screen, 0, 0, 0, 0);
slouken@0
   325
slouken@1662
   326
    /* Loop, waiting for QUIT */
slouken@1662
   327
    while (!done) {
slouken@1662
   328
        if (!(init_flags & SDL_INIT_EVENTTHREAD)) {
slouken@1668
   329
            SDL_PumpEvents();   /* Needed when event thread is off */
slouken@1662
   330
        }
slouken@1668
   331
        if (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_QUITMASK)) {
slouken@1662
   332
            done = 1;
slouken@1662
   333
        }
slouken@1662
   334
        /* Give up some CPU so the events can accumulate */
slouken@1668
   335
        SDL_Delay(20);
slouken@1662
   336
    }
slouken@1668
   337
    SDL_WaitThread(mouse_thread, NULL);
slouken@1668
   338
    SDL_WaitThread(keybd_thread, NULL);
slouken@1668
   339
    SDL_Quit();
slouken@1662
   340
    return (0);
slouken@0
   341
}