src/events/SDL_mouse.c
author Sam Lantinga
Fri, 11 Mar 2011 14:14:38 -0800
changeset 5473 5665ccbd6792
parent 5406 1517da4ab6b1
child 5535 96594ac5fd1a
permissions -rw-r--r--
Added a function to create color cursors: SDL_CreateColorCursor()
     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 /* General mouse handling code for SDL */
    25 
    26 #include "SDL_events.h"
    27 #include "SDL_events_c.h"
    28 #include "default_cursor.h"
    29 #include "../video/SDL_sysvideo.h"
    30 
    31 
    32 /* The mouse state */
    33 static SDL_Mouse SDL_mouse;
    34 
    35 
    36 /* Public functions */
    37 int
    38 SDL_MouseInit(void)
    39 {
    40     SDL_Mouse *mouse = SDL_GetMouse();
    41 
    42     mouse->cursor_shown = SDL_TRUE;
    43 
    44     return (0);
    45 }
    46 
    47 void
    48 SDL_SetDefaultCursor(SDL_Cursor * cursor)
    49 {
    50     SDL_Mouse *mouse = SDL_GetMouse();
    51 
    52     mouse->def_cursor = cursor;
    53     if (!mouse->cur_cursor) {
    54         SDL_SetCursor(cursor);
    55     }
    56 }
    57 
    58 SDL_Mouse *
    59 SDL_GetMouse(void)
    60 {
    61     return &SDL_mouse;
    62 }
    63 
    64 SDL_Window *
    65 SDL_GetMouseFocus(void)
    66 {
    67     SDL_Mouse *mouse = SDL_GetMouse();
    68 
    69     return mouse->focus;
    70 }
    71 
    72 void
    73 SDL_SetMouseFocus(SDL_Window * window)
    74 {
    75     SDL_Mouse *mouse = SDL_GetMouse();
    76 
    77     if (mouse->focus == window) {
    78         return;
    79     }
    80 
    81     /* See if the current window has lost focus */
    82     if (mouse->focus) {
    83         SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
    84     }
    85 
    86     mouse->focus = window;
    87 
    88     if (mouse->focus) {
    89         SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
    90     }
    91 }
    92 
    93 int
    94 SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
    95 {
    96     SDL_Mouse *mouse = SDL_GetMouse();
    97     int posted;
    98     int xrel;
    99     int yrel;
   100     int x_max = 0, y_max = 0;
   101 
   102     if (window) {
   103         SDL_SetMouseFocus(window);
   104     }
   105 
   106     /* the relative motion is calculated regarding the system cursor last position */
   107     if (relative) {
   108         xrel = x;
   109         yrel = y;
   110         x = (mouse->last_x + x);
   111         y = (mouse->last_y + y);
   112     } else {
   113         xrel = x - mouse->last_x;
   114         yrel = y - mouse->last_y;
   115     }
   116 
   117     /* Drop events that don't change state */
   118     if (!xrel && !yrel) {
   119 #if 0
   120         printf("Mouse event didn't change state - dropped!\n");
   121 #endif
   122         return 0;
   123     }
   124 
   125     /* Update internal mouse coordinates */
   126     if (mouse->relative_mode == SDL_FALSE) {
   127         mouse->x = x;
   128         mouse->y = y;
   129     } else {
   130         mouse->x += xrel;
   131         mouse->y += yrel;
   132     }
   133 
   134     SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
   135     --x_max;
   136     --y_max;
   137 
   138     /* make sure that the pointers find themselves inside the windows */
   139     /* only check if mouse->xmax is set ! */
   140     if (mouse->x > x_max) {
   141         mouse->x = x_max;
   142     }
   143     if (mouse->x < 0) {
   144         mouse->x = 0;
   145     }
   146 
   147     if (mouse->y > y_max) {
   148         mouse->y = y_max;
   149     }
   150     if (mouse->y < 0) {
   151         mouse->y = 0;
   152     }
   153 
   154     mouse->xdelta += xrel;
   155     mouse->ydelta += yrel;
   156 
   157 #if 0 /* FIXME */
   158     /* Move the mouse cursor, if needed */
   159     if (mouse->cursor_shown && !mouse->relative_mode &&
   160         mouse->MoveCursor && mouse->cur_cursor) {
   161         mouse->MoveCursor(mouse->cur_cursor);
   162     }
   163 #endif
   164 
   165     /* Post the event, if desired */
   166     posted = 0;
   167     if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
   168         SDL_Event event;
   169         event.motion.type = SDL_MOUSEMOTION;
   170         event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
   171         event.motion.state = mouse->buttonstate;
   172         event.motion.x = mouse->x;
   173         event.motion.y = mouse->y;
   174         event.motion.xrel = xrel;
   175         event.motion.yrel = yrel;
   176         posted = (SDL_PushEvent(&event) > 0);
   177     }
   178     mouse->last_x = mouse->x;
   179     mouse->last_y = mouse->y;
   180     return posted;
   181 }
   182 
   183 int
   184 SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
   185 {
   186     SDL_Mouse *mouse = SDL_GetMouse();
   187     int posted;
   188     Uint32 type;
   189 
   190     if (window) {
   191         SDL_SetMouseFocus(window);
   192     }
   193 
   194     /* Figure out which event to perform */
   195     switch (state) {
   196     case SDL_PRESSED:
   197         if (mouse->buttonstate & SDL_BUTTON(button)) {
   198             /* Ignore this event, no state change */
   199             return 0;
   200         }
   201         type = SDL_MOUSEBUTTONDOWN;
   202         mouse->buttonstate |= SDL_BUTTON(button);
   203         break;
   204     case SDL_RELEASED:
   205         if (!(mouse->buttonstate & SDL_BUTTON(button))) {
   206             /* Ignore this event, no state change */
   207             return 0;
   208         }
   209         type = SDL_MOUSEBUTTONUP;
   210         mouse->buttonstate &= ~SDL_BUTTON(button);
   211         break;
   212     default:
   213         /* Invalid state -- bail */
   214         return 0;
   215     }
   216 
   217     /* Post the event, if desired */
   218     posted = 0;
   219     if (SDL_GetEventState(type) == SDL_ENABLE) {
   220         SDL_Event event;
   221         event.type = type;
   222         event.button.state = state;
   223         event.button.button = button;
   224         event.button.x = mouse->x;
   225         event.button.y = mouse->y;
   226         event.button.windowID = mouse->focus ? mouse->focus->id : 0;
   227         posted = (SDL_PushEvent(&event) > 0);
   228     }
   229     return posted;
   230 }
   231 
   232 int
   233 SDL_SendMouseWheel(SDL_Window * window, int x, int y)
   234 {
   235     SDL_Mouse *mouse = SDL_GetMouse();
   236     int posted;
   237 
   238     if (window) {
   239         SDL_SetMouseFocus(window);
   240     }
   241 
   242     if (!x && !y) {
   243         return 0;
   244     }
   245 
   246     /* Post the event, if desired */
   247     posted = 0;
   248     if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
   249         SDL_Event event;
   250         event.type = SDL_MOUSEWHEEL;
   251         event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
   252         event.wheel.x = x;
   253         event.wheel.y = y;
   254         posted = (SDL_PushEvent(&event) > 0);
   255     }
   256     return posted;
   257 }
   258 
   259 void
   260 SDL_MouseQuit(void)
   261 {
   262 }
   263 
   264 Uint8
   265 SDL_GetMouseState(int *x, int *y)
   266 {
   267     SDL_Mouse *mouse = SDL_GetMouse();
   268 
   269     if (x) {
   270         *x = mouse->x;
   271     }
   272     if (y) {
   273         *y = mouse->y;
   274     }
   275     return mouse->buttonstate;
   276 }
   277 
   278 Uint8
   279 SDL_GetRelativeMouseState(int *x, int *y)
   280 {
   281     SDL_Mouse *mouse = SDL_GetMouse();
   282 
   283     if (x) {
   284         *x = mouse->xdelta;
   285     }
   286     if (y) {
   287         *y = mouse->ydelta;
   288     }
   289     mouse->xdelta = 0;
   290     mouse->ydelta = 0;
   291     return mouse->buttonstate;
   292 }
   293 
   294 void
   295 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
   296 {
   297     SDL_Mouse *mouse = SDL_GetMouse();
   298 
   299     if (mouse->WarpMouse) {
   300         mouse->WarpMouse(window, x, y);
   301     } else {
   302         SDL_SendMouseMotion(window, 0, x, y);
   303     }
   304 }
   305 
   306 int
   307 SDL_SetRelativeMouseMode(SDL_bool enabled)
   308 {
   309     SDL_Mouse *mouse = SDL_GetMouse();
   310 
   311     if (enabled == mouse->relative_mode) {
   312         return 0;
   313     }
   314 
   315     if (!mouse->SetRelativeMouseMode) {
   316         SDL_Unsupported();
   317         return -1;
   318     }
   319 
   320     if (mouse->SetRelativeMouseMode(enabled) < 0) {
   321         return -1;
   322     }
   323 
   324     /* Set the relative mode */
   325     mouse->relative_mode = enabled;
   326 
   327     if (!enabled) {
   328         /* Restore the expected mouse position */
   329         SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   330     }
   331 
   332     /* Flush pending mouse motion */
   333     SDL_FlushEvent(SDL_MOUSEMOTION);
   334 
   335     /* Update cursor visibility */
   336     SDL_SetCursor(NULL);
   337 
   338     return 0;
   339 }
   340 
   341 SDL_bool
   342 SDL_GetRelativeMouseMode()
   343 {
   344     SDL_Mouse *mouse = SDL_GetMouse();
   345 
   346     return mouse->relative_mode;
   347 }
   348 
   349 SDL_Cursor *
   350 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   351                  int w, int h, int hot_x, int hot_y)
   352 {
   353     SDL_Mouse *mouse = SDL_GetMouse();
   354     SDL_Surface *surface;
   355     SDL_Cursor *cursor;
   356     int x, y;
   357     Uint32 *pixel;
   358     Uint8 datab = 0, maskb = 0;
   359     const Uint32 black = 0xFF000000;
   360     const Uint32 white = 0xFFFFFFFF;
   361     const Uint32 transparent = 0x00000000;
   362 
   363     /* Make sure the width is a multiple of 8 */
   364     w = ((w + 7) & ~7);
   365 
   366     /* Create the surface from a bitmap */
   367     surface = SDL_CreateRGBSurface(0, w, h, 32,
   368                                    0x00FF0000,
   369                                    0x0000FF00,
   370                                    0x000000FF,
   371                                    0xFF000000);
   372     if (!surface) {
   373         return NULL;
   374     }
   375     for (y = 0; y < h; ++y) {
   376         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   377         for (x = 0; x < w; ++x) {
   378             if ((x % 8) == 0) {
   379                 datab = *data++;
   380                 maskb = *mask++;
   381             }
   382             if (maskb & 0x80) {
   383                 *pixel++ = (datab & 0x80) ? black : white;
   384             } else {
   385                 *pixel++ = (datab & 0x80) ? black : transparent;
   386             }
   387             datab <<= 1;
   388             maskb <<= 1;
   389         }
   390     }
   391 
   392     cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
   393 
   394     SDL_FreeSurface(surface);
   395 
   396     return cursor;
   397 }
   398 
   399 SDL_Cursor *
   400 SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
   401 {
   402     SDL_Mouse *mouse = SDL_GetMouse();
   403     SDL_Surface *temp = NULL;
   404     SDL_Cursor *cursor;
   405 
   406     if (!surface) {
   407         SDL_SetError("Passed NULL cursor surface");
   408         return NULL;
   409     }
   410 
   411     if (!mouse->CreateCursor) {
   412         SDL_SetError("Cursors are not currently supported");
   413         return NULL;
   414     }
   415 
   416     /* Sanity check the hot spot */
   417     if ((hot_x < 0) || (hot_y < 0) ||
   418         (hot_x >= surface->w) || (hot_y >= surface->h)) {
   419         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   420         return NULL;
   421     }
   422 
   423     if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
   424         temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
   425         if (!temp) {
   426             return NULL;
   427         }
   428         surface = temp;
   429     }
   430 
   431     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   432     if (cursor) {
   433         cursor->next = mouse->cursors;
   434         mouse->cursors = cursor;
   435     }
   436 
   437     if (temp) {
   438         SDL_FreeSurface(temp);
   439     }
   440 
   441     return cursor;
   442 }
   443 
   444 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   445    if this is desired for any reason.  This is used when setting
   446    the video mode and when the SDL window gains the mouse focus.
   447  */
   448 void
   449 SDL_SetCursor(SDL_Cursor * cursor)
   450 {
   451     SDL_Mouse *mouse = SDL_GetMouse();
   452 
   453     /* Set the new cursor */
   454     if (cursor) {
   455         /* Make sure the cursor is still valid for this mouse */
   456         if (cursor != mouse->def_cursor) {
   457             SDL_Cursor *found;
   458             for (found = mouse->cursors; found; found = found->next) {
   459                 if (found == cursor) {
   460                     break;
   461                 }
   462             }
   463             if (!found) {
   464                 SDL_SetError("Cursor not associated with the current mouse");
   465                 return;
   466             }
   467         }
   468         mouse->cur_cursor = cursor;
   469     } else {
   470         cursor = mouse->cur_cursor;
   471     }
   472 
   473     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   474         if (mouse->ShowCursor) {
   475             mouse->ShowCursor(cursor);
   476         }
   477     } else {
   478         if (mouse->ShowCursor) {
   479             mouse->ShowCursor(NULL);
   480         }
   481     }
   482 }
   483 
   484 SDL_Cursor *
   485 SDL_GetCursor(void)
   486 {
   487     SDL_Mouse *mouse = SDL_GetMouse();
   488 
   489     if (!mouse) {
   490         return NULL;
   491     }
   492     return mouse->cur_cursor;
   493 }
   494 
   495 void
   496 SDL_FreeCursor(SDL_Cursor * cursor)
   497 {
   498     SDL_Mouse *mouse = SDL_GetMouse();
   499     SDL_Cursor *curr, *prev;
   500 
   501     if (!cursor) {
   502         return;
   503     }
   504 
   505     if (cursor == mouse->def_cursor) {
   506         return;
   507     }
   508     if (cursor == mouse->cur_cursor) {
   509         SDL_SetCursor(mouse->def_cursor);
   510     }
   511 
   512     for (prev = NULL, curr = mouse->cursors; curr;
   513          prev = curr, curr = curr->next) {
   514         if (curr == cursor) {
   515             if (prev) {
   516                 prev->next = curr->next;
   517             } else {
   518                 mouse->cursors = curr->next;
   519             }
   520 
   521             if (mouse->FreeCursor) {
   522                 mouse->FreeCursor(curr);
   523             }
   524             return;
   525         }
   526     }
   527 }
   528 
   529 int
   530 SDL_ShowCursor(int toggle)
   531 {
   532     SDL_Mouse *mouse = SDL_GetMouse();
   533     SDL_bool shown;
   534 
   535     if (!mouse) {
   536         return 0;
   537     }
   538 
   539     shown = mouse->cursor_shown;
   540     if (toggle >= 0) {
   541         if (toggle) {
   542             mouse->cursor_shown = SDL_TRUE;
   543         } else {
   544             mouse->cursor_shown = SDL_FALSE;
   545         }
   546         if (mouse->cursor_shown != shown) {
   547             SDL_SetCursor(NULL);
   548         }
   549     }
   550     return shown;
   551 }
   552 
   553 /* vi: set ts=4 sw=4 expandtab: */