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