src/video/x11/SDL_x11mouse.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 12 Mar 2011 13:21:57 -0800
changeset 5481 22dfc3958dc3
parent 5471 179adad3ae6f
child 5505 c4bb4c8ea6fd
permissions -rw-r--r--
Fixed so code will compile with SDL_config_minimal.h
slouken@1950
     1
/*
slouken@1950
     2
    SDL - Simple DirectMedia Layer
slouken@5262
     3
    Copyright (C) 1997-2011 Sam Lantinga
slouken@1950
     4
slouken@1950
     5
    This library is free software; you can redistribute it and/or
slouken@1950
     6
    modify it under the terms of the GNU Lesser General Public
slouken@1950
     7
    License as published by the Free Software Foundation; either
slouken@1950
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@1950
     9
slouken@1950
    10
    This library is distributed in the hope that it will be useful,
slouken@1950
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@1950
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1950
    13
    Lesser General Public License for more details.
slouken@1950
    14
slouken@1950
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1950
    16
    License along with this library; if not, write to the Free Software
slouken@1950
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@1950
    18
slouken@1950
    19
    Sam Lantinga
slouken@1950
    20
    slouken@libsdl.org
slouken@1950
    21
*/
slouken@1950
    22
#include "SDL_config.h"
slouken@5471
    23
slouken@5481
    24
#if SDL_VIDEO_DRIVER_X11
slouken@5481
    25
slouken@5471
    26
#include "SDL_assert.h"
slouken@1950
    27
#include "SDL_x11video.h"
slouken@2940
    28
#include "SDL_x11mouse.h"
slouken@1950
    29
#include "../../events/SDL_mouse_c.h"
slouken@1950
    30
slouken@5470
    31
slouken@5470
    32
/* FIXME: Find a better place to put this... */
slouken@5470
    33
static Cursor x11_empty_cursor = None;
slouken@5470
    34
slouken@5470
    35
static Display *
slouken@5470
    36
GetDisplay(void)
slouken@5470
    37
{
slouken@5470
    38
    return ((SDL_VideoData *)SDL_GetVideoDevice()->driverdata)->display;
slouken@5470
    39
}
slouken@5470
    40
slouken@5470
    41
static Cursor
slouken@5470
    42
X11_CreateEmptyCursor()
slouken@5470
    43
{
slouken@5470
    44
    if (x11_empty_cursor == None) {
slouken@5470
    45
        Display *display = GetDisplay();
slouken@5470
    46
        char data[1];
slouken@5470
    47
        XColor color;
slouken@5470
    48
        Pixmap pixmap;
slouken@5470
    49
slouken@5470
    50
        SDL_zero(data);
slouken@5470
    51
        color.red = color.green = color.blue = 0;
slouken@5470
    52
        pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
slouken@5470
    53
                                       data, 1, 1);
slouken@5470
    54
        if (pixmap) {
slouken@5470
    55
            x11_empty_cursor = XCreatePixmapCursor(display, pixmap, pixmap,
slouken@5470
    56
                                                   &color, &color, 0, 0);
slouken@5470
    57
            XFreePixmap(display, pixmap);
slouken@5470
    58
        }
slouken@5470
    59
    }
slouken@5470
    60
    return x11_empty_cursor;
slouken@5470
    61
}
slouken@5470
    62
slouken@5470
    63
static void
slouken@5470
    64
X11_DestroyEmptyCursor(void)
slouken@5470
    65
{
slouken@5470
    66
    if (x11_empty_cursor != None) {
slouken@5470
    67
        XFreeCursor(GetDisplay(), x11_empty_cursor);
slouken@5470
    68
        x11_empty_cursor = None;
slouken@5470
    69
    }
slouken@5470
    70
}
slouken@5470
    71
slouken@5470
    72
static SDL_Cursor *
slouken@5470
    73
