Implemented X11 cursor support.
authorSam Lantinga <slouken@libsdl.org>
Fri, 11 Mar 2011 13:27:25 -0800
changeset 54708f5e10ec4faf
parent 5469 810b7f9bac86
child 5471 179adad3ae6f
Implemented X11 cursor support.
src/video/x11/SDL_x11mouse.c
src/video/x11/SDL_x11sym.h
     1.1 --- a/src/video/x11/SDL_x11mouse.c	Fri Mar 11 13:22:43 2011 -0800
     1.2 +++ b/src/video/x11/SDL_x11mouse.c	Fri Mar 11 13:27:25 2011 -0800
     1.3 @@ -24,14 +24,229 @@
     1.4  #include "SDL_x11mouse.h"
     1.5  #include "../../events/SDL_mouse_c.h"
     1.6  
     1.7 +
     1.8 +/* FIXME: Find a better place to put this... */
     1.9 +static Cursor x11_empty_cursor = None;
    1.10 +
    1.11 +static Display *
    1.12 +GetDisplay(void)
    1.13 +{
    1.14 +    return ((SDL_VideoData *)SDL_GetVideoDevice()->driverdata)->display;
    1.15 +}
    1.16 +
    1.17 +static Cursor
    1.18 +X11_CreateEmptyCursor()
    1.19 +{
    1.20 +    if (x11_empty_cursor == None) {
    1.21 +        Display *display = GetDisplay();
    1.22 +        char data[1];
    1.23 +        XColor color;
    1.24 +        Pixmap pixmap;
    1.25 +
    1.26 +        SDL_zero(data);
    1.27 +        color.red = color.green = color.blue = 0;
    1.28 +        pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
    1.29 +                                       data, 1, 1);
    1.30 +        if (pixmap) {
    1.31 +            x11_empty_cursor = XCreatePixmapCursor(display, pixmap, pixmap,
    1.32 +                                                   &color, &color, 0, 0);
    1.33 +            XFreePixmap(display, pixmap);
    1.34 +        }
    1.35 +    }
    1.36 +    return x11_empty_cursor;
    1.37 +}
    1.38 +
    1.39 +static void
    1.40 +X11_DestroyEmptyCursor(void)
    1.41 +{
    1.42 +    if (x11_empty_cursor != None) {
    1.43 +        XFreeCursor(GetDisplay(), x11_empty_cursor);
    1.44 +        x11_empty_cursor = None;
    1.45 +    }
    1.46 +}
    1.47 +
    1.48 +static SDL_Cursor *
    1.49 +X11_CreateDefaultCursor()
    1.50 +{
    1.51 +    SDL_Cursor *cursor;
    1.52 +
    1.53 +    cursor = SDL_calloc(1, sizeof(*cursor));
    1.54 +    if (cursor) {
    1.55 +        /* None is used to indicate the default cursor */
    1.56 +        cursor->driverdata = (void*)None;
    1.57 +    } else {
    1.58 +        SDL_OutOfMemory();
    1.59 +    }
    1.60 +
    1.61 +    return cursor;
    1.62 +}
    1.63 +
    1.64 +static Cursor
    1.65 +X11_CreatePixmapCursor(SDL_Surface * surface, int hot_x, int hot_y)
    1.66 +{
    1.67 +    Display *display = GetDisplay();
    1.68 +    XColor fg, bg;
    1.69 +    Cursor cursor = None;
    1.70 +    Uint32 *ptr;
    1.71 +    Uint8 *data_bits, *mask_bits;
    1.72 +    Pixmap data_pixmap, mask_pixmap;
    1.73 +    int x, y;
    1.74 +    unsigned int rfg, gfg, bfg, rbg, gbg, bbg, fgBits, bgBits;
    1.75 +    unsigned int width_bytes = ((surface->w + 7) & ~7) / 8;
    1.76 +
    1.77 +    data_bits = SDL_calloc(1, surface->h * width_bytes);
    1.78 +    mask_bits = SDL_calloc(1, surface->h * width_bytes);
    1.79 +    if (!data_bits || !mask_bits) {
    1.80 +        SDL_OutOfMemory();
    1.81 +        return None;
    1.82 +    }
    1.83 +
    1.84 +    rfg = gfg = bfg = rbg = gbg = bbg = fgBits = 0;
    1.85 +    for (y = 0; y < surface->h; ++y) {
    1.86 +        ptr = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch);
    1.87 +        for (x = 0; x < surface->w; ++x) {
    1.88 +            int alpha = (*ptr >> 24) & 0xff;
    1.89 +            int red   = (*ptr >> 16) & 0xff;
    1.90 +            int green = (*ptr >> 8) & 0xff;
    1.91 +            int blue  = (*ptr >> 0) & 0xff;
    1.92 +            if (alpha > 25) {
    1.93 +                mask_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
    1.94 +
    1.95 +                if ((red + green + blue) > 0x40) {
    1.96 +                    fgBits++;
    1.97 +                    rfg += red;
    1.98 +                    gfg += green;
    1.99 +                    bfg += blue;
   1.100 +                    data_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
   1.101 +                } else {
   1.102 +                    bgBits++;
   1.103 +                    rbg += red;
   1.104 +                    gbg += green;
   1.105 +                    bbg += blue;
   1.106 +                }
   1.107 +            }
   1.108 +            ++ptr;
   1.109 +        }
   1.110 +    }
   1.111 +
   1.112 +    if (fgBits) {
   1.113 +        fg.red   = rfg * 257 / fgBits;
   1.114 +        fg.green = gfg * 257 / fgBits;
   1.115 +        fg.blue  = bfg * 257 / fgBits;
   1.116 +    }
   1.117 +    else fg.red = fg.green = fg.blue = 0;
   1.118 +
   1.119 +    if (bgBits) {
   1.120 +        bg.red   = rbg * 257 / bgBits;
   1.121 +        bg.green = gbg * 257 / bgBits;
   1.122 +        bg.blue  = bbg * 257 / bgBits;
   1.123 +    }
   1.124 +    else bg.red = bg.green = bg.blue = 0;
   1.125 +
   1.126 +    data_pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
   1.127 +                                        data_bits, surface->w, surface->h);
   1.128 +    mask_pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
   1.129 +                                        mask_bits, surface->w, surface->h);
   1.130 +    cursor = XCreatePixmapCursor(display, data_pixmap, mask_pixmap,
   1.131 +                                 &fg, &bg, hot_x, hot_y);
   1.132 +	XFreePixmap(display, data_pixmap);
   1.133 +	XFreePixmap(display, mask_pixmap);
   1.134 +
   1.135 +    return cursor;
   1.136 +}
   1.137 +
   1.138 +static SDL_Cursor *
   1.139 +X11_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
   1.140 +{
   1.141 +    SDL_Cursor *cursor;
   1.142 +
   1.143 +    cursor = SDL_calloc(1, sizeof(*cursor));
   1.144 +    if (cursor) {
   1.145 +        cursor->driverdata = (void*)X11_CreatePixmapCursor(surface, hot_x, hot_y);
   1.146 +    } else {
   1.147 +        SDL_OutOfMemory();
   1.148 +    }
   1.149 +
   1.150 +    return cursor;
   1.151 +}
   1.152 +
   1.153 +static void
   1.154 +X11_FreeCursor(SDL_Cursor * cursor)
   1.155 +{
   1.156 +    Cursor x11_cursor = (Cursor)cursor->driverdata;
   1.157 +
   1.158 +    if (x11_cursor != None) {
   1.159 +        XFreeCursor(GetDisplay(), x11_cursor);
   1.160 +    }
   1.161 +    SDL_free(cursor);
   1.162 +}
   1.163 +
   1.164 +static int
   1.165 +X11_ShowCursor(SDL_Cursor * cursor)
   1.166 +{
   1.167 +    Cursor x11_cursor = 0;
   1.168 +
   1.169 +    if (cursor) {
   1.170 +        x11_cursor = (Cursor)cursor->driverdata;
   1.171 +    } else {
   1.172 +        x11_cursor = X11_CreateEmptyCursor();
   1.173 +    }
   1.174 +
   1.175 +    /* FIXME: Is there a better way than this? */
   1.176 +    {
   1.177 +        SDL_VideoDevice *video = SDL_GetVideoDevice();
   1.178 +        Display *display = GetDisplay();
   1.179 +        SDL_Window *window;
   1.180 +        SDL_WindowData *data;
   1.181 +
   1.182 +        for (window = video->windows; window; window = window->next) {
   1.183 +            data = (SDL_WindowData *)window->driverdata;
   1.184 +            if (x11_cursor != None) {
   1.185 +                XDefineCursor(display, data->xwindow, x11_cursor);
   1.186 +            } else {
   1.187 +                XUndefineCursor(display, data->xwindow);
   1.188 +            }
   1.189 +        }
   1.190 +        XFlush(display);
   1.191 +    }
   1.192 +    return 0;
   1.193 +}
   1.194 +
   1.195 +static void
   1.196 +X11_WarpMouse(SDL_Window * window, int x, int y)
   1.197 +{
   1.198 +    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   1.199 +    Display *display = data->videodata->display;
   1.200 +
   1.201 +    XWarpPointer(display, None, data->xwindow, 0, 0, 0, 0, x, y);
   1.202 +    XSync(display, False);
   1.203 +}
   1.204 +
   1.205 +static int
   1.206 +X11_SetRelativeMouseMode(SDL_bool enabled)
   1.207 +{
   1.208 +    SDL_Unsupported();
   1.209 +    return -1;
   1.210 +}
   1.211 +
   1.212  void
   1.213  X11_InitMouse(_THIS)
   1.214  {
   1.215 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.216 +
   1.217 +    mouse->CreateCursor = X11_CreateCursor;
   1.218 +    mouse->ShowCursor = X11_ShowCursor;
   1.219 +    mouse->FreeCursor = X11_FreeCursor;
   1.220 +    mouse->WarpMouse = X11_WarpMouse;
   1.221 +    mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode;
   1.222 +
   1.223 +    SDL_SetDefaultCursor(X11_CreateDefaultCursor());
   1.224  }
   1.225  
   1.226  void
   1.227  X11_QuitMouse(_THIS)
   1.228  {
   1.229 +    X11_DestroyEmptyCursor();
   1.230  }
   1.231  
   1.232  /* vi: set ts=4 sw=4 expandtab: */
     2.1 --- a/src/video/x11/SDL_x11sym.h	Fri Mar 11 13:22:43 2011 -0800
     2.2 +++ b/src/video/x11/SDL_x11sym.h	Fri Mar 11 13:27:25 2011 -0800
     2.3 @@ -98,6 +98,7 @@
     2.4  SDL_X11_SYM(int,XStoreColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return)
     2.5  SDL_X11_SYM(Status,XStringListToTextProperty,(char** a,int b,XTextProperty* c),(a,b,c),return)
     2.6  SDL_X11_SYM(int,XSync,(Display* a,Bool b),(a,b),return)
     2.7 +SDL_X11_SYM(int,XUndefineCursor,(Display* a,Window b),(a,b),return)
     2.8  SDL_X11_SYM(int,XUngrabKeyboard,(Display* a,Time b),(a,b),return)
     2.9  SDL_X11_SYM(int,XUngrabPointer,(Display* a,Time b),(a,b),return)
    2.10  SDL_X11_SYM(int,XUngrabServer,(Display* a),(a),return)