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