X11_CreateDefaultCursor()
slouken@5470
    74
{
slouken@5470
    75
    SDL_Cursor *cursor;
slouken@5470
    76
slouken@5470
    77
    cursor = SDL_calloc(1, sizeof(*cursor));
slouken@5470
    78
    if (cursor) {
slouken@5470
    79
        /* None is used to indicate the default cursor */
slouken@5470
    80
        cursor->driverdata = (void*)None;
slouken@5470
    81
    } else {
slouken@5470
    82
        SDL_OutOfMemory();
slouken@5470
    83
    }
slouken@5470
    84
slouken@5470
    85
    return cursor;
slouken@5470
    86
}
slouken@5470
    87
slouken@5471
    88
#if SDL_VIDEO_DRIVER_X11_XCURSOR
slouken@5471
    89
static Cursor
slouken@5471
    90
X11_CreateXCursorCursor(SDL_Surface * surface, int hot_x, int hot_y)
slouken@5471
    91
{
slouken@5471
    92
    Display *display = GetDisplay();
slouken@5471
    93
    Cursor cursor = None;
slouken@5471
    94
    XcursorImage *image;
slouken@5471
    95
slouken@5471
    96
    image = XcursorImageCreate(surface->w, surface->h);
slouken@5471
    97
    if (!image) {
slouken@5471
    98
        SDL_OutOfMemory();
slouken@5471
    99
        return None;
slouken@5471
   100
    }
slouken@5471
   101
    image->xhot = hot_x;
slouken@5471
   102
    image->yhot = hot_y;
slouken@5471
   103
    image->delay = 0;
slouken@5471
   104
slouken@5471
   105
    SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
slouken@5471
   106
    SDL_assert(surface->pitch == surface->w * 4);
slouken@5471
   107
    SDL_memcpy(image->pixels, surface->pixels, surface->h * surface->pitch);
slouken@5471
   108
slouken@5471
   109
    cursor = XcursorImageLoadCursor(display, image);
slouken@5471
   110
slouken@5471
   111
    XcursorImageDestroy(image);
slouken@5471
   112
slouken@5471
   113
    return cursor;
slouken@5471
   114
}
slouken@5471
   115
#endif /* SDL_VIDEO_DRIVER_X11_XCURSOR */
slouken@5471
   116
slouken@5470
   117
static Cursor
slouken@5470
   118
X11_CreatePixmapCursor(SDL_Surface * surface, int hot_x, int hot_y)
slouken@5470
   119
{
slouken@5470
   120
    Display *display = GetDisplay();
slouken@5470
   121
    XColor fg, bg;
slouken@5470
   122
    Cursor cursor = None;
slouken@5470
   123
    Uint32 *ptr;
slouken@5470
   124
    Uint8 *data_bits, *mask_bits;
slouken@5470
   125
    Pixmap data_pixmap, mask_pixmap;
slouken@5470
   126
    int x, y;
slouken@5470
   127
    unsigned int rfg, gfg, bfg, rbg, gbg, bbg, fgBits, bgBits;
slouken@5470
   128
    unsigned int width_bytes = ((surface->w + 7) & ~7) / 8;
slouken@5470
   129
slouken@5470
   130
    data_bits = SDL_calloc(1, surface->h * width_bytes);
slouken@5470
   131
    mask_bits = SDL_calloc(1, surface->h * width_bytes);
slouken@5470
   132
    if (!data_bits || !mask_bits) {
slouken@5470
   133
        SDL_OutOfMemory();
slouken@5470
   134
        return None;
slouken@5470
   135
    }
slouken@5470
   136
slouken@5471
   137
    /* Code below assumes ARGB pixel format */
slouken@5471
   138
    SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
slouken@5471
   139
slouken@5470
   140
    rfg = gfg = bfg = rbg = gbg = bbg = fgBits = 0;
slouken@5470
   141
    for (y = 0; y < surface->h; ++y) {
slouken@5470
   142
        ptr = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch);
slouken@5470
   143
        for (x = 0; x < surface->w; ++x) {
slouken@5470
   144
            int alpha = (*ptr >> 24) & 0xff;
slouken@5470
   145
            int red   = (*ptr >> 16) & 0xff;
slouken@5470
   146
            int green = (*ptr >> 8) & 0xff;
slouken@5470
   147
            int blue  = (*ptr >> 0) & 0xff;
slouken@5470
   148
            if (alpha > 25) {
slouken@5470
   149
                mask_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
slouken@5470
   150
slouken@5470
   151
                if ((red + green + blue) > 0x40) {
slouken@5470
   152
                    fgBits++;
slouken@5470
   153
                    rfg += red;
slouken@5470
   154
                    gfg += green;
slouken@5470
   155
                    bfg += blue;
slouken@5470
   156
                    data_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
slouken@5470
   157
                } else {
slouken@5470
   158
                    bgBits++;
slouken@5470
   159
                    rbg += red;
slouken@5470
   160
                    gbg += green;
slouken@5470
   161
                    bbg += blue;
slouken@5470
   162
                }
slouken@5470
   163
            }
slouken@5470
   164
            ++ptr;
slouken@5470
   165
        }
slouken@5470
   166
    }
