Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Implemented X11 cursor support.
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Mar 11, 2011
1 parent 29703c5 commit ebab52b
Show file tree
Hide file tree
Showing 2 changed files with 216 additions and 0 deletions.
215 changes: 215 additions & 0 deletions src/video/x11/SDL_x11mouse.c
Expand Up @@ -24,14 +24,229 @@
#include "SDL_x11mouse.h"
#include "../../events/SDL_mouse_c.h"


/* FIXME: Find a better place to put this... */
static Cursor x11_empty_cursor = None;

static Display *
GetDisplay(void)
{
return ((SDL_VideoData *)SDL_GetVideoDevice()->driverdata)->display;
}

static Cursor
X11_CreateEmptyCursor()
{
if (x11_empty_cursor == None) {
Display *display = GetDisplay();
char data[1];
XColor color;
Pixmap pixmap;

SDL_zero(data);
color.red = color.green = color.blue = 0;
pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
data, 1, 1);
if (pixmap) {
x11_empty_cursor = XCreatePixmapCursor(display, pixmap, pixmap,
&color, &color, 0, 0);
XFreePixmap(display, pixmap);
}
}
return x11_empty_cursor;
}

static void
X11_DestroyEmptyCursor(void)
{
if (x11_empty_cursor != None) {
XFreeCursor(GetDisplay(), x11_empty_cursor);
x11_empty_cursor = None;
}
}

static SDL_Cursor *
X11_CreateDefaultCursor()
{
SDL_Cursor *cursor;

cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
/* None is used to indicate the default cursor */
cursor->driverdata = (void*)None;
} else {
SDL_OutOfMemory();
}

return cursor;
}

static Cursor
X11_CreatePixmapCursor(SDL_Surface * surface, int hot_x, int hot_y)
{
Display *display = GetDisplay();
XColor fg, bg;
Cursor cursor = None;
Uint32 *ptr;
Uint8 *data_bits, *mask_bits;
Pixmap data_pixmap, mask_pixmap;
int x, y;
unsigned int rfg, gfg, bfg, rbg, gbg, bbg, fgBits, bgBits;
unsigned int width_bytes = ((surface->w + 7) & ~7) / 8;

data_bits = SDL_calloc(1, surface->h * width_bytes);
mask_bits = SDL_calloc(1, surface->h * width_bytes);
if (!data_bits || !mask_bits) {
SDL_OutOfMemory();
return None;
}

rfg = gfg = bfg = rbg = gbg = bbg = fgBits = 0;
for (y = 0; y < surface->h; ++y) {
ptr = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch);
for (x = 0; x < surface->w; ++x) {
int alpha = (*ptr >> 24) & 0xff;
int red = (*ptr >> 16) & 0xff;
int green = (*ptr >> 8) & 0xff;
int blue = (*ptr >> 0) & 0xff;
if (alpha > 25) {
mask_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));

if ((red + green + blue) > 0x40) {
fgBits++;
rfg += red;
gfg += green;
bfg += blue;
data_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
} else {
bgBits++;
rbg += red;
gbg += green;
bbg += blue;
}
}
++ptr;
}
}

if (fgBits) {
fg.red = rfg * 257 / fgBits;
fg.green = gfg * 257 / fgBits;
fg.blue = bfg * 257 / fgBits;
}
else fg.red = fg.green = fg.blue = 0;

if (bgBits) {
bg.red = rbg * 257 / bgBits;
bg.green = gbg * 257 / bgBits;
bg.blue = bbg * 257 / bgBits;
}
else bg.red = bg.green = bg.blue = 0;

data_pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
data_bits, surface->w, surface->h);
mask_pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
mask_bits, surface->w, surface->h);
cursor = XCreatePixmapCursor(display, data_pixmap, mask_pixmap,
&fg, &bg, hot_x, hot_y);
XFreePixmap(display, data_pixmap);
XFreePixmap(display, mask_pixmap);

return cursor;
}

static SDL_Cursor *
X11_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
{
SDL_Cursor *cursor;

cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
cursor->driverdata = (void*)X11_CreatePixmapCursor(surface, hot_x, hot_y);
} else {
SDL_OutOfMemory();
}

return cursor;
}

static void
X11_FreeCursor(SDL_Cursor * cursor)
{
Cursor x11_cursor = (Cursor)cursor->driverdata;

if (x11_cursor != None) {
XFreeCursor(GetDisplay(), x11_cursor);
}
SDL_free(cursor);
}

static int
X11_ShowCursor(SDL_Cursor * cursor)
{
Cursor x11_cursor = 0;

if (cursor) {
x11_cursor = (Cursor)cursor->driverdata;
} else {
x11_cursor = X11_CreateEmptyCursor();
}

/* FIXME: Is there a better way than this? */
{
SDL_VideoDevice *video = SDL_GetVideoDevice();
Display *display = GetDisplay();
SDL_Window *window;
SDL_WindowData *data;

for (window = video->windows; window; window = window->next) {
data = (SDL_WindowData *)window->driverdata;
if (x11_cursor != None) {
XDefineCursor(display, data->xwindow, x11_cursor);
} else {
XUndefineCursor(display, data->xwindow);
}
}
XFlush(display);
}
return 0;
}

static void
X11_WarpMouse(SDL_Window * window, int x, int y)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
Display *display = data->videodata->display;

XWarpPointer(display, None, data->xwindow, 0, 0, 0, 0, x, y);
XSync(display, False);
}

static int
X11_SetRelativeMouseMode(SDL_bool enabled)
{
SDL_Unsupported();
return -1;
}

void
X11_InitMouse(_THIS)
{
SDL_Mouse *mouse = SDL_GetMouse();

mouse->CreateCursor = X11_CreateCursor;
mouse->ShowCursor = X11_ShowCursor;
mouse->FreeCursor = X11_FreeCursor;
mouse->WarpMouse = X11_WarpMouse;
mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode;

SDL_SetDefaultCursor(X11_CreateDefaultCursor());
}

void
X11_QuitMouse(_THIS)
{
X11_DestroyEmptyCursor();
}

/* vi: set ts=4 sw=4 expandtab: */
1 change: 1 addition & 0 deletions src/video/x11/SDL_x11sym.h
Expand Up @@ -98,6 +98,7 @@ SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d)
SDL_X11_SYM(int,XStoreColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return)
SDL_X11_SYM(Status,XStringListToTextProperty,(char** a,int b,XTextProperty* c),(a,b,c),return)
SDL_X11_SYM(int,XSync,(Display* a,Bool b),(a,b),return)
SDL_X11_SYM(int,XUndefineCursor,(Display* a,Window b),(a,b),return)
SDL_X11_SYM(int,XUngrabKeyboard,(Display* a,Time b),(a,b),return)
SDL_X11_SYM(int,XUngrabPointer,(Display* a,Time b),(a,b),return)
SDL_X11_SYM(int,XUngrabServer,(Display* a),(a),return)
Expand Down

0 comments on commit ebab52b

Please sign in to comment.