src/video/x11/SDL_x11mouse.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 13 Oct 2011 01:08:30 -0400
changeset 5981 75caa8a7d559
parent 5535 96594ac5fd1a
child 6138 4c64952a58fb
permissions -rw-r--r--
Fixed a whole slew of compiler warnings that -Wall exposed.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_X11
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_x11video.h"
    27 #include "SDL_x11mouse.h"
    28 #include "../../events/SDL_mouse_c.h"
    29 
    30 
    31 /* FIXME: Find a better place to put this... */
    32 static Cursor x11_empty_cursor = None;
    33 
    34 static Display *
    35 GetDisplay(void)
    36 {
    37     return ((SDL_VideoData *)SDL_GetVideoDevice()->driverdata)->display;
    38 }
    39 
    40 static Cursor
    41 X11_CreateEmptyCursor()
    42 {
    43     if (x11_empty_cursor == None) {
    44         Display *display = GetDisplay();
    45         char data[1];
    46         XColor color;
    47         Pixmap pixmap;
    48 
    49         SDL_zero(data);
    50         color.red = color.green = color.blue = 0;
    51         pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
    52                                        data, 1, 1);
    53         if (pixmap) {
    54             x11_empty_cursor = XCreatePixmapCursor(display, pixmap, pixmap,
    55                                                    &color, &color, 0, 0);
    56             XFreePixmap(display, pixmap);
    57         }
    58     }
    59     return x11_empty_cursor;
    60 }
    61 
    62 static void
    63 X11_DestroyEmptyCursor(void)
    64 {
    65     if (x11_empty_cursor != None) {
    66         XFreeCursor(GetDisplay(), x11_empty_cursor);
    67         x11_empty_cursor = None;
    68     }
    69 }
    70 
    71 static SDL_Cursor *
    72 X11_CreateDefaultCursor()
    73 {
    74     SDL_Cursor *cursor;
    75 
    76     cursor = SDL_calloc(1, sizeof(*cursor));
    77     if (cursor) {
    78         /* None is used to indicate the default cursor */
    79         cursor->driverdata = (void*)None;
    80     } else {
    81         SDL_OutOfMemory();
    82     }
    83 
    84     return cursor;
    85 }
    86 
    87 #if SDL_VIDEO_DRIVER_X11_XCURSOR
    88 static Cursor
    89 X11_CreateXCursorCursor(SDL_Surface * surface, int hot_x, int hot_y)
    90 {
    91     Display *display = GetDisplay();
    92     Cursor cursor = None;
    93     XcursorImage *image;
    94 
    95     image = XcursorImageCreate(surface->w, surface->h);
    96     if (!image) {
    97         SDL_OutOfMemory();
    98         return None;
    99     }
   100     image->xhot = hot_x;
   101     image->yhot = hot_y;
   102     image->delay = 0;
   103 
   104     SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
   105     SDL_assert(surface->pitch == surface->w * 4);
   106     SDL_memcpy(image->pixels, surface->pixels, surface->h * surface->pitch);
   107 
   108     cursor = XcursorImageLoadCursor(display, image);
   109 
   110     XcursorImageDestroy(image);
   111 
   112     return cursor;
   113 }
   114 #endif /* SDL_VIDEO_DRIVER_X11_XCURSOR */
   115 
   116 static Cursor
   117 X11_CreatePixmapCursor(SDL_Surface * surface, int hot_x, int hot_y)
   118 {
   119     Display *display = GetDisplay();
   120     XColor fg, bg;
   121     Cursor cursor = None;
   122     Uint32 *ptr;
   123     Uint8 *data_bits, *mask_bits;
   124     Pixmap data_pixmap, mask_pixmap;
   125     int x, y;
   126     unsigned int rfg, gfg, bfg, rbg, gbg, bbg, fgBits, bgBits;
   127     unsigned int width_bytes = ((surface->w + 7) & ~7) / 8;
   128 
   129     data_bits = SDL_calloc(1, surface->h * width_bytes);
   130     mask_bits = SDL_calloc(1, surface->h * width_bytes);
   131     if (!data_bits || !mask_bits) {
   132         SDL_OutOfMemory();
   133         return None;
   134     }
   135 
   136     /* Code below assumes ARGB pixel format */
   137     SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
   138 
   139     rfg = gfg = bfg = rbg = gbg = bbg = fgBits = bgBits = 0;
   140     for (y = 0; y < surface->h; ++y) {
   141         ptr = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch);
   142         for (x = 0; x < surface->w; ++x) {
   143             int alpha = (*ptr >> 24) & 0xff;
   144             int red   = (*ptr >> 16) & 0xff;
   145             int green = (*ptr >> 8) & 0xff;
   146             int blue  = (*ptr >> 0) & 0xff;
   147             if (alpha > 25) {
   148                 mask_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
   149 
   150                 if ((red + green + blue) > 0x40) {
   151                     fgBits++;
   152                     rfg += red;
   153                     gfg += green;
   154                     bfg += blue;
   155                     data_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
   156                 } else {
   157                     bgBits++;
   158                     rbg += red;
   159                     gbg += green;
   160                     bbg += blue;
   161                 }
   162             }
   163             ++ptr;
   164         }
   165     }
   166 
   167     if (fgBits) {
   168         fg.red   = rfg * 257 / fgBits;
   169         fg.green = gfg * 257 / fgBits;
   170         fg.blue  = bfg * 257 / fgBits;
   171     }
   172     else fg.red = fg.green = fg.blue = 0;
   173 
   174     if (bgBits) {
   175         bg.red   = rbg * 257 / bgBits;
   176         bg.green = gbg * 257 / bgBits;
   177         bg.blue  = bbg * 257 / bgBits;
   178     }
   179     else bg.red = bg.green = bg.blue = 0;
   180 
   181     data_pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
   182                                         (char*)data_bits,
   183                                         surface->w, surface->h);
   184     mask_pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
   185                                         (char*)mask_bits,
   186                                         surface->w, surface->h);
   187     cursor = XCreatePixmapCursor(display, data_pixmap, mask_pixmap,
   188                                  &fg, &bg, hot_x, hot_y);
   189 	XFreePixmap(display, data_pixmap);
   190 	XFreePixmap(display, mask_pixmap);
   191 
   192     return cursor;
   193 }
   194 
   195 static SDL_Cursor *
   196 X11_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
   197 {
   198     SDL_Cursor *cursor;
   199 
   200     cursor = SDL_calloc(1, sizeof(*cursor));
   201     if (cursor) {
   202         Cursor x11_cursor = None;
   203 
   204 #if SDL_VIDEO_DRIVER_X11_XCURSOR
   205         if (SDL_X11_HAVE_XCURSOR) {
   206             x11_cursor = X11_CreateXCursorCursor(surface, hot_x, hot_y);
   207         }
   208 #endif
   209         if (x11_cursor == None) {
   210             x11_cursor = X11_CreatePixmapCursor(surface, hot_x, hot_y);
   211         }
   212         cursor->driverdata = (void*)x11_cursor;
   213     } else {
   214         SDL_OutOfMemory();
   215     }
   216 
   217     return cursor;
   218 }
   219 
   220 static void
   221 X11_FreeCursor(SDL_Cursor * cursor)
   222 {
   223     Cursor x11_cursor = (Cursor)cursor->driverdata;
   224 
   225     if (x11_cursor != None) {
   226         XFreeCursor(GetDisplay(), x11_cursor);
   227     }
   228     SDL_free(cursor);
   229 }
   230 
   231 static int
   232 X11_ShowCursor(SDL_Cursor * cursor)
   233 {
   234     Cursor x11_cursor = 0;
   235 
   236     if (cursor) {
   237         x11_cursor = (Cursor)cursor->driverdata;
   238     } else {
   239         x11_cursor = X11_CreateEmptyCursor();
   240     }
   241 
   242     /* FIXME: Is there a better way than this? */
   243     {
   244         SDL_VideoDevice *video = SDL_GetVideoDevice();
   245         Display *display = GetDisplay();
   246         SDL_Window *window;
   247         SDL_WindowData *data;
   248 
   249         for (window = video->windows; window; window = window->next) {
   250             data = (SDL_WindowData *)window->driverdata;
   251             if (x11_cursor != None) {
   252                 XDefineCursor(display, data->xwindow, x11_cursor);
   253             } else {
   254                 XUndefineCursor(display, data->xwindow);
   255             }
   256         }
   257         XFlush(display);
   258     }
   259     return 0;
   260 }
   261 
   262 static void
   263 X11_WarpMouse(SDL_Window * window, int x, int y)
   264 {
   265     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   266     Display *display = data->videodata->display;
   267 
   268     XWarpPointer(display, None, data->xwindow, 0, 0, 0, 0, x, y);
   269     XSync(display, False);
   270 }
   271 
   272 static int
   273 X11_SetRelativeMouseMode(SDL_bool enabled)
   274 {
   275     SDL_Unsupported();
   276     return -1;
   277 }
   278 
   279 void
   280 X11_InitMouse(_THIS)
   281 {
   282     SDL_Mouse *mouse = SDL_GetMouse();
   283 
   284     mouse->CreateCursor = X11_CreateCursor;
   285     mouse->ShowCursor = X11_ShowCursor;
   286     mouse->FreeCursor = X11_FreeCursor;
   287     mouse->WarpMouse = X11_WarpMouse;
   288     mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode;
   289 
   290     SDL_SetDefaultCursor(X11_CreateDefaultCursor());
   291 }
   292 
   293 void
   294 X11_QuitMouse(_THIS)
   295 {
   296     X11_DestroyEmptyCursor();
   297 }
   298 
   299 #endif /* SDL_VIDEO_DRIVER_X11 */
   300 
   301 /* vi: set ts=4 sw=4 expandtab: */