src/video/SDL_cursor.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 1670 eef792d31de8
permissions -rw-r--r--
more tweaking indent options
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
/* General cursor handling code for SDL */
slouken@0
    25
slouken@0
    26
#include "SDL_mutex.h"
slouken@0
    27
#include "SDL_video.h"
slouken@0
    28
#include "SDL_mouse.h"
slouken@0
    29
#include "SDL_blit.h"
slouken@0
    30
#include "SDL_sysvideo.h"
slouken@0
    31
#include "SDL_cursor_c.h"
slouken@0
    32
#include "SDL_pixels_c.h"
slouken@0
    33
#include "default_cursor.h"
slouken@1361
    34
#include "../events/SDL_sysevents.h"
slouken@1361
    35
#include "../events/SDL_events_c.h"
slouken@0
    36
slouken@0
    37
/* These are static for our cursor handling code */
slouken@0
    38
volatile int SDL_cursorstate = CURSOR_VISIBLE;
slouken@0
    39
SDL_Cursor *SDL_cursor = NULL;
slouken@0
    40
static SDL_Cursor *SDL_defcursor = NULL;
slouken@0
    41
SDL_mutex *SDL_cursorlock = NULL;
slouken@0
    42
slouken@0
    43
/* Public functions */
slouken@1662
    44
void
slouken@1668
    45
SDL_CursorQuit(void)
slouken@0
    46
{
slouken@1662
    47
    if (SDL_cursor != NULL) {
slouken@1662
    48
        SDL_Cursor *cursor;
slouken@0
    49
slouken@1662
    50
        SDL_cursorstate &= ~CURSOR_VISIBLE;
slouken@1662
    51
        if (SDL_cursor != SDL_defcursor) {
slouken@1668
    52
            SDL_FreeCursor(SDL_cursor);
slouken@1662
    53
        }
slouken@1662
    54
        SDL_cursor = NULL;
slouken@1662
    55
        if (SDL_defcursor != NULL) {
slouken@1662
    56
            cursor = SDL_defcursor;
slouken@1662
    57
            SDL_defcursor = NULL;
slouken@1668
    58
            SDL_FreeCursor(cursor);
slouken@1662
    59
        }
slouken@1662
    60
    }
slouken@1662
    61
    if (SDL_cursorlock != NULL) {
slouken@1668
    62
        SDL_DestroyMutex(SDL_cursorlock);
slouken@1662
    63
        SDL_cursorlock = NULL;
slouken@1662
    64
    }
slouken@0
    65
}
slouken@1662
    66
int
slouken@1668
    67
SDL_CursorInit(Uint32 multithreaded)
slouken@0
    68
{
slouken@1662
    69
    /* We don't have mouse focus, and the cursor isn't drawn yet */
icculus@1140
    70
#ifndef IPOD
slouken@1662
    71
    SDL_cursorstate = CURSOR_VISIBLE;
icculus@1140
    72
#endif
slouken@0
    73
slouken@1662
    74
    /* Create the default cursor */
slouken@1662
    75
    if (SDL_defcursor == NULL) {
slouken@1668
    76
        SDL_defcursor = SDL_CreateCursor(default_cdata, default_cmask,
slouken@1668
    77
                                         DEFAULT_CWIDTH, DEFAULT_CHEIGHT,
slouken@1668
    78
                                         DEFAULT_CHOTX, DEFAULT_CHOTY);
slouken@1668
    79
        SDL_SetCursor(SDL_defcursor);
slouken@1662
    80
    }
slouken@0
    81
slouken@1662
    82
    /* Create a lock if necessary */
slouken@1662
    83
    if (multithreaded) {
slouken@1668
    84
        SDL_cursorlock = SDL_CreateMutex();
slouken@1662
    85
    }
slouken@0
    86
slouken@1662
    87
    /* That's it! */
slouken@1662
    88
    return (0);
slouken@0
    89
}
slouken@0
    90
slouken@0
    91
/* Multi-thread support for cursors */
slouken@0
    92
#ifndef SDL_LockCursor
slouken@1662
    93
void
slouken@1668
    94
SDL_LockCursor(void)
slouken@0
    95
{
slouken@1662
    96
    if (SDL_cursorlock) {
slouken@1668
    97
        SDL_mutexP(SDL_cursorlock);
slouken@1662
    98
    }
slouken@0
    99
}
slouken@0
   100
#endif
slouken@0
   101
#ifndef SDL_UnlockCursor
slouken@1662
   102
void
slouken@1668
   103
SDL_UnlockCursor(void)
slouken@0
   104
{
slouken@1662
   105
    if (SDL_cursorlock) {
slouken@1668
   106
        SDL_mutexV(SDL_cursorlock);
slouken@1662
   107
    }
slouken@0
   108
}
slouken@0
   109
#endif
slouken@0
   110
slouken@0
   111
/* Software cursor drawing support */
slouken@1662
   112
SDL_Cursor *
slouken@1668
   113
SDL_CreateCursor(Uint8 * data, Uint8 * mask,
slouken@1668
   114
                 int w, int h, int hot_x, int hot_y)
