src/events/SDL_mouse.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 /* 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) {
   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         cursor = mouse->cur_cursor;
   469     }
   470 
   471     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   472         if (mouse->ShowCursor) {
   473             mouse->ShowCursor(cursor);
   474         }
   475     } else {
   476         if (mouse->ShowCursor) {
   477             mouse->ShowCursor(NULL);
   478         }
   479     }
   480 }
   481 
   482 SDL_Cursor *
   483 SDL_GetCursor(void)
   484 {
   485     SDL_Mouse *mouse = SDL_GetMouse();
   486 
   487     if (!mouse) {
   488         return NULL;
   489     }
   490     return mouse->cur_cursor;
   491 }
   492 
   493 void
   494 SDL_FreeCursor(SDL_Cursor * cursor)
   495 {
   496     SDL_Mouse *mouse = SDL_GetMouse();
   497     SDL_Cursor *curr, *prev;
   498 
   499     if (!cursor) {
   500         return;
   501     }
   502 
   503     if (cursor == mouse->def_cursor) {
   504         return;
   505     }
   506     if (cursor == mouse->cur_cursor) {
   507         SDL_SetCursor(mouse->def_cursor);
   508     }
   509 
   510     for (prev = NULL, curr = mouse->cursors; curr;
   511          prev = curr, curr = curr->next) {
   512         if (curr == cursor) {
   513             if (prev) {
   514                 prev->next = curr->next;
   515             } else {
   516                 mouse->cursors = curr->next;
   517             }
   518 
   519             if (mouse->FreeCursor) {
   520                 mouse->FreeCursor(curr);
   521             }
   522             return;
   523         }
   524     }
   525 }
   526 
   527 int
   528 SDL_ShowCursor(int toggle)
   529 {
   530     SDL_Mouse *mouse = SDL_GetMouse();
   531     SDL_bool shown;
   532 
   533     if (!mouse) {
   534         return 0;
   535     }
   536 
   537     shown = mouse->cursor_shown;
   538     if (toggle >= 0) {
   539         if (toggle) {
   540             mouse->cursor_shown = SDL_TRUE;
   541         } else {
   542             mouse->cursor_shown = SDL_FALSE;
   543         }
   544         if (mouse->cursor_shown != shown) {
   545             SDL_SetCursor(NULL);
   546         }
   547     }
   548     return shown;
   549 }
   550 
   551 /* vi: set ts=4 sw=4 expandtab: */