src/events/SDL_mouse.c
author Ryan C. Gordon
Tue, 17 Oct 2006 09:15:21 +0000
changeset 2049 5f6550e5184f
parent 1895 c121d94672cb
child 2152 003c1b5b07da
permissions -rw-r--r--
Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 
    30 
    31 static int SDL_num_mice;
    32 static int SDL_current_mouse;
    33 static SDL_Mouse **SDL_mice;
    34 
    35 
    36 /* Public functions */
    37 int
    38 SDL_MouseInit(void)
    39 {
    40     return (0);
    41 }
    42 
    43 SDL_Mouse *
    44 SDL_GetMouse(int index)
    45 {
    46     if (index < 0 || index >= SDL_num_mice) {
    47         return NULL;
    48     }
    49     return SDL_mice[index];
    50 }
    51 
    52 int
    53 SDL_AddMouse(const SDL_Mouse * mouse, int index)
    54 {
    55     SDL_Mouse **mice;
    56     int selected_mouse;
    57 
    58     /* Add the mouse to the list of mice */
    59     if (index < 0 || index >= SDL_num_mice || SDL_mice[index]) {
    60         mice =
    61             (SDL_Mouse **) SDL_realloc(SDL_mice,
    62                                        (SDL_num_mice + 1) * sizeof(*mice));
    63         if (!mice) {
    64             SDL_OutOfMemory();
    65             return -1;
    66         }
    67 
    68         SDL_mice = mice;
    69         index = SDL_num_mice++;
    70     }
    71     SDL_mice[index] = (SDL_Mouse *) SDL_malloc(sizeof(*SDL_mice[index]));
    72     if (!SDL_mice[index]) {
    73         SDL_OutOfMemory();
    74         return -1;
    75     }
    76     *SDL_mice[index] = *mouse;
    77 
    78     /* Create the default cursor for the mouse */
    79     SDL_mice[index]->cursor_shown = SDL_TRUE;
    80     selected_mouse = SDL_SelectMouse(index);
    81     SDL_mice[index]->cur_cursor = NULL;
    82     SDL_mice[index]->def_cursor =
    83         SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH,
    84                          DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
    85     SDL_SetCursor(SDL_mice[index]->def_cursor);
    86     SDL_SelectMouse(selected_mouse);
    87 
    88     return index;
    89 }
    90 
    91 void
    92 SDL_DelMouse(int index)
    93 {
    94     SDL_Mouse *mouse = SDL_GetMouse(index);
    95 
    96     if (!mouse) {
    97         return;
    98     }
    99 
   100     mouse->def_cursor = NULL;
   101     while (mouse->cursors) {
   102         SDL_FreeCursor(mouse->cursors);
   103     }
   104 
   105     if (mouse->FreeMouse) {
   106         mouse->FreeMouse(mouse);
   107     }
   108     SDL_free(mouse);
   109 
   110     SDL_mice[index] = NULL;
   111 }
   112 
   113 void
   114 SDL_ResetMouse(int index)
   115 {
   116     SDL_Mouse *mouse = SDL_GetMouse(index);
   117 
   118     if (!mouse) {
   119         return;
   120     }
   121 
   122     /* FIXME */
   123 }
   124 
   125 void
   126 SDL_MouseQuit(void)
   127 {
   128     int i;
   129 
   130     for (i = 0; i < SDL_num_mice; ++i) {
   131         SDL_DelMouse(i);
   132     }
   133     SDL_num_mice = 0;
   134     SDL_current_mouse = 0;
   135 
   136     if (SDL_mice) {
   137         SDL_free(SDL_mice);
   138         SDL_mice = NULL;
   139     }
   140 }
   141 
   142 int
   143 SDL_GetNumMice(void)
   144 {
   145     return SDL_num_mice;
   146 }
   147 
   148 int
   149 SDL_SelectMouse(int index)
   150 {
   151     if (index >= 0 && index < SDL_num_mice) {
   152         SDL_current_mouse = index;
   153     }
   154     return SDL_current_mouse;
   155 }
   156 
   157 SDL_WindowID
   158 SDL_GetMouseFocusWindow()
   159 {
   160     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   161 
   162     if (!mouse) {
   163         return 0;
   164     }
   165     return mouse->focus;
   166 }
   167 
   168 static int SDLCALL
   169 FlushMouseMotion(void *param, SDL_Event * event)
   170 {
   171     if (event->type == SDL_MOUSEMOTION
   172         && event->motion.which == (Uint8) SDL_current_mouse) {
   173         return 0;
   174     } else {
   175         return 1;
   176     }
   177 }
   178 
   179 int
   180 SDL_SetRelativeMouseMode(SDL_bool enabled)
   181 {
   182     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   183 
   184     if (!mouse) {
   185         return -1;
   186     }
   187 
   188     /* Flush pending mouse motion */
   189     mouse->flush_motion = SDL_TRUE;
   190     SDL_PumpEvents();
   191     mouse->flush_motion = SDL_FALSE;
   192     SDL_FilterEvents(FlushMouseMotion, mouse);
   193 
   194     /* Set the relative mode */
   195     mouse->relative_mode = enabled;
   196 
   197     /* Update cursor visibility */
   198     SDL_SetCursor(NULL);
   199 
   200     if (!enabled) {
   201         /* Restore the expected mouse position */
   202         SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   203     }
   204     return 0;
   205 }
   206 
   207 SDL_bool
   208 SDL_GetRelativeMouseMode()
   209 {
   210     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   211 
   212     if (!mouse) {
   213         return SDL_FALSE;
   214     }
   215     return mouse->relative_mode;
   216 }
   217 
   218 Uint8
   219 SDL_GetMouseState(int *x, int *y)
   220 {
   221     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   222 
   223     if (!mouse) {
   224         if (x) {
   225             *x = 0;
   226         }
   227         if (y) {
   228             *y = 0;
   229         }
   230         return 0;
   231     }
   232 
   233     if (x) {
   234         *x = mouse->x;
   235     }
   236     if (y) {
   237         *y = mouse->y;
   238     }
   239     return mouse->buttonstate;
   240 }
   241 
   242 Uint8
   243 SDL_GetRelativeMouseState(int *x, int *y)
   244 {
   245     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   246 
   247     if (!mouse) {
   248         if (x) {
   249             *x = 0;
   250         }
   251         if (y) {
   252             *y = 0;
   253         }
   254         return 0;
   255     }
   256 
   257     if (x) {
   258         *x = mouse->xdelta;
   259     }
   260     if (y) {
   261         *y = mouse->ydelta;
   262     }
   263     mouse->xdelta = 0;
   264     mouse->ydelta = 0;
   265     return mouse->buttonstate;
   266 }
   267 
   268 void
   269 SDL_SetMouseFocus(int index, SDL_WindowID windowID)
   270 {
   271     SDL_Mouse *mouse = SDL_GetMouse(index);
   272     int i;
   273     SDL_bool focus;
   274 
   275     if (!mouse || (mouse->focus == windowID)) {
   276         return;
   277     }
   278 
   279     /* See if the current window has lost focus */
   280     if (mouse->focus) {
   281         focus = SDL_FALSE;
   282         for (i = 0; i < SDL_num_mice; ++i) {
   283             SDL_Mouse *check;
   284             if (i != index) {
   285                 check = SDL_GetMouse(i);
   286                 if (check && check->focus == mouse->focus) {
   287                     focus = SDL_TRUE;
   288                     break;
   289                 }
   290             }
   291         }
   292         if (!focus) {
   293             SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   294         }
   295     }
   296 
   297     mouse->focus = windowID;
   298 
   299     if (mouse->focus) {
   300         focus = SDL_FALSE;
   301         for (i = 0; i < SDL_num_mice; ++i) {
   302             SDL_Mouse *check;
   303             if (i != index) {
   304                 check = SDL_GetMouse(i);
   305                 if (check && check->focus == mouse->focus) {
   306                     focus = SDL_TRUE;
   307                     break;
   308                 }
   309             }
   310         }
   311         if (!focus) {
   312             SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   313         }
   314     }
   315 }
   316 
   317 int
   318 SDL_SendMouseMotion(int index, int relative, int x, int y)
   319 {
   320     SDL_Mouse *mouse = SDL_GetMouse(index);
   321     int posted;
   322     int xrel;
   323     int yrel;
   324 
   325     if (!mouse || mouse->flush_motion) {
   326         return 0;
   327     }
   328 
   329     if (relative) {
   330         /* Push the cursor around */
   331         xrel = x;
   332         yrel = y;
   333         x = (mouse->x + xrel);
   334         y = (mouse->y + yrel);
   335     } else {
   336         xrel = x - mouse->x;
   337         yrel = y - mouse->y;
   338     }
   339 
   340     /* Drop events that don't change state */
   341     if (!xrel && !yrel) {
   342 #if 0
   343         printf("Mouse event didn't change state - dropped!\n");
   344 #endif
   345         return 0;
   346     }
   347 
   348     /* Update internal mouse state */
   349     if (!mouse->relative_mode) {
   350         mouse->x = x;
   351         mouse->y = y;
   352     }
   353     mouse->xdelta += xrel;
   354     mouse->ydelta += yrel;
   355 
   356     /* Move the mouse cursor, if needed */
   357     if (mouse->cursor_shown && !mouse->relative_mode &&
   358         mouse->MoveCursor && mouse->cur_cursor) {
   359         mouse->MoveCursor(mouse->cur_cursor);
   360     }
   361 
   362     /* Post the event, if desired */
   363     posted = 0;
   364     if (SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE) {
   365         SDL_Event event;
   366         event.motion.type = SDL_MOUSEMOTION;
   367         event.motion.which = (Uint8) index;
   368         event.motion.state = mouse->buttonstate;
   369         event.motion.x = mouse->x;
   370         event.motion.y = mouse->y;
   371         event.motion.xrel = xrel;
   372         event.motion.yrel = yrel;
   373         event.motion.windowID = mouse->focus;
   374         posted = (SDL_PushEvent(&event) > 0);
   375     }
   376     return posted;
   377 }
   378 
   379 int
   380 SDL_SendMouseButton(int index, Uint8 state, Uint8 button)
   381 {
   382     SDL_Mouse *mouse = SDL_GetMouse(index);
   383     int posted;
   384     Uint8 type;
   385 
   386     if (!mouse) {
   387         return 0;
   388     }
   389 
   390     /* Figure out which event to perform */
   391     switch (state) {
   392     case SDL_PRESSED:
   393         if (mouse->buttonstate & SDL_BUTTON(button)) {
   394             /* Ignore this event, no state change */
   395             return 0;
   396         }
   397         type = SDL_MOUSEBUTTONDOWN;
   398         mouse->buttonstate |= SDL_BUTTON(button);
   399         break;
   400     case SDL_RELEASED:
   401         if (!(mouse->buttonstate & SDL_BUTTON(button))) {
   402             /* Ignore this event, no state change */
   403             return 0;
   404         }
   405         type = SDL_MOUSEBUTTONUP;
   406         mouse->buttonstate &= ~SDL_BUTTON(button);
   407         break;
   408     default:
   409         /* Invalid state -- bail */
   410         return 0;
   411     }
   412 
   413     /* Post the event, if desired */
   414     posted = 0;
   415     if (SDL_ProcessEvents[type] == SDL_ENABLE) {
   416         SDL_Event event;
   417         event.type = type;
   418         event.button.which = (Uint8) index;
   419         event.button.state = state;
   420         event.button.button = button;
   421         event.button.x = mouse->x;
   422         event.button.y = mouse->y;
   423         event.button.windowID = mouse->focus;
   424         posted = (SDL_PushEvent(&event) > 0);
   425     }
   426     return posted;
   427 }
   428 
   429 int
   430 SDL_SendMouseWheel(int index, int motion)
   431 {
   432     SDL_Mouse *mouse = SDL_GetMouse(index);
   433     int posted;
   434 
   435     if (!mouse || !motion) {
   436         return 0;
   437     }
   438 
   439     /* Post the event, if desired */
   440     posted = 0;
   441     if (SDL_ProcessEvents[SDL_MOUSEWHEEL] == SDL_ENABLE) {
   442         SDL_Event event;
   443         event.type = SDL_MOUSEWHEEL;
   444         event.wheel.which = (Uint8) index;
   445         event.wheel.motion = motion;
   446         event.wheel.windowID = mouse->focus;
   447         posted = (SDL_PushEvent(&event) > 0);
   448     }
   449     return posted;
   450 }
   451 
   452 void
   453 SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y)
   454 {
   455     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   456 
   457     if (!mouse) {
   458         return;
   459     }
   460 
   461     if (mouse->WarpMouse) {
   462         mouse->WarpMouse(mouse, windowID, x, y);
   463     } else {
   464         SDL_SetMouseFocus(SDL_current_mouse, windowID);
   465         SDL_SendMouseMotion(SDL_current_mouse, 0, x, y);
   466     }
   467 }
   468 
   469 SDL_Cursor *
   470 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   471                  int w, int h, int hot_x, int hot_y)
   472 {
   473     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   474     SDL_Surface *surface;
   475     SDL_Cursor *cursor;
   476     int x, y;
   477     Uint32 *pixel;
   478     Uint8 datab, maskb;
   479     const Uint32 black = 0xFF000000;
   480     const Uint32 white = 0xFFFFFFFF;
   481     const Uint32 transparent = 0x00000000;
   482 
   483     if (!mouse) {
   484         SDL_SetError("No mice are initialized");
   485         return NULL;
   486     }
   487 
   488     if (!mouse->CreateCursor) {
   489         SDL_SetError("Current mouse doesn't have cursor support");
   490         return NULL;
   491     }
   492 
   493     /* Sanity check the hot spot */
   494     if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) {
   495         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   496         return NULL;
   497     }
   498 
   499     /* Make sure the width is a multiple of 8 */
   500     w = ((w + 7) & ~7);
   501 
   502     /* Create the surface from a bitmap */
   503     surface =
   504         SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
   505                              0xFF000000);
   506     if (!surface) {
   507         return NULL;
   508     }
   509     for (y = 0; y < h; ++y) {
   510         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   511         for (x = 0; x < w; ++x) {
   512             if ((x % 8) == 0) {
   513                 datab = *data++;
   514                 maskb = *mask++;
   515             }
   516             if (maskb & 0x80) {
   517                 *pixel++ = (datab & 0x80) ? black : white;
   518             } else {
   519                 *pixel++ = (datab & 0x80) ? black : transparent;
   520             }
   521             datab <<= 1;
   522             maskb <<= 1;
   523         }
   524     }
   525 
   526     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   527     if (cursor) {
   528         cursor->mouse = mouse;
   529         cursor->next = mouse->cursors;
   530         mouse->cursors = cursor;
   531     }
   532 
   533     SDL_FreeSurface(surface);
   534 
   535     return cursor;
   536 }
   537 
   538 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   539    if this is desired for any reason.  This is used when setting
   540    the video mode and when the SDL window gains the mouse focus.
   541  */
   542 void
   543 SDL_SetCursor(SDL_Cursor * cursor)
   544 {
   545     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   546 
   547     if (!mouse) {
   548         SDL_SetError("No mice are initialized");
   549         return;
   550     }
   551 
   552     /* Set the new cursor */
   553     if (cursor) {
   554         /* Make sure the cursor is still valid for this mouse */
   555         SDL_Cursor *found;
   556         for (found = mouse->cursors; found; found = found->next) {
   557             if (found == cursor) {
   558                 break;
   559             }
   560         }
   561         if (!found) {
   562             SDL_SetError("Cursor not associated with the current mouse");
   563             return;
   564         }
   565         mouse->cur_cursor = cursor;
   566     } else {
   567         cursor = mouse->cur_cursor;
   568     }
   569 
   570     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   571         if (mouse->ShowCursor) {
   572             mouse->ShowCursor(cursor);
   573         }
   574     } else {
   575         if (mouse->ShowCursor) {
   576             mouse->ShowCursor(NULL);
   577         }
   578     }
   579 }
   580 
   581 SDL_Cursor *
   582 SDL_GetCursor(void)
   583 {
   584     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   585 
   586     if (!mouse) {
   587         return NULL;
   588     }
   589     return mouse->cur_cursor;
   590 }
   591 
   592 void
   593 SDL_FreeCursor(SDL_Cursor * cursor)
   594 {
   595     SDL_Mouse *mouse;
   596     SDL_Cursor *curr, *prev;
   597 
   598     if (!cursor) {
   599         return;
   600     }
   601     mouse = cursor->mouse;
   602 
   603     if (cursor == mouse->def_cursor) {
   604         return;
   605     }
   606     if (cursor == mouse->cur_cursor) {
   607         SDL_SetCursor(mouse->def_cursor);
   608     }
   609 
   610     for (prev = NULL, curr = mouse->cursors; curr;
   611          prev = curr, curr = curr->next) {
   612         if (curr == cursor) {
   613             if (prev) {
   614                 prev->next = curr->next;
   615             } else {
   616                 mouse->cursors = curr->next;
   617             }
   618 
   619             if (mouse->FreeCursor) {
   620                 mouse->FreeCursor(curr);
   621             }
   622             return;
   623         }
   624     }
   625 }
   626 
   627 int
   628 SDL_ShowCursor(int toggle)
   629 {
   630     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   631     SDL_bool shown;
   632 
   633     if (!mouse) {
   634         return 0;
   635     }
   636 
   637     shown = mouse->cursor_shown;
   638     if (toggle >= 0) {
   639         if (toggle) {
   640             mouse->cursor_shown = SDL_TRUE;
   641         } else {
   642             mouse->cursor_shown = SDL_FALSE;
   643         }
   644         if (mouse->cursor_shown != shown) {
   645             SDL_SetCursor(NULL);
   646         }
   647     }
   648     return shown;
   649 }
   650 
   651 /* vi: set ts=4 sw=4 expandtab: */