slouken@0
   115
{
slouken@1668
   116
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@1662
   117
    int savelen;
slouken@1662
   118
    int i;
slouken@1662
   119
    SDL_Cursor *cursor;
slouken@0
   120
slouken@1662
   121
    /* Make sure the width is a multiple of 8 */
slouken@1662
   122
    w = ((w + 7) & ~7);
slouken@0
   123
slouken@1662
   124
    /* Sanity check the hot spot */
slouken@1662
   125
    if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) {
slouken@1668
   126
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@1662
   127
        return (NULL);
slouken@1662
   128
    }
slouken@0
   129
slouken@1662
   130
    /* Allocate memory for the cursor */
slouken@1668
   131
    cursor = (SDL_Cursor *) SDL_malloc(sizeof *cursor);
slouken@1662
   132
    if (cursor == NULL) {
slouken@1668
   133
        SDL_OutOfMemory();
slouken@1662
   134
        return (NULL);
slouken@1662
   135
    }
slouken@1662
   136
    savelen = (w * 4) * h;
slouken@1662
   137
    cursor->area.x = 0;
slouken@1662
   138
    cursor->area.y = 0;
slouken@1662
   139
    cursor->area.w = w;
slouken@1662
   140
    cursor->area.h = h;
slouken@1662
   141
    cursor->hot_x = hot_x;
slouken@1662
   142
    cursor->hot_y = hot_y;
slouken@1668
   143
    cursor->data = (Uint8 *) SDL_malloc((w / 8) * h * 2);
slouken@1662
   144
    cursor->mask = cursor->data + ((w / 8) * h);
slouken@1668
   145
    cursor->save[0] = (Uint8 *) SDL_malloc(savelen * 2);
slouken@1662
   146
    cursor->save[1] = cursor->save[0] + savelen;
slouken@1662
   147
    cursor->wm_cursor = NULL;
slouken@1662
   148
    if (!cursor->data || !cursor->save[0]) {
slouken@1668
   149
        SDL_FreeCursor(cursor);
slouken@1668
   150
        SDL_OutOfMemory();
slouken@1662
   151
        return (NULL);
slouken@1662
   152
    }
slouken@1662
   153
    for (i = ((w / 8) * h) - 1; i >= 0; --i) {
slouken@1662
   154
        cursor->data[i] = data[i];
slouken@1662
   155
        cursor->mask[i] = mask[i] | data[i];
slouken@1662
   156
    }
slouken@1668
   157
    SDL_memset(cursor->save[0], 0, savelen * 2);
slouken@0
   158
slouken@1662
   159
    /* If the window manager gives us a good cursor, we're done! */
slouken@1662
   160
    if (_this->CreateWMCursor) {
slouken@1668
   161
        cursor->wm_cursor = _this->CreateWMCursor(_this, data, mask,
slouken@1668
   162
                                                  w, h, hot_x, hot_y);
slouken@1662
   163
    } else {
slouken@1662
   164
        cursor->wm_cursor = NULL;
slouken@1662
   165
    }
slouken@1662
   166
    return (cursor);
slouken@0
   167
}
slouken@0
   168
slouken@0
   169
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@0
   170
   if this is desired for any reason.  This is used when setting
slouken@0
   171
   the video mode and when the SDL window gains the mouse focus.
slouken@0
   172
 */
slouken@1662
   173
void
slouken@1668
   174
SDL_SetCursor(SDL_Cursor * cursor)
slouken@0
   175
{
slouken@1668
   176
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@0
   177
slouken@1662
   178
    /* Make sure that the video subsystem has been initialized */
slouken@1662
   179
    if (!_this) {
slouken@1662
   180
        return;
slouken@1662
   181
    }
slouken@0
   182
slouken@1662
   183
    /* Prevent the event thread from moving the mouse */
slouken@1668
   184
    SDL_LockCursor();
slouken@0
   185
slouken@1662
   186
    /* Set the new cursor */
slouken@1662
   187
    if (cursor && (cursor != SDL_cursor)) {
slouken@1662
   188
        /* Erase the current mouse position */
slouken@1668
   189
        if (SHOULD_DRAWCURSOR(SDL_cursorstate)) {
slouken@1668
   190
            SDL_EraseCursor(SDL_VideoSurface);
slouken@1662
   191
        } else if (_this->MoveWMCursor) {
slouken@1662
   192
            /* If the video driver is moving the cursor directly,
slouken@1662
   193
               it needs to hide the old cursor before (possibly)
slouken@1662
   194
               showing the new one.  (But don't erase NULL cursor)
slouken@1662
   195
             */
slouken@1662
   196
            if (SDL_cursor) {
slouken@1668
   197
                _this->ShowWMCursor(_this, NULL);
slouken@1662
   198
            }
slouken@1662
   199
        }
slouken@1662
   200
        SDL_cursor = cursor;
slouken@1662
   201
    }
slouken@0
   202
slouken@1662
   203
    /* Draw the new mouse cursor */
slouken@1662
   204
    if (SDL_cursor && (SDL_cursorstate & CURSOR_VISIBLE)) {
slouken@1662
   205
        /* Use window manager cursor if possible */
slouken@1662
   206
        if (SDL_cursor->wm_cursor &&
slouken@1668
   207
            _this->ShowWMCursor(_this, SDL_cursor->wm_cursor)) {
slouken@1662
   208
            SDL_cursorstate &= ~CURSOR_USINGSW;
slouken@1662
   209
        } else {
slouken@1662
   210
            SDL_cursorstate |= CURSOR_USINGSW;
slouken@1662
   211
            if (_this->ShowWMCursor) {
slouken@1668
   212
                _this->ShowWMCursor(_this, NULL);
slouken@1662
   213
            }
slouken@1662
   214
            {
slouken@1662
   215
                int x, y;
slouken@1668
   216
                SDL_GetMouseState(&x, &y);
slouken@1662
   217
                SDL_cursor->area.x = (x - SDL_cursor->hot_x);
slouken@1662
   218
                SDL_cursor->area.y = (y - SDL_cursor->hot_y);
slouken@1662
   219
            }
slouken@1668
   220
            SDL_DrawCursor(SDL_VideoSurface);
slouken@1662
   221
        }
slouken@1662
   222
    } else {
slouken@1662
   223
        /* Erase window manager mouse (cursor not visible) */
slouken@1662
   224
        if (SDL_cursor && (SDL_cursorstate & CURSOR_USINGSW)) {
slouken@1668
   225
            SDL_EraseCursor(SDL_VideoSurface);
slouken@1662
   226
        } else {
slouken@1662
   227
            if (_this) {
slouken@1668
   228
                _this->ShowWMCursor(_this, NULL);
slouken@1662
   229
            }
slouken@1662
   230
        }
slouken@1662
   231
    }
slouken@1668
   232
    SDL_UnlockCursor();
slouken@0
   233
}
slouken@0
   234