slouken@5470
   167
slouken@5470
   168
    if (fgBits) {
slouken@5470
   169
        fg.red   = rfg * 257 / fgBits;
slouken@5470
   170
        fg.green = gfg * 257 / fgBits;
slouken@5470
   171
        fg.blue  = bfg * 257 / fgBits;
slouken@5470
   172
    }
slouken@5470
   173
    else fg.red = fg.green = fg.blue = 0;
slouken@5470
   174
slouken@5470
   175
    if (bgBits) {
slouken@5470
   176
        bg.red   = rbg * 257 / bgBits;
slouken@5470
   177
        bg.green = gbg * 257 / bgBits;
slouken@5470
   178
        bg.blue  = bbg * 257 / bgBits;
slouken@5470
   179
    }
slouken@5470
   180
    else bg.red = bg.green = bg.blue = 0;
slouken@5470
   181
slouken@5470
   182
    data_pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
slouken@5470
   183
                                        data_bits, surface->w, surface->h);
slouken@5470
   184
    mask_pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
slouken@5470
   185
                                        mask_bits, surface->w, surface->h);
slouken@5470
   186
    cursor = XCreatePixmapCursor(display, data_pixmap, mask_pixmap,
slouken@5470
   187
                                 &fg, &bg, hot_x, hot_y);
slouken@5470
   188
	XFreePixmap(display, data_pixmap);
slouken@5470
   189
	XFreePixmap(display, mask_pixmap);
slouken@5470
   190
slouken@5470
   191
    return cursor;
slouken@5470
   192
}
slouken@5470
   193
slouken@5470
   194
static SDL_Cursor *
slouken@5470
   195
X11_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
slouken@5470
   196
{
slouken@5470
   197
    SDL_Cursor *cursor;
slouken@5470
   198
slouken@5470
   199
    cursor = SDL_calloc(1, sizeof(*cursor));
slouken@5470
   200
    if (cursor) {
slouken@5471
   201
        Cursor x11_cursor = None;
slouken@5471
   202
slouken@5471
   203
#if SDL_VIDEO_DRIVER_X11_XCURSOR
slouken@5471
   204
        if (SDL_X11_HAVE_XCURSOR) {
slouken@5471
   205
            x11_cursor = X11_CreateXCursorCursor(surface, hot_x, hot_y);
slouken@5471
   206
        }
slouken@5471
   207
#endif
slouken@5471
   208
        if (x11_cursor == None) {
slouken@5471
   209
            x11_cursor = X11_CreatePixmapCursor(surface, hot_x, hot_y);
slouken@5471
   210
        }
slouken@5471
   211
        cursor->driverdata = (void*)x11_cursor;
slouken@5470
   212
    } else {
slouken@5470
   213
        SDL_OutOfMemory();
slouken@5470
   214
    }
slouken@5470
   215
slouken@5470
   216
    return cursor;
slouken@5470
   217
}
slouken@5470
   218
slouken@5470
   219
static void
slouken@5470
   220
