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