slouken@1662
   235
SDL_Cursor *
slouken@1668
   236
SDL_GetCursor(void)
slouken@0
   237
{
slouken@1662
   238
    return (SDL_cursor);
slouken@0
   239
}
slouken@0
   240
slouken@1662
   241
void
slouken@1668
   242
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@0
   243
{
slouken@1662
   244
    if (cursor) {
slouken@1662
   245
        if (cursor == SDL_cursor) {
slouken@1668
   246
            SDL_SetCursor(SDL_defcursor);
slouken@1662
   247
        }
slouken@1662
   248
        if (cursor != SDL_defcursor) {
slouken@1668
   249
            SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@77
   250
slouken@1662
   251
            if (cursor->data) {
slouken@1668
   252
                SDL_free(cursor->data);
slouken@1662
   253
            }
slouken@1662
   254
            if (cursor->save[0]) {
slouken@1668
   255
                SDL_free(cursor->save[0]);
slouken@1662
   256
            }
slouken@1662
   257
            if (_this && cursor->wm_cursor) {
slouken@1668
   258
                _this->FreeWMCursor(_this, cursor->wm_cursor);
slouken@1662
   259
            }
slouken@1668
   260
            SDL_free(cursor);
slouken@1662
   261
        }
slouken@1662
   262
    }
slouken@0
   263
}
slouken@0
   264
slouken@1662
   265
int
slouken@1668
   266
SDL_ShowCursor(int toggle)
slouken@0
   267
{
slouken@1662
   268
    int showing;
slouken@0
   269
slouken@1662
   270
    showing = (SDL_cursorstate & CURSOR_VISIBLE);
slouken@1662
   271
    if (toggle >= 0) {
slouken@1668
   272
        SDL_LockCursor();
slouken@1662
   273
        if (toggle) {
slouken@1662
   274
            SDL_cursorstate |= CURSOR_VISIBLE;
slouken@1662
   275
        } else {
slouken@1662
   276
            SDL_cursorstate &= ~CURSOR_VISIBLE;
slouken@1662
   277
        }
slouken@1668
   278
        SDL_UnlockCursor();
slouken@1662
   279
        if ((SDL_cursorstate & CURSOR_VISIBLE) != showing) {
slouken@1668
   280
            SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@0
   281
slouken@1668
   282
            SDL_SetCursor(NULL);
slouken@1662
   283
            if (_this && _this->CheckMouseMode) {
slouken@1668
   284
                _this->CheckMouseMode(_this);
slouken@1662
   285
            }
slouken@1662
   286
        }
slouken@1662
   287
    } else {
slouken@1662
   288
        /* Query current state */ ;
slouken@1662
   289
    }
slouken@1662
   290
    return (showing ? 1 : 0);
slouken@0
   291
}
slouken@0
   292
slouken@1662
   293
void
slouken@1668
   294
SDL_WarpMouse(Uint16 x, Uint16 y)
slouken@0
   295
{
slouken@1668
   296
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@0
   297
slouken@1662
   298
    if (!_this || !SDL_PublicSurface) {
slouken@1668
   299
        SDL_SetError("A video mode must be set before warping mouse");
slouken@1662
   300
        return;
slouken@1662
   301
    }
slouken@595
   302
slouken@1662
   303
    /* If we have an offset video mode, offset the mouse coordinates */
slouken@1662
   304
    if (SDL_VideoSurface->pitch == 0) {
slouken@1662
   305
        x += SDL_VideoSurface->offset /
slouken@1662
   306
            SDL_VideoSurface->format->BytesPerPixel;
slouken@1662
   307
        y += SDL_VideoSurface->offset;
slouken@1662
   308
    } else {
slouken@1662
   309
        x += (SDL_VideoSurface->offset % SDL_VideoSurface->pitch) /
slouken@1662
   310
            SDL_VideoSurface->format->BytesPerPixel;
slouken@1662
   311
        y += (SDL_VideoSurface->offset / SDL_VideoSurface->pitch);
slouken@1662
   312
    }
slouken@527
   313
slouken@1662
   314
    /* This generates a mouse motion event */
slouken@1662
   315
    if (_this->WarpWMCursor) {
slouken@1668
   316
        _this->WarpWMCursor(_this, x, y);
slouken@1662
   317
    } else {
slouken@1668
   318
        SDL_PrivateMouseMotion(0, 0, x, y);
slouken@1662
   319
    }
slouken@0
   320
}
slouken@0
   321