X11_FreeCursor(SDL_Cursor * cursor)
slouken@5470
   221
{
slouken@5470
   222
    Cursor x11_cursor = (Cursor)cursor->driverdata;
slouken@5470
   223
slouken@5470
   224
    if (x11_cursor != None) {
slouken@5470
   225
        XFreeCursor(GetDisplay(), x11_cursor);
slouken@5470
   226
    }
slouken@5470
   227
    SDL_free(cursor);
slouken@5470
   228
}
slouken@5470
   229
slouken@5470
   230
static int
slouken@5470
   231
X11_ShowCursor(SDL_Cursor * cursor)
slouken@5470
   232
{
slouken@5470
   233
    Cursor x11_cursor = 0;
slouken@5470
   234
slouken@5470
   235
    if (cursor) {
slouken@5470
   236
        x11_cursor = (Cursor)cursor->driverdata;
slouken@5470
   237
    } else {
slouken@5470
   238
        x11_cursor = X11_CreateEmptyCursor();
slouken@5470
   239
    }
slouken@5470
   240
slouken@5470
   241
    /* FIXME: Is there a better way than this? */
slouken@5470
   242
    {
slouken@5470
   243
        SDL_VideoDevice *video = SDL_GetVideoDevice();
slouken@5470
   244
        Display *display = GetDisplay();
slouken@5470
   245
        SDL_Window *window;
slouken@5470
   246
        SDL_WindowData *data;
slouken@5470
   247
slouken@5470
   248
        for (window = video->windows; window; window = window->next) {
slouken@5470
   249
            data = (SDL_WindowData *)window->driverdata;
slouken@5470
   250
            if (x11_cursor != None) {
slouken@5470
   251
                XDefineCursor(display, data->xwindow, x11_cursor);
slouken@5470
   252
            } else {
slouken@5470
   253
                XUndefineCursor(display, data->xwindow);
slouken@5470
   254
            }
slouken@5470
   255
        }
slouken@5470
   256
        XFlush(display);
slouken@5470
   257
    }
slouken@5470
   258
    return 0;
slouken@5470
   259
}
slouken@5470
   260
slouken@5470
   261
static void
slouken@5470
   262
X11_WarpMouse(SDL_Window * window, int x, int y)
slouken@5470
   263
{
slouken@5470
   264
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@5470
   265
    Display *display = data->videodata->display;
slouken@5470
   266
slouken@5470
   267
    XWarpPointer(display, None, data->xwindow, 0, 0, 0, 0, x, y);
slouken@5470
   268
    XSync(display, False);
slouken@5470
   269
}
slouken@5470
   270
slouken@5470
   271
static int
slouken@5470
   272
X11_SetRelativeMouseMode(SDL_bool enabled)
slouken@5470
   273
{
slouken@5470
   274
    SDL_Unsupported();
slouken@5470
   275
    return -1;
slouken@5470
   276
}
slouken@5470
   277
slouken@1950
   278
void
slouken@1950
   279
X11_InitMouse(_THIS)
slouken@1950
   280
{
slouken@5470
   281
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5470
   282
slouken@5470
   283
    mouse->CreateCursor = X11_CreateCursor;
slouken@5470
   284
    mouse->ShowCursor = X11_ShowCursor;
slouken@5470
   285
    mouse->FreeCursor = X11_FreeCursor;
slouken@5470
   286
    mouse->WarpMouse = X11_WarpMouse;
slouken@5470
   287
    mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode;
slouken@5470
   288
slouken@5470
   289
    SDL_SetDefaultCursor(X11_CreateDefaultCursor());
slouken@1950
   290
}
slouken@1950
   291
slouken@1950
   292
void
slouken@1950
   293
X11_QuitMouse(_THIS)
slouken@1950
   294
{
slouken@5470
   295
    X11_DestroyEmptyCursor();
slouken@1950
   296
}
slouken@1950
   297
slouken@5481
   298
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@5481
   299
slouken@1950
   300
/* vi: set ts=4 sw=4 expandtab: */