src/events/SDL_mouse.c
author Ryan C. Gordon
Sun, 31 Mar 2013 12:48:50 -0400
changeset 7037 3fedf1f25b94
parent 6950 1ddb72193079
child 7089 257fc4e541e1
permissions -rw-r--r--
Make SDL_SetError and friends unconditionally return -1.

This lets us change things like this...

if (Failed) {
SDL_SetError("We failed");
return -1;
}

...into this...

if (Failed) {
return SDL_SetError("We failed");
}


Fixes Bugzilla #1778.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_assert.h"
    26 #include "SDL_events.h"
    27 #include "SDL_events_c.h"
    28 #include "default_cursor.h"
    29 #include "../video/SDL_sysvideo.h"
    30 
    31 /*#define DEBUG_MOUSE*/
    32 
    33 /* The mouse state */
    34 static SDL_Mouse SDL_mouse;
    35 
    36 
    37 /* Public functions */
    38 int
    39 SDL_MouseInit(void)
    40 {
    41     SDL_Mouse *mouse = SDL_GetMouse();
    42 
    43     mouse->cursor_shown = SDL_TRUE;
    44 
    45     return (0);
    46 }
    47 
    48 void
    49 SDL_SetDefaultCursor(SDL_Cursor * cursor)
    50 {
    51     SDL_Mouse *mouse = SDL_GetMouse();
    52 
    53     mouse->def_cursor = cursor;
    54     if (!mouse->cur_cursor) {
    55         SDL_SetCursor(cursor);
    56     }
    57 }
    58 
    59 SDL_Mouse *
    60 SDL_GetMouse(void)
    61 {
    62     return &SDL_mouse;
    63 }
    64 
    65 SDL_Window *
    66 SDL_GetMouseFocus(void)
    67 {
    68     SDL_Mouse *mouse = SDL_GetMouse();
    69 
    70     return mouse->focus;
    71 }
    72 
    73 void
    74 SDL_ResetMouse(void)
    75 {
    76     SDL_Mouse *mouse = SDL_GetMouse();
    77     Uint8 i;
    78 
    79 #ifdef DEBUG_MOUSE
    80     printf("Resetting mouse\n");
    81 #endif
    82     for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
    83         if (mouse->buttonstate & SDL_BUTTON(i)) {
    84             SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
    85         }
    86     }
    87     SDL_assert(mouse->buttonstate == 0);
    88 }
    89 
    90 void
    91 SDL_SetMouseFocus(SDL_Window * window)
    92 {
    93     SDL_Mouse *mouse = SDL_GetMouse();
    94 
    95     if (mouse->focus == window) {
    96         return;
    97     }
    98 
    99     /* Actually, this ends up being a bad idea, because most operating
   100        systems have an implicit grab when you press the mouse button down
   101        so you can drag things out of the window and then get the mouse up
   102        when it happens.  So, #if 0...
   103     */
   104 #if 0
   105     if (mouse->focus && !window) {
   106         /* We won't get anymore mouse messages, so reset mouse state */
   107         SDL_ResetMouse();
   108     }
   109 #endif
   110 
   111     /* See if the current window has lost focus */
   112     if (mouse->focus) {
   113         SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   114     }
   115 
   116     mouse->focus = window;
   117 
   118     if (mouse->focus) {
   119         SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   120     }
   121 
   122     /* Update cursor visibility */
   123     SDL_SetCursor(NULL);
   124 }
   125 
   126 /* Check to see if we need to synthesize focus events */
   127 static SDL_bool
   128 SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
   129 {
   130     SDL_Mouse *mouse = SDL_GetMouse();
   131     int w, h;
   132     SDL_bool inWindow;
   133 
   134     SDL_GetWindowSize(window, &w, &h);
   135     if (x < 0 || y < 0 || x >= w || y >= h) {
   136         inWindow = SDL_FALSE;
   137     } else {
   138         inWindow = SDL_TRUE;
   139     }
   140 
   141 /* Linux doesn't give you mouse events outside your window unless you grab
   142    the pointer.
   143 
   144    Windows doesn't give you mouse events outside your window unless you call
   145    SetCapture().
   146 
   147    Both of these are slightly scary changes, so for now we'll punt and if the
   148    mouse leaves the window you'll lose mouse focus and reset button state.
   149 */
   150 #ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
   151     if (!inWindow && !buttonstate) {
   152 #else
   153     if (!inWindow) {
   154 #endif
   155         if (window == mouse->focus) {
   156 #ifdef DEBUG_MOUSE
   157             printf("Mouse left window, synthesizing focus lost event\n");
   158 #endif
   159             SDL_SetMouseFocus(NULL);
   160         }
   161         return SDL_FALSE;
   162     }
   163 
   164     if (window != mouse->focus) {
   165         mouse->last_x = x;
   166         mouse->last_y = y;
   167 
   168 #ifdef DEBUG_MOUSE
   169         printf("Mouse entered window, synthesizing focus gain event\n");
   170 #endif
   171         SDL_SetMouseFocus(window);
   172     }
   173     return SDL_TRUE;
   174 }
   175 
   176 int
   177 SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
   178 {
   179     SDL_Mouse *mouse = SDL_GetMouse();
   180     int posted;
   181     int xrel;
   182     int yrel;
   183     int x_max = 0, y_max = 0;
   184 
   185     if (window && !relative) {
   186         if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
   187             return 0;
   188         }
   189     }
   190 
   191     /* relative motion is calculated regarding the system cursor last position */
   192     if (relative) {
   193         xrel = x;
   194         yrel = y;
   195         x = (mouse->last_x + x);
   196         y = (mouse->last_y + y);
   197     } else {
   198         xrel = x - mouse->last_x;
   199         yrel = y - mouse->last_y;
   200     }
   201 
   202     /* Drop events that don't change state */
   203     if (!xrel && !yrel) {
   204 #ifdef DEBUG_MOUSE
   205         printf("Mouse event didn't change state - dropped!\n");
   206 #endif
   207         return 0;
   208     }
   209 
   210     /* Update internal mouse coordinates */
   211     if (mouse->relative_mode == SDL_FALSE) {
   212         mouse->x = x;
   213         mouse->y = y;
   214     } else {
   215         mouse->x += xrel;
   216         mouse->y += yrel;
   217     }
   218 
   219     SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
   220     --x_max;
   221     --y_max;
   222 
   223     /* make sure that the pointers find themselves inside the windows */
   224     if (mouse->x > x_max) {
   225         mouse->x = x_max;
   226     }
   227     if (mouse->x < 0) {
   228         mouse->x = 0;
   229     }
   230 
   231     if (mouse->y > y_max) {
   232         mouse->y = y_max;
   233     }
   234     if (mouse->y < 0) {
   235         mouse->y = 0;
   236     }
   237 
   238     mouse->xdelta += xrel;
   239     mouse->ydelta += yrel;
   240 
   241 #if 0 /* FIXME */
   242     /* Move the mouse cursor, if needed */
   243     if (mouse->cursor_shown && !mouse->relative_mode &&
   244         mouse->MoveCursor && mouse->cur_cursor) {
   245         mouse->MoveCursor(mouse->cur_cursor);
   246     }
   247 #endif
   248 
   249     /* Post the event, if desired */
   250     posted = 0;
   251     if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
   252         SDL_Event event;
   253         event.motion.type = SDL_MOUSEMOTION;
   254         event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
   255         event.motion.which = mouseID;
   256         event.motion.state = mouse->buttonstate;
   257         event.motion.x = mouse->x;
   258         event.motion.y = mouse->y;
   259         event.motion.xrel = xrel;
   260         event.motion.yrel = yrel;
   261         posted = (SDL_PushEvent(&event) > 0);
   262     }
   263     /* Use unclamped values if we're getting events outside the window */
   264     mouse->last_x = x;
   265     mouse->last_y = y;
   266     return posted;
   267 }
   268 
   269 int
   270 SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
   271 {
   272     SDL_Mouse *mouse = SDL_GetMouse();
   273     int posted;
   274     Uint32 type;
   275     Uint32 buttonstate = mouse->buttonstate;
   276 
   277     /* Figure out which event to perform */
   278     switch (state) {
   279     case SDL_PRESSED:
   280         type = SDL_MOUSEBUTTONDOWN;
   281         buttonstate |= SDL_BUTTON(button);
   282         break;
   283     case SDL_RELEASED:
   284         type = SDL_MOUSEBUTTONUP;
   285         buttonstate &= ~SDL_BUTTON(button);
   286         break;
   287     default:
   288         /* Invalid state -- bail */
   289         return 0;
   290     }
   291 
   292     /* We do this after calculating buttonstate so button presses gain focus */
   293     if (window && state == SDL_PRESSED) {
   294         SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   295     }
   296 
   297     if (buttonstate == mouse->buttonstate) {
   298         /* Ignore this event, no state change */
   299         return 0;
   300     }
   301     mouse->buttonstate = buttonstate;
   302 
   303     /* Post the event, if desired */
   304     posted = 0;
   305     if (SDL_GetEventState(type) == SDL_ENABLE) {
   306         SDL_Event event;
   307         event.type = type;
   308         event.button.windowID = mouse->focus ? mouse->focus->id : 0;
   309         event.button.which = mouseID;
   310         event.button.state = state;
   311         event.button.button = button;
   312         event.button.x = mouse->x;
   313         event.button.y = mouse->y;
   314         posted = (SDL_PushEvent(&event) > 0);
   315     }
   316 
   317     /* We do this after dispatching event so button releases can lose focus */
   318     if (window && state == SDL_RELEASED) {
   319         SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
   320     }
   321 
   322     return posted;
   323 }
   324 
   325 int
   326 SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y)
   327 {
   328     SDL_Mouse *mouse = SDL_GetMouse();
   329     int posted;
   330 
   331     if (window) {
   332         SDL_SetMouseFocus(window);
   333     }
   334 
   335     if (!x && !y) {
   336         return 0;
   337     }
   338 
   339     /* Post the event, if desired */
   340     posted = 0;
   341     if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
   342         SDL_Event event;
   343         event.type = SDL_MOUSEWHEEL;
   344         event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
   345         event.wheel.which = mouseID;
   346         event.wheel.x = x;
   347         event.wheel.y = y;
   348         posted = (SDL_PushEvent(&event) > 0);
   349     }
   350     return posted;
   351 }
   352 
   353 void
   354 SDL_MouseQuit(void)
   355 {
   356 }
   357 
   358 Uint32
   359 SDL_GetMouseState(int *x, int *y)
   360 {
   361     SDL_Mouse *mouse = SDL_GetMouse();
   362 
   363     if (x) {
   364         *x = mouse->x;
   365     }
   366     if (y) {
   367         *y = mouse->y;
   368     }
   369     return mouse->buttonstate;
   370 }
   371 
   372 Uint32
   373 SDL_GetRelativeMouseState(int *x, int *y)
   374 {
   375     SDL_Mouse *mouse = SDL_GetMouse();
   376 
   377     if (x) {
   378         *x = mouse->xdelta;
   379     }
   380     if (y) {
   381         *y = mouse->ydelta;
   382     }
   383     mouse->xdelta = 0;
   384     mouse->ydelta = 0;
   385     return mouse->buttonstate;
   386 }
   387 
   388 void
   389 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
   390 {
   391     SDL_Mouse *mouse = SDL_GetMouse();
   392 	
   393 	if ( window == NULL )
   394 		window = mouse->focus;
   395 	
   396 	if ( window == NULL )
   397 		return;
   398 
   399     if (mouse->WarpMouse) {
   400         mouse->WarpMouse(window, x, y);
   401     } else {
   402         SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
   403     }
   404 }
   405 
   406 int
   407 SDL_SetRelativeMouseMode(SDL_bool enabled)
   408 {
   409     SDL_Mouse *mouse = SDL_GetMouse();
   410 
   411     if (enabled == mouse->relative_mode) {
   412         return 0;
   413     }
   414 
   415     if (!mouse->SetRelativeMouseMode) {
   416         return SDL_Unsupported();
   417     }
   418 
   419     if (mouse->SetRelativeMouseMode(enabled) < 0) {
   420         return -1;
   421     }
   422 
   423     /* Set the relative mode */
   424     mouse->relative_mode = enabled;
   425 
   426     if (enabled) {
   427         /* Save the expected mouse position */
   428         mouse->original_x = mouse->x;
   429         mouse->original_y = mouse->y;
   430     } else if (mouse->focus) {
   431         /* Restore the expected mouse position */
   432         SDL_WarpMouseInWindow(mouse->focus, mouse->original_x, mouse->original_y);
   433     }
   434 
   435     /* Flush pending mouse motion */
   436     SDL_FlushEvent(SDL_MOUSEMOTION);
   437 
   438     /* Update cursor visibility */
   439     SDL_SetCursor(NULL);
   440 
   441     return 0;
   442 }
   443 
   444 SDL_bool
   445 SDL_GetRelativeMouseMode()
   446 {
   447     SDL_Mouse *mouse = SDL_GetMouse();
   448 
   449     return mouse->relative_mode;
   450 }
   451 
   452 SDL_Cursor *
   453 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   454                  int w, int h, int hot_x, int hot_y)
   455 {
   456     SDL_Surface *surface;
   457     SDL_Cursor *cursor;
   458     int x, y;
   459     Uint32 *pixel;
   460     Uint8 datab = 0, maskb = 0;
   461     const Uint32 black = 0xFF000000;
   462     const Uint32 white = 0xFFFFFFFF;
   463     const Uint32 transparent = 0x00000000;
   464 
   465     /* Make sure the width is a multiple of 8 */
   466     w = ((w + 7) & ~7);
   467 
   468     /* Create the surface from a bitmap */
   469     surface = SDL_CreateRGBSurface(0, w, h, 32,
   470                                    0x00FF0000,
   471                                    0x0000FF00,
   472                                    0x000000FF,
   473                                    0xFF000000);
   474     if (!surface) {
   475         return NULL;
   476     }
   477     for (y = 0; y < h; ++y) {
   478         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   479         for (x = 0; x < w; ++x) {
   480             if ((x % 8) == 0) {
   481                 datab = *data++;
   482                 maskb = *mask++;
   483             }
   484             if (maskb & 0x80) {
   485                 *pixel++ = (datab & 0x80) ? black : white;
   486             } else {
   487                 *pixel++ = (datab & 0x80) ? black : transparent;
   488             }
   489             datab <<= 1;
   490             maskb <<= 1;
   491         }
   492     }
   493 
   494     cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
   495 
   496     SDL_FreeSurface(surface);
   497 
   498     return cursor;
   499 }
   500 
   501 SDL_Cursor *
   502 SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
   503 {
   504     SDL_Mouse *mouse = SDL_GetMouse();
   505     SDL_Surface *temp = NULL;
   506     SDL_Cursor *cursor;
   507 
   508     if (!surface) {
   509         SDL_SetError("Passed NULL cursor surface");
   510         return NULL;
   511     }
   512 
   513     if (!mouse->CreateCursor) {
   514         SDL_SetError("Cursors are not currently supported");
   515         return NULL;
   516     }
   517 
   518     /* Sanity check the hot spot */
   519     if ((hot_x < 0) || (hot_y < 0) ||
   520         (hot_x >= surface->w) || (hot_y >= surface->h)) {
   521         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   522         return NULL;
   523     }
   524 
   525     if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
   526         temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
   527         if (!temp) {
   528             return NULL;
   529         }
   530         surface = temp;
   531     }
   532 
   533     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   534     if (cursor) {
   535         cursor->next = mouse->cursors;
   536         mouse->cursors = cursor;
   537     }
   538 
   539     if (temp) {
   540         SDL_FreeSurface(temp);
   541     }
   542 
   543     return cursor;
   544 }
   545 
   546 SDL_Cursor *
   547 SDL_CreateSystemCursor(SDL_SystemCursor id)
   548 {
   549     SDL_Mouse *mouse = SDL_GetMouse();
   550     SDL_Cursor *cursor;
   551 
   552     if (!mouse->CreateSystemCursor) {
   553         SDL_SetError("CreateSystemCursor is not currently supported");
   554         return NULL;
   555     }
   556 
   557 	cursor = mouse->CreateSystemCursor(id);
   558     if (cursor) {
   559         cursor->next = mouse->cursors;
   560         mouse->cursors = cursor;
   561     }
   562 
   563 	return cursor;
   564 }
   565 
   566 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   567    if this is desired for any reason.  This is used when setting
   568    the video mode and when the SDL window gains the mouse focus.
   569  */
   570 void
   571 SDL_SetCursor(SDL_Cursor * cursor)
   572 {
   573     SDL_Mouse *mouse = SDL_GetMouse();
   574 
   575     /* Set the new cursor */
   576     if (cursor) {
   577         /* Make sure the cursor is still valid for this mouse */
   578         if (cursor != mouse->def_cursor) {
   579             SDL_Cursor *found;
   580             for (found = mouse->cursors; found; found = found->next) {
   581                 if (found == cursor) {
   582                     break;
   583                 }
   584             }
   585             if (!found) {
   586                 SDL_SetError("Cursor not associated with the current mouse");
   587                 return;
   588             }
   589         }
   590         mouse->cur_cursor = cursor;
   591     } else {
   592         if (mouse->focus) {
   593             cursor = mouse->cur_cursor;
   594         } else {
   595             cursor = mouse->def_cursor;
   596         }
   597     }
   598 
   599     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   600         if (mouse->ShowCursor) {
   601             mouse->ShowCursor(cursor);
   602         }
   603     } else {
   604         if (mouse->ShowCursor) {
   605             mouse->ShowCursor(NULL);
   606         }
   607     }
   608 }
   609 
   610 SDL_Cursor *
   611 SDL_GetCursor(void)
   612 {
   613     SDL_Mouse *mouse = SDL_GetMouse();
   614 
   615     if (!mouse) {
   616         return NULL;
   617     }
   618     return mouse->cur_cursor;
   619 }
   620 
   621 void
   622 SDL_FreeCursor(SDL_Cursor * cursor)
   623 {
   624     SDL_Mouse *mouse = SDL_GetMouse();
   625     SDL_Cursor *curr, *prev;
   626 
   627     if (!cursor) {
   628         return;
   629     }
   630 
   631     if (cursor == mouse->def_cursor) {
   632         return;
   633     }
   634     if (cursor == mouse->cur_cursor) {
   635         SDL_SetCursor(mouse->def_cursor);
   636     }
   637 
   638     for (prev = NULL, curr = mouse->cursors; curr;
   639          prev = curr, curr = curr->next) {
   640         if (curr == cursor) {
   641             if (prev) {
   642                 prev->next = curr->next;
   643             } else {
   644                 mouse->cursors = curr->next;
   645             }
   646 
   647             if (mouse->FreeCursor) {
   648                 mouse->FreeCursor(curr);
   649             }
   650             return;
   651         }
   652     }
   653 }
   654 
   655 int
   656 SDL_ShowCursor(int toggle)
   657 {
   658     SDL_Mouse *mouse = SDL_GetMouse();
   659     SDL_bool shown;
   660 
   661     if (!mouse) {
   662         return 0;
   663     }
   664 
   665     shown = mouse->cursor_shown;
   666     if (toggle >= 0) {
   667         if (toggle) {
   668             mouse->cursor_shown = SDL_TRUE;
   669         } else {
   670             mouse->cursor_shown = SDL_FALSE;
   671         }
   672         if (mouse->cursor_shown != shown) {
   673             SDL_SetCursor(NULL);
   674         }
   675     }
   676     return shown;
   677 }
   678 
   679 /* vi: set ts=4 sw=4 expandtab: */