slouken@1662
   322
void
slouken@1668
   323
SDL_MoveCursor(int x, int y)
slouken@0
   324
{
slouken@1668
   325
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@0
   326
slouken@1662
   327
    /* Erase and update the current mouse position */
slouken@1668
   328
    if (SHOULD_DRAWCURSOR(SDL_cursorstate)) {
slouken@1662
   329
        /* Erase and redraw mouse cursor in new position */
slouken@1668
   330
        SDL_LockCursor();
slouken@1668
   331
        SDL_EraseCursor(SDL_VideoSurface);
slouken@1662
   332
        SDL_cursor->area.x = (x - SDL_cursor->hot_x);
slouken@1662
   333
        SDL_cursor->area.y = (y - SDL_cursor->hot_y);
slouken@1668
   334
        SDL_DrawCursor(SDL_VideoSurface);
slouken@1668
   335
        SDL_UnlockCursor();
slouken@1662
   336
    } else if (_this->MoveWMCursor) {
slouken@1668
   337
        _this->MoveWMCursor(_this, x, y);
slouken@1662
   338
    }
slouken@0
   339
}
slouken@0
   340
slouken@0
   341
/* Keep track of the current cursor colors */
slouken@0
   342
static int palette_changed = 1;
slouken@1428
   343
static Uint8 pixels8[2];
slouken@0
   344
slouken@1662
   345
void
slouken@1668
   346
SDL_CursorPaletteChanged(void)
slouken@0
   347
{
slouken@1662
   348
    palette_changed = 1;
slouken@0
   349
}
slouken@0
   350
slouken@1662
   351
void
slouken@1668
   352
SDL_MouseRect(SDL_Rect * area)
slouken@0
   353
{
slouken@1668
   354
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@1662
   355
    int clip_diff;
slouken@0
   356
slouken@1662
   357
    *area = SDL_cursor->area;
slouken@1662
   358
    if (area->x < 0) {
slouken@1662
   359
        area->w += area->x;
slouken@1662
   360
        area->x = 0;
slouken@1662
   361
    }
slouken@1662
   362
    if (area->y < 0) {
slouken@1662
   363
        area->h += area->y;
slouken@1662
   364
        area->y = 0;
slouken@1662
   365
    }
slouken@1662
   366
    clip_diff = (area->x + area->w) - SDL_VideoSurface->w;
slouken@1662
   367
    if (clip_diff > 0) {
slouken@1662
   368
        area->w = area->w < clip_diff ? 0 : area->w - clip_diff;
slouken@1662
   369
    }
slouken@1662
   370
    clip_diff = (area->y + area->h) - SDL_VideoSurface->h;
slouken@1662
   371
    if (clip_diff > 0) {
slouken@1662
   372
        area->h = area->h < clip_diff ? 0 : area->h - clip_diff;
slouken@1662
   373
    }
slouken@0
   374
}
slouken@0
   375
slouken@1662
   376
static void
slouken@1668
   377
