src/events/SDL_mouse.c
author Sam Lantinga
Sat, 06 Oct 2012 12:16:32 -0700
changeset 6566 dd7e57847ea9
parent 6302 b0ae93a5b8d6
child 6666 018f8019ce36
permissions -rw-r--r--
Add flags to the vidmode debug output
     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) {
   327         /* Save the expected mouse position */
   328         mouse->original_x = mouse->x;
   329         mouse->original_y = mouse->y;
   330     } else if (mouse->focus) {
   331         /* Restore the expected mouse position */
   332         SDL_WarpMouseInWindow(mouse->focus, mouse->original_x, mouse->original_y);
   333     }
   334 
   335     /* Flush pending mouse motion */
   336     SDL_FlushEvent(SDL_MOUSEMOTION);
   337 
   338     /* Update cursor visibility */
   339     SDL_SetCursor(NULL);
   340 
   341     return 0;
   342 }
   343 
   344 SDL_bool
   345 SDL_GetRelativeMouseMode()
   346 {
   347     SDL_Mouse *mouse = SDL_GetMouse();
   348 
   349     return mouse->relative_mode;
   350 }
   351 
   352 SDL_Cursor *
   353 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   354                  int w, int h, int hot_x, int hot_y)
   355 {
   356     SDL_Surface *surface;
   357     SDL_Cursor *cursor;
   358     int x, y;
   359     Uint32 *pixel;
   360     Uint8 datab = 0, maskb = 0;
   361     const Uint32 black = 0xFF000000;
   362     const Uint32 white = 0xFFFFFFFF;
   363     const Uint32 transparent = 0x00000000;
   364 
   365     /* Make sure the width is a multiple of 8 */
   366     w = ((w + 7) & ~7);
   367 
   368     /* Create the surface from a bitmap */
   369     surface = SDL_CreateRGBSurface(0, w, h, 32,
   370                                    0x00FF0000,
   371                                    0x0000FF00,
   372                                    0x000000FF,
   373                                    0xFF000000);
   374     if (!surface) {
   375         return NULL;
   376     }
   377     for (y = 0; y < h; ++y) {
   378         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   379         for (x = 0; x < w; ++x) {
   380             if ((x % 8) == 0) {
   381                 datab = *data++;
   382                 maskb = *mask++;
   383             }
   384             if (maskb & 0x80) {
   385                 *pixel++ = (datab & 0x80) ? black : white;
   386             } else {
   387                 *pixel++ = (datab & 0x80) ? black : transparent;
   388             }
   389             datab <<= 1;
   390             maskb <<= 1;
   391         }
   392     }
   393 
   394     cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
   395 
   396     SDL_FreeSurface(surface);
   397 
   398     return cursor;
   399 }
   400 
   401 SDL_Cursor *
   402 SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
   403 {
   404     SDL_Mouse *mouse = SDL_GetMouse();
   405     SDL_Surface *temp = NULL;
   406     SDL_Cursor *cursor;
   407 
   408     if (!surface) {
   409         SDL_SetError("Passed NULL cursor surface");
   410         return NULL;
   411     }
   412 
   413     if (!mouse->CreateCursor) {
   414         SDL_SetError("Cursors are not currently supported");
   415         return NULL;
   416     }
   417 
   418     /* Sanity check the hot spot */
   419     if ((hot_x < 0) || (hot_y < 0) ||
   420         (hot_x >= surface->w) || (hot_y >= surface->h)) {
   421         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   422         return NULL;
   423     }
   424 
   425     if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
   426         temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
   427         if (!temp) {
   428             return NULL;
   429         }
   430         surface = temp;
   431     }
   432 
   433     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   434     if (cursor) {
   435         cursor->next = mouse->cursors;
   436         mouse->cursors = cursor;
   437     }
   438 
   439     if (temp) {
   440         SDL_FreeSurface(temp);
   441     }
   442 
   443     return cursor;
   444 }
   445 
   446 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   447    if this is desired for any reason.  This is used when setting
   448    the video mode and when the SDL window gains the mouse focus.
   449  */
   450 void
   451 SDL_SetCursor(SDL_Cursor * cursor)
   452 {
   453     SDL_Mouse *mouse = SDL_GetMouse();
   454 
   455     /* Set the new cursor */
   456     if (cursor) {
   457         /* Make sure the cursor is still valid for this mouse */
   458         if (cursor != mouse->def_cursor) {
   459             SDL_Cursor *found;
   460             for (found = mouse->cursors; found; found = found->next) {
   461                 if (found == cursor) {
   462                     break;
   463                 }
   464             }
   465             if (!found) {
   466                 SDL_SetError("Cursor not associated with the current mouse");
   467                 return;
   468             }
   469         }
   470         mouse->cur_cursor = cursor;
   471     } else {
   472         if (mouse->focus) {
   473             cursor = mouse->cur_cursor;
   474         } else {
   475             cursor = mouse->def_cursor;
   476         }
   477     }
   478 
   479     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   480         if (mouse->ShowCursor) {
   481             mouse->ShowCursor(cursor);
   482         }
   483     } else {
   484         if (mouse->ShowCursor) {
   485             mouse->ShowCursor(NULL);
   486         }
   487     }
   488 }
   489 
   490 SDL_Cursor *
   491 SDL_GetCursor(void)
   492 {
   493     SDL_Mouse *mouse = SDL_GetMouse();
   494 
   495     if (!mouse) {
   496         return NULL;
   497     }
   498     return mouse->cur_cursor;
   499 }
   500 
   501 void
   502 SDL_FreeCursor(SDL_Cursor * cursor)
   503 {
   504     SDL_Mouse *mouse = SDL_GetMouse();
   505     SDL_Cursor *curr, *prev;
   506 
   507     if (!cursor) {
   508         return;
   509     }
   510 
   511     if (cursor == mouse->def_cursor) {
   512         return;
   513     }
   514     if (cursor == mouse->cur_cursor) {
   515         SDL_SetCursor(mouse->def_cursor);
   516     }
   517 
   518     for (prev = NULL, curr = mouse->cursors; curr;
   519          prev = curr, curr = curr->next) {
   520         if (curr == cursor) {
   521             if (prev) {
   522                 prev->next = curr->next;
   523             } else {
   524                 mouse->cursors = curr->next;
   525             }
   526 
   527             if (mouse->FreeCursor) {
   528                 mouse->FreeCursor(curr);
   529             }
   530             return;
   531         }
   532     }
   533 }
   534 
   535 int
   536 SDL_ShowCursor(int toggle)
   537 {
   538     SDL_Mouse *mouse = SDL_GetMouse();
   539     SDL_bool shown;
   540 
   541     if (!mouse) {
   542         return 0;
   543     }
   544 
   545     shown = mouse->cursor_shown;
   546     if (toggle >= 0) {
   547         if (toggle) {
   548             mouse->cursor_shown = SDL_TRUE;
   549         } else {
   550             mouse->cursor_shown = SDL_FALSE;
   551         }
   552         if (mouse->cursor_shown != shown) {
   553             SDL_SetCursor(NULL);
   554         }
   555     }
   556     return shown;
   557 }
   558 
   559 /* vi: set ts=4 sw=4 expandtab: */