SDL_DrawCursorFast(SDL_Surface * screen, SDL_Rect * area)
slouken@0
   378
{
slouken@1662
   379
    const Uint32 pixels[2] = { 0xFFFFFFFF, 0x00000000 };
slouken@1662
   380
    int i, w, h;
slouken@1662
   381
    Uint8 *data, datab;
slouken@1662
   382
    Uint8 *mask, maskb;
slouken@0
   383
slouken@1662
   384
    data = SDL_cursor->data + area->y * SDL_cursor->area.w / 8;
slouken@1662
   385
    mask = SDL_cursor->mask + area->y * SDL_cursor->area.w / 8;
slouken@1662
   386
    switch (screen->format->BytesPerPixel) {
slouken@0
   387
slouken@1662
   388
    case 1:
slouken@1662
   389
        {
slouken@1662
   390
            Uint8 *dst;
slouken@1662
   391
            int dstskip;
slouken@0
   392
slouken@1662
   393
            if (palette_changed) {
slouken@1662
   394
                pixels8[0] =
slouken@1668
   395
                    (Uint8) SDL_MapRGB(screen->format, 255, 255, 255);
slouken@1668
   396
                pixels8[1] = (Uint8) SDL_MapRGB(screen->format, 0, 0, 0);
slouken@1662
   397
                palette_changed = 0;
slouken@1662
   398
            }
slouken@1662
   399
            dst = (Uint8 *) screen->pixels +
slouken@1662
   400
                (SDL_cursor->area.y + area->y) * screen->pitch +
slouken@1662
   401
                SDL_cursor->area.x;
slouken@1662
   402
            dstskip = screen->pitch - area->w;
slouken@0
   403
slouken@1662
   404
            for (h = area->h; h; h--) {
slouken@1662
   405
                for (w = area->w / 8; w; w--) {
slouken@1662
   406
                    maskb = *mask++;
slouken@1662
   407
                    datab = *data++;
slouken@1662
   408
                    for (i = 0; i < 8; ++i) {
slouken@1662
   409
                        if (maskb & 0x80) {
slouken@1662
   410
                            *dst = pixels8[datab >> 7];
slouken@1662
   411
                        }
slouken@1662
   412
                        maskb <<= 1;
slouken@1662
   413
                        datab <<= 1;
slouken@1662
   414
                        dst++;
slouken@1662
   415
                    }
slouken@1662
   416
                }
slouken@1662
   417
                dst += dstskip;
slouken@1662
   418
            }
slouken@1662
   419
        }
slouken@1662
   420
        break;
slouken@0
   421
slouken@1662
   422
    case 2:
slouken@1662
   423
        {
slouken@1662
   424
            Uint16 *dst;
slouken@1662
   425
            int dstskip;
slouken@0
   426
slouken@1662
   427
            dst = (Uint16 *) screen->pixels +
slouken@1662
   428
                (SDL_cursor->area.y + area->y) * screen->pitch / 2 +
slouken@1662
   429
                SDL_cursor->area.x;
slouken@1662
   430
            dstskip = (screen->pitch / 2) - area->w;
slouken@0
   431
slouken@1662
   432
            for (h = area->h; h; h--) {
slouken@1662
   433
                for (w = area->w / 8; w; w--) {
slouken@1662
   434
                    maskb = *mask++;
slouken@1662
   435
                    datab = *data++;
slouken@1662
   436
                    for (i = 0; i < 8; ++i) {
slouken@1662
   437
                        if (maskb & 0x80) {
slouken@1662
   438
                            *dst = (Uint16) pixels[datab >> 7];
slouken@1662
   439
                        }
slouken@1662
   440
                        maskb <<= 1;
slouken@1662
   441
                        datab <<= 1;
slouken@1662
   442
                        dst++;
slouken@1662
   443
                    }
slouken@1662
   444
                }
slouken@1662
   445
                dst += dstskip;
slouken@1662
   446
            }
slouken@1662
   447
        }
slouken@1662
   448
        break;
slouken@0
   449
slouken@1662
   450
    case 3:
slouken@1662
   451
        {
slouken@1662
   452
            Uint8 *dst;
slouken@1662
   453
            int dstskip;
slouken@0
   454
slouken@1662
   455
            dst = (Uint8 *) screen->pixels +
slouken@1662
   456
                (SDL_cursor->area.y + area->y) * screen->pitch +
slouken@1662
   457
                SDL_cursor->area.x * 3;
slouken@1662
   458
            dstskip = screen->pitch - area->w * 3;
slouken@0
   459
slouken@1662
   460
            for (h = area->h; h; h--) {
slouken@1662
   461
                for (w = area->w / 8; w; w--) {
slouken@1662
   462
                    maskb = *mask++;
slouken@1662
   463
                    datab = *data++;
slouken@1662
   464
                    for (i = 0; i < 8; ++i) {
slouken@1662
   465
                        if (maskb & 0x80) {
slouken@1668
   466
                            SDL_memset(dst, pixels[datab >> 7], 3);
slouken@1662
   467
                        }
slouken@1662
   468
                        maskb <<= 1;
slouken@1662
   469
                        datab <<= 1;
slouken@1662
   470
                        dst += 3;
slouken@1662
   471
                    }
slouken@1662
   472
                }
slouken@1662
   473
                dst += dstskip;
slouken@1662
   474
            }
slouken@1662
   475
        }
slouken@1662
   476
        break;
slouken@0
   477
slouken@1662
   478
    case 4:
slouken@1662
   479
        {
slouken@1662
   480
            Uint32 *dst;
slouken@1662
   481
            int dstskip;
slouken@0
   482
slouken@1662
   483
            dst = (Uint32 *) screen->pixels +
slouken@1662
   484
                (SDL_cursor->area.y + area->y) * screen->pitch / 4 +
slouken@1662
   485
                SDL_cursor->area.x;
slouken@1662
   486
            dstskip = (screen->pitch / 4) - area->w;
slouken@0
   487
slouken@1662
   488
            for (h = area->h; h; h--) {
slouken@1662
   489
                for (w = area->w / 8; w; w--) {
slouken@1662
   490
                    maskb = *mask++;
slouken@1662
   491
                    datab = *data++;
slouken@1662
   492
                    for (i = 0; i < 8; ++i) {
slouken@1662
   493
                        if (maskb & 0x80) {
slouken@1662
   494
                            *dst = pixels[datab >> 7];
slouken@1662
   495
                        }
slouken@1662
   496
                        maskb <<= 1;
slouken@1662
   497
                        datab <<= 1;
slouken@1662
   498
                        dst++;
slouken@1662
   499
                    }
slouken@1662
   500
                }
slouken@1662
   501
                dst += dstskip;
slouken@1662
   502
            }
slouken@1662
   503
        }
slouken@1662
   504
        break;
slouken@1662
   505
    }
slouken@0
   506
}
slouken@0
   507
slouken@1662
   508
static void
slouken@1668
   509
SDL_DrawCursorSlow(SDL_Surface * screen, SDL_Rect * area)
slouken@0
   510
{
slouken@1662
   511
    const Uint32 pixels[2] = { 0xFFFFFF, 0x000000 };
slouken@1662
   512
    int h;
slouken@1662
   513
    int x, minx, maxx;
slouken@1662
   514
    Uint8 *data, datab = 0;
slouken@1662
   515
    Uint8 *mask, maskb = 0;
slouken@1662
   516
    Uint8 *dst;
slouken@1662
   517
    int dstbpp, dstskip;
slouken@0
   518
slouken@1662
   519
    data = SDL_cursor->data + area->y * SDL_cursor->area.w / 8;
slouken@1662
   520
    mask = SDL_cursor->mask + area->y * SDL_cursor->area.w / 8;
slouken@1662
   521
    dstbpp = screen->format->BytesPerPixel;
slouken@1662
   522
    dst = (Uint8 *) screen->pixels +
slouken@1662
   523
        (SDL_cursor->area.y + area->y) * screen->pitch +
slouken@1662
   524
        SDL_cursor->area.x * dstbpp;
slouken@1662
   525
    dstskip = screen->pitch - SDL_cursor->area.w * dstbpp;
slouken@0
   526
slouken@1662
   527
    minx = area->x;
slouken@1662
   528
    maxx = area->x + area->w;
slouken@1662
   529
    if (screen->format->BytesPerPixel == 1) {
slouken@1662
   530
        if (palette_changed) {
slouken@1668
   531
            pixels8[0] = (Uint8) SDL_MapRGB(screen->format, 255, 255, 255);
slouken@1668
   532
            pixels8[1] = (Uint8) SDL_MapRGB(screen->format, 0, 0, 0);
slouken@1662
   533
            palette_changed = 0;
slouken@1662
   534
        }
slouken@1662
   535
        for (h = area->h; h; h--) {
slouken@1662
   536
            for (x = 0; x < SDL_cursor->area.w; ++x) {
slouken@1662
   537
                if ((x % 8) == 0) {
slouken@1662
   538
                    maskb = *mask++;
slouken@1662
   539
                    datab = *data++;
slouken@1662
   540
                }
slouken@1662
   541
                if ((x >= minx) && (x < maxx)) {
slouken@1662
   542
                    if (maskb & 0x80) {
slouken@1668
   543
                        SDL_memset(dst, pixels8[datab >> 7], dstbpp);
slouken@1662
   544
                    }
slouken@1662
   545
                }
slouken@1662
   546
                maskb <<= 1;
slouken@1662
   547
                datab <<= 1;
slouken@1662
   548
                dst += dstbpp;
slouken@1662
   549
            }
slouken@1662
   550
            dst += dstskip;
slouken@1662
   551
        }
slouken@1662
   552
    } else {
slouken@1662
   553
        for (h = area->h; h; h--) {
slouken@1662
   554
            for (x = 0; x < SDL_cursor->area.w; ++x) {
slouken@1662
   555
                if ((x % 8) == 0) {
slouken@1662
   556
                    maskb = *mask++;
slouken@1662
   557
                    datab = *data++;
slouken@1662
   558
                }
slouken@1662
   559
                if ((x >= minx) && (x < maxx)) {
slouken@1662
   560
                    if (maskb & 0x80) {
slouken@1668
   561
                        SDL_memset(dst, pixels[datab >> 7], dstbpp);
slouken@1662
   562
                    }
slouken@1662
   563
                }
slouken@1662
   564
                maskb <<= 1;
slouken@1662
   565
                datab <<= 1;
slouken@1662
   566
                dst += dstbpp;
slouken@1662
   567
            }
slouken@1662
   568
            dst += dstskip;
slouken@1662
   569
        }
slouken@1662
   570
    }
slouken@0
   571
}
slouken@0
   572
slouken@0
   573
/* This handles the ugly work of converting the saved cursor background from
slouken@0
   574
   the pixel format of the shadow surface to that of the video surface.
slouken@0
   575
   This is only necessary when blitting from a shadow surface of a different
slouken@0
   576
   pixel format than the video surface, and using a software rendered cursor.
slouken@0
   577
*/
slouken@1662
   578
static void
slouken@1668
   579
SDL_ConvertCursorSave(SDL_Surface * screen, int w, int h)
slouken@0
   580
{
slouken@1668
   581
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@1662
   582
    SDL_BlitInfo info;
slouken@1662
   583
    SDL_loblit RunBlit;
slouken@0
   584
slouken@1662
   585
    /* Make sure we can steal the blit mapping */
slouken@1662
   586
    if (screen->map->dst != SDL_VideoSurface) {
slouken@1662
   587
        return;
slouken@1662
   588
    }
slouken@0
   589
slouken@1662
   590
    /* Set up the blit information */
slouken@1662
   591
    info.s_pixels = SDL_cursor->save[1];
slouken@1662
   592
    info.s_width = w;
slouken@1662
   593
    info.s_height = h;
slouken@1662
   594
    info.s_skip = 0;
slouken@1662
   595
    info.d_pixels = SDL_cursor->save[0];
slouken@1662
   596
    info.d_width = w;
slouken@1662
   597
    info.d_height = h;
slouken@1662
   598
    info.d_skip = 0;
slouken@1662
   599
    info.aux_data = screen->map->sw_data->aux_data;
slouken@1662
   600
    info.src = screen->format;
slouken@1662
   601
    info.table = screen->map->table;
slouken@1662
   602
    info.dst = SDL_VideoSurface->format;
slouken@1662
   603
    RunBlit = screen->map->sw_data->blit;
slouken@0
   604
slouken@1662
   605
    /* Run the actual software blit */
slouken@1668
   606
    RunBlit(&info);
slouken@0
   607
}
slouken@0
   608
slouken@1662
   609
void
slouken@1668
   610
SDL_DrawCursorNoLock(SDL_Surface * screen)
slouken@0
   611
{
slouken@1668
   612
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@1662
   613
    SDL_Rect area;
slouken@0
   614
slouken@1662
   615
    /* Get the mouse rectangle, clipped to the screen */
slouken@1668
   616
    SDL_MouseRect(&area);
slouken@1662
   617
    if ((area.w == 0) || (area.h == 0)) {
slouken@1662
   618
        return;
slouken@1662
   619
    }
slouken@0
   620
slouken@1662
   621
    /* Copy mouse background */
slouken@1662
   622
    {
slouken@1662
   623
        int w, h, screenbpp;
slouken@1662
   624
        Uint8 *src, *dst;
slouken@0
   625
slouken@1662
   626
        /* Set up the copy pointers */
slouken@1662
   627
        screenbpp = screen->format->BytesPerPixel;
slouken@1662
   628
        if ((screen == SDL_VideoSurface) ||
slouken@1668
   629
            FORMAT_EQUAL(screen->format, SDL_VideoSurface->format)) {
slouken@1662
   630
            dst = SDL_cursor->save[0];
slouken@1662
   631
        } else {
slouken@1662
   632
            dst = SDL_cursor->save[1];
slouken@1662
   633
        }
slouken@1662
   634
        src = (Uint8 *) screen->pixels + area.y * screen->pitch +
slouken@1662
   635
            area.x * screenbpp;
slouken@0
   636
slouken@1662
   637
        /* Perform the copy */
slouken@1662
   638
        w = area.w * screenbpp;
slouken@1662
   639
        h = area.h;
slouken@1662
   640
        while (h--) {
slouken@1668
   641
            SDL_memcpy(dst, src, w);
slouken@1662
   642
            dst += w;
slouken@1662
   643
            src += screen->pitch;
slouken@1662
   644
        }
slouken@1662
   645
    }
slouken@0
   646
slouken@1662
   647
    /* Draw the mouse cursor */
slouken@1662
   648
    area.x -= SDL_cursor->area.x;
slouken@1662
   649
    area.y -= SDL_cursor->area.y;
slouken@1662
   650
    if ((area.x == 0) && (area.w == SDL_cursor->area.w)) {
slouken@1668
   651
        SDL_DrawCursorFast(screen, &area);
slouken@1662
   652
    } else {
slouken@1668
   653
        SDL_DrawCursorSlow(screen, &area);
slouken@1662
   654
    }
slouken@0
   655
}
slouken@0
   656
slouken@1662
   657
void
slouken@1668
   658
SDL_DrawCursor(SDL_Surface * screen)
slouken@0
   659
{
slouken@1662
   660
    /* Lock the screen if necessary */
slouken@1662
   661
    if (screen == NULL) {
slouken@1662
   662
        return;
slouken@1662
   663
    }
slouken@1668
   664
    if (SDL_MUSTLOCK(screen)) {
slouken@1668
   665
        if (SDL_LockSurface(screen) < 0) {
slouken@1662
   666
            return;
slouken@1662
   667
        }
slouken@1662
   668
    }
slouken@0
   669
slouken@1668
   670
    SDL_DrawCursorNoLock(screen);
slouken@0
   671
slouken@1662
   672
    /* Unlock the screen and update if necessary */
slouken@1668
   673
    if (SDL_MUSTLOCK(screen)) {
slouken@1668
   674
        SDL_UnlockSurface(screen);
slouken@1662
   675
    }
slouken@1662
   676
    if ((screen->flags & SDL_SCREEN_SURFACE) &&
slouken@1662
   677
        !(screen->flags & SDL_HWSURFACE)) {
slouken@1668
   678
        SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@1662
   679
        SDL_Window *window;
slouken@1662
   680
        SDL_Rect area;
slouken@0
   681
slouken@1668
   682
        window = SDL_GetWindowFromSurface(screen);
slouken@1662
   683
        if (!window) {
slouken@1662
   684
            return;
slouken@1662
   685
        }
slouken@0
   686
slouken@1668
   687
        SDL_MouseRect(&area);
slouken@1662
   688
slouken@1662
   689
        if (_this->UpdateWindowSurface) {
slouken@1668
   690
            _this->UpdateWindowSurface(_this, window, 1, &area);
slouken@1662
   691
        }
slouken@1662
   692
    }
slouken@0
   693
}
slouken@0
   694
slouken@1662
   695
void
slouken@1668
   696
SDL_EraseCursorNoLock(SDL_Surface * screen)
slouken@0
   697
{
slouken@1668
   698
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@1662
   699
    SDL_Window *window;
slouken@1662
   700
    SDL_Rect area;
slouken@0
   701
slouken@1662
   702
    /* Get the window associated with the surface */
slouken@1668
   703
    window = SDL_GetWindowFromSurface(screen);
slouken@1662
   704
    if (!window || !window->surface) {
slouken@1662
   705
        return;
slouken@1662
   706
    }
slouken@0
   707
slouken@1662
   708
    /* Get the mouse rectangle, clipped to the screen */
slouken@1668
   709
    SDL_MouseRect(&area);
slouken@1662
   710
    if ((area.w == 0) || (area.h == 0)) {
slouken@1662
   711
        return;
slouken@1662
   712
    }
slouken@0
   713
slouken@1662
   714
    /* Copy mouse background */
slouken@1662
   715
    {
slouken@1662
   716
        int w, h, screenbpp;
slouken@1662
   717
        Uint8 *src, *dst;
slouken@0
   718
slouken@1662
   719
        /* Set up the copy pointers */
slouken@1662
   720
        screenbpp = screen->format->BytesPerPixel;
slouken@1662
   721
        if ((screen->flags & SDL_SCREEN_SURFACE) ||
slouken@1668
   722
            FORMAT_EQUAL(screen->format, window->surface->format)) {
slouken@1662
   723
            src = SDL_cursor->save[0];
slouken@1662
   724
        } else {
slouken@1662
   725
            src = SDL_cursor->save[1];
slouken@1662
   726
        }
slouken@1662
   727
        dst = (Uint8 *) screen->pixels + area.y * screen->pitch +
slouken@1662
   728
            area.x * screenbpp;
slouken@0
   729
slouken@1662
   730
        /* Perform the copy */
slouken@1662
   731
        w = area.w * screenbpp;
slouken@1662
   732
        h = area.h;
slouken@1662
   733
        while (h--) {
slouken@1668
   734
            SDL_memcpy(dst, src, w);
slouken@1662
   735
            src += w;
slouken@1662
   736
            dst += screen->pitch;
slouken@1662
   737
        }
slouken@1662
   738
slouken@1662
   739
        /* Perform pixel conversion on cursor background */
slouken@1662
   740
        if (src > SDL_cursor->save[1]) {
slouken@1668
   741
            SDL_ConvertCursorSave(screen, area.w, area.h);
slouken@1662
   742
        }
slouken@1662
   743
    }
slouken@0
   744
}
slouken@0
   745
slouken@1662
   746
void
slouken@1668
   747
SDL_EraseCursor(SDL_Surface * screen)
slouken@0
   748
{
slouken@1662
   749
    /* Lock the screen if necessary */
slouken@1662
   750
    if (screen == NULL) {
slouken@1662
   751
        return;
slouken@1662
   752
    }
slouken@1668
   753
    if (SDL_MUSTLOCK(screen)) {
slouken@1668
   754
        if (SDL_LockSurface(screen) < 0) {
slouken@1662
   755
            return;
slouken@1662
   756
        }
slouken@1662
   757
    }
slouken@0
   758
slouken@1668
   759
    SDL_EraseCursorNoLock(screen);
slouken@0
   760
slouken@1662
   761
    /* Unlock the screen and update if necessary */
slouken@1668
   762
    if (SDL_MUSTLOCK(screen)) {
slouken@1668
   763
        SDL_UnlockSurface(screen);
slouken@1662
   764
    }
slouken@1662
   765
    if ((screen->flags & SDL_SCREEN_SURFACE) &&
slouken@1662
   766
        !(screen->flags & SDL_HWSURFACE)) {
slouken@1668
   767
        SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@1662
   768
        SDL_Window *window;
slouken@1662
   769
        SDL_Rect area;
slouken@0
   770
slouken@1668
   771
        window = SDL_GetWindowFromSurface(screen);
slouken@1662
   772
        if (!window) {
slouken@1662
   773
            return;
slouken@1662
   774
        }
slouken@1662
   775
slouken@1668
   776
        SDL_MouseRect(&area);
slouken@1662
   777
slouken@1662
   778
        if (_this->UpdateWindowSurface) {
slouken@1668
   779
            _this->UpdateWindowSurface(_this, window, 1, &area);
slouken@1662
   780
        }
slouken@1662
   781
    }
slouken@0
   782
}
slouken@0
   783
slouken@0
   784
/* Reset the cursor on video mode change
slouken@0
   785
   FIXME:  Keep track of all cursors, and reset them all.
slouken@0
   786
 */
slouken@1662
   787
void
slouken@1668
   788
SDL_ResetCursor(void)
slouken@0
   789
{
slouken@1662
   790
    int savelen;
slouken@0
   791
slouken@1662
   792
    if (SDL_cursor) {
slouken@1662
   793
        savelen = SDL_cursor->area.w * 4 * SDL_cursor->area.h;
slouken@1662
   794
        SDL_cursor->area.x = 0;
slouken@1662
   795
        SDL_cursor->area.y = 0;
slouken@1668
   796
        SDL_memset(SDL_cursor->save[0], 0, savelen);
slouken@1662
   797
    }
slouken@0
   798
}
slouken@1662
   799
slouken@1662
   800
/* vi: set ts=4 sw=4 expandtab: */