From 677a1ffc68cbdc23ced7c1a00b93b89a58183421 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 9 Jun 2006 06:42:42 +0000 Subject: [PATCH] Moved the cursor handling into the mouse code. Added support for multiple mice, potentially dynamically added and removed. --- include/SDL_mouse.h | 46 ++-- src/events/SDL_mouse.c | 310 +++++++++++++++++++++++-- src/events/SDL_mouse_c.h | 64 ++++- src/{video => events}/blank_cursor.h | 0 src/{video => events}/default_cursor.h | 0 src/video/SDL_cursor.c | 204 ---------------- src/video/SDL_sysvideo.h | 24 -- 7 files changed, 377 insertions(+), 271 deletions(-) rename src/{video => events}/blank_cursor.h (100%) rename src/{video => events}/default_cursor.h (100%) delete mode 100644 src/video/SDL_cursor.c diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h index 44a285178..ad64ed59e 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -57,7 +57,7 @@ extern DECLSPEC int SDLCALL SDL_GetNumMice(void); * * \brief Set the index of the currently selected mouse. * - * \return The index of the currently selected mouse. + * \return The index of the previously selected mouse. * * \note You can query the currently selected mouse by passing an index of -1. * @@ -109,7 +109,11 @@ extern DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y); /* - * Create a cursor using the specified data and mask (in MSB format). + * \fn SDL_Cursor *SDL_CreateCursor (const Uint8 * data, const Uint8 * mask, int w, int h, int hot_x, int hot_y) + * + * \brief Create a cursor for the currently selected mouse, using the + * specified bitmap data and mask (in MSB format). + * * The cursor width must be a multiple of 8 bits. * * The cursor is created in black and white according to the following: @@ -119,34 +123,46 @@ extern DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_WindowID windowID, * 0 0 Transparent * 1 0 Inverted color if possible, black if not. * - * Cursors created with this function must be freed with SDL_FreeCursor(). + * \sa SDL_FreeCursor() */ -extern DECLSPEC SDL_Cursor *SDLCALL SDL_CreateCursor - (Uint8 * data, Uint8 * mask, int w, int h, int hot_x, int hot_y); +extern DECLSPEC SDL_Cursor *SDLCALL SDL_CreateCursor(const Uint8 * data, + const Uint8 * mask, + int w, int h, int hot_x, + int hot_y); /* - * Set the currently active cursor to the specified one. - * If the cursor is currently visible, the change will be immediately - * represented on the display. + * \fn void SDL_SetCursor(SDL_Cursor * cursor) + * + * \brief Set the active cursor for the currently selected mouse. + * + * \note The cursor must have been created for the selected mouse. */ extern DECLSPEC void SDLCALL SDL_SetCursor(SDL_Cursor * cursor); /* - * Returns the currently active cursor. + * \fn SDL_Cursor *SDL_GetCursor(void) + * + * \brief Return the active cursor for the currently selected mouse. */ extern DECLSPEC SDL_Cursor *SDLCALL SDL_GetCursor(void); /* - * Deallocates a cursor created with SDL_CreateCursor(). + * \fn void SDL_FreeCursor(SDL_Cursor * cursor) + * + * \brief Frees a cursor created with SDL_CreateCursor(). + * + * \sa SDL_CreateCursor() */ extern DECLSPEC void SDLCALL SDL_FreeCursor(SDL_Cursor * cursor); /* - * Toggle whether or not the cursor is shown on the screen. - * The cursor start off displayed, but can be turned off. - * SDL_ShowCursor() returns 1 if the cursor was being displayed - * before the call, or 0 if it was not. You can query the current - * state by passing a 'toggle' value of -1. + * \fn int SDL_ShowCursor(int toggle) + * + * \brief Toggle whether or not the cursor is shown for the currently selected mouse. + * + * \param toggle 1 to show the cursor, 0 to hide it, -1 to query the current state. + * + * \return 1 if the cursor is shown, or 0 if the cursor is hidden. */ extern DECLSPEC int SDLCALL SDL_ShowCursor(int toggle); diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 80e7fc8e7..5f426496e 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -26,11 +26,12 @@ #include "SDL_events.h" #include "SDL_events_c.h" #include "SDL_mouse_c.h" +#include "default_cursor.h" static int SDL_num_mice; static int SDL_current_mouse; -static SDL_Mouse *SDL_mice; +static SDL_Mouse **SDL_mice; /* Public functions */ @@ -40,45 +41,97 @@ SDL_MouseInit(void) return (0); } +SDL_Mouse * +SDL_GetMouse(int index) +{ + if (index < 0 || index >= SDL_num_mice) { + return NULL; + } + return SDL_mice[index]; +} + int -SDL_AddMouse(SDL_WindowID focus, int x, int y, Uint8 buttonstate) +SDL_AddMouse(const SDL_Mouse * mouse, int index) { - SDL_Mouse *new_mice; - int index; - SDL_Mouse *mouse; + SDL_Mouse **mice; + SDL_Cursor *cursor; + int selected_mouse; + + /* Add the mouse to the list of mice */ + if (index < 0 || index >= SDL_num_mice || SDL_mice[index]) { + mice = + (SDL_Mouse **) SDL_realloc(SDL_mice, + (SDL_num_mice + 1) * sizeof(*mice)); + if (!mice) { + SDL_OutOfMemory(); + return -1; + } - new_mice = - (SDL_Mouse *) SDL_realloc(SDL_mice, - (SDL_num_mice + 1) * sizeof(*new_mice)); - if (!new_mice) { + SDL_mice = mice; + index = SDL_num_mice++; + } + SDL_mice[index] = (SDL_Mouse *) SDL_malloc(sizeof(*SDL_mice[index])); + if (!SDL_mice[index]) { SDL_OutOfMemory(); return -1; } - - index = SDL_num_mice++; - mouse = &SDL_mice[index]; - mouse->focus = focus; - mouse->x = x; - mouse->y = y; - mouse->xdelta = 0; - mouse->ydelta = 0; - mouse->buttonstate = buttonstate; + *SDL_mice[index] = *mouse; + + /* Create the default cursor for the mouse */ + SDL_mice[index]->cursor_shown = SDL_TRUE; + selected_mouse = SDL_SelectMouse(index); + SDL_mice[index]->cur_cursor = NULL; + SDL_mice[index]->def_cursor = + SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, + DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY); + SDL_SetCursor(SDL_mice[index]->def_cursor); + SDL_SelectMouse(selected_mouse); return index; } -SDL_Mouse * -SDL_GetMouse(int index) +void +SDL_DelMouse(int index) { - if (index < 0 || index >= SDL_num_mice) { - return NULL; + SDL_Mouse *mouse = SDL_GetMouse(index); + + if (!mouse) { + return; + } + + mouse->def_cursor = NULL; + while (mouse->cursors) { + SDL_FreeCursor(mouse->cursors); + } + + if (mouse->FreeMouse) { + mouse->FreeMouse(mouse); + } + SDL_free(mouse); + + SDL_mice[index] = NULL; +} + +void +SDL_ResetMouse(int index) +{ + SDL_Mouse *mouse = SDL_GetMouse(index); + + if (!mouse) { + return; } - return &SDL_mice[index]; + + /* FIXME */ } void SDL_MouseQuit(void) { + int i; + + for (i = 0; i < SDL_num_mice; ++i) { + SDL_DelMouse(i); + } SDL_num_mice = 0; SDL_current_mouse = 0; @@ -201,9 +254,16 @@ SDL_SendMouseMotion(int index, SDL_WindowID windowID, int relative, int x, } /* Update internal mouse state */ + mouse->x = x; + mouse->y = y; mouse->xdelta += xrel; mouse->ydelta += yrel; + /* Move the mouse cursor, if needed */ + if (mouse->MoveCursor && mouse->cur_cursor) { + mouse->MoveCursor(mouse->cur_cursor); + } + /* Post the event, if desired */ posted = 0; if (SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE) { @@ -225,8 +285,8 @@ SDL_SendMouseMotion(int index, SDL_WindowID windowID, int relative, int x, } int -SDL_PrivateMouseButton(int index, SDL_WindowID windowID, Uint8 state, - Uint8 button) +SDL_SendMouseButton(int index, SDL_WindowID windowID, Uint8 state, + Uint8 button) { SDL_Mouse *mouse = SDL_GetMouse(index); int posted; @@ -282,4 +342,204 @@ SDL_PrivateMouseButton(int index, SDL_WindowID windowID, Uint8 state, return posted; } +void +SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + return; + } + + if (mouse->WarpMouse) { + mouse->WarpMouse(mouse, windowID, x, y); + } else { + SDL_SendMouseMotion(SDL_current_mouse, windowID, 0, x, y); + } +} + +SDL_Cursor * +SDL_CreateCursor(const Uint8 * data, const Uint8 * mask, + int w, int h, int hot_x, int hot_y) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_Surface *surface; + SDL_Cursor *cursor; + int x, y; + Uint32 *pixel; + Uint8 datab, maskb; + const Uint32 black = 0xFF000000; + const Uint32 white = 0xFFFFFFFF; + const Uint32 transparent = 0x00000000; + + if (!mouse) { + SDL_SetError("No mice are initialized"); + return NULL; + } + + if (!mouse->CreateCursor) { + SDL_SetError("Current mouse doesn't have cursor support"); + return NULL; + } + + /* Sanity check the hot spot */ + if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) { + SDL_SetError("Cursor hot spot doesn't lie within cursor"); + return NULL; + } + + /* Make sure the width is a multiple of 8 */ + w = ((w + 7) & ~7); + + /* Create the surface from a bitmap */ + surface = + SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, + 0xFF000000); + if (!surface) { + return NULL; + } + for (y = 0; y < h; ++y) { + pixel = + (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch + + x * 4); + for (x = 0; x < w; ++x) { + if ((x % 8) == 0) { + datab = *data++; + maskb = *mask++; + } + if (maskb & 0x80) { + *pixel++ = (datab & 0x80) ? black : white; + } else { + *pixel++ = (datab & 0x80) ? black : transparent; + } + datab <<= 1; + maskb <<= 1; + } + } + + cursor = mouse->CreateCursor(surface, hot_x, hot_y); + if (cursor) { + cursor->mouse = mouse; + cursor->next = mouse->cursors; + mouse->cursors = cursor; + } + + SDL_FreeSurface(surface); + + return cursor; +} + +/* SDL_SetCursor(NULL) can be used to force the cursor redraw, + if this is desired for any reason. This is used when setting + the video mode and when the SDL window gains the mouse focus. + */ +void +SDL_SetCursor(SDL_Cursor * cursor) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + SDL_SetError("No mice are initialized"); + return; + } + + /* Set the new cursor */ + if (cursor) { + /* Make sure the cursor is still valid for this mouse */ + SDL_Cursor *found; + for (found = mouse->cursors; found; found = found->next) { + if (found == cursor) { + break; + } + } + if (!found) { + SDL_SetError("Cursor not associated with the current mouse"); + return; + } + mouse->cur_cursor = cursor; + } else { + cursor = mouse->cur_cursor; + } + + if (cursor && mouse->cursor_shown) { + if (mouse->ShowCursor) { + mouse->ShowCursor(cursor); + } + } else { + if (mouse->ShowCursor) { + mouse->ShowCursor(NULL); + } + } +} + +SDL_Cursor * +SDL_GetCursor(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + return NULL; + } + return mouse->cur_cursor; +} + +void +SDL_FreeCursor(SDL_Cursor * cursor) +{ + SDL_Mouse *mouse; + SDL_Cursor *curr, *prev; + + if (!cursor) { + return; + } + mouse = cursor->mouse; + + if (cursor == mouse->def_cursor) { + return; + } + if (cursor == mouse->cur_cursor) { + SDL_SetCursor(mouse->def_cursor); + } + + for (prev = NULL, curr = mouse->cursors; curr; + prev = curr, curr = curr->next) { + if (curr == cursor) { + if (prev) { + prev->next = curr->next; + } else { + mouse->cursors = curr->next; + } + + if (mouse->FreeCursor) { + mouse->FreeCursor(curr); + } + return; + } + } +} + +int +SDL_ShowCursor(int toggle) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_bool shown; + + if (!mouse) { + return 0; + } + + shown = mouse->cursor_shown; + if (toggle >= 0) { + if (toggle) { + mouse->cursor_shown = SDL_TRUE; + } else { + mouse->cursor_shown = SDL_FALSE; + } + if (mouse->cursor_shown != shown) { + SDL_SetCursor(NULL); + } + } + return shown; +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index ac2225517..a02a14ef2 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -24,23 +24,81 @@ #ifndef _SDL_mouse_c_h #define _SDL_mouse_c_h -typedef struct +typedef struct SDL_Mouse SDL_Mouse; + +struct SDL_Cursor +{ + SDL_Mouse *mouse; + + SDL_Cursor *next; + + void *driverdata; +}; + +struct SDL_Mouse { + /* Create a cursor from a surface */ + SDL_Cursor *(*CreateCursor) (SDL_Surface * surface, int hot_x, int hot_y); + + /* Show the specified cursor, or hide if cursor is NULL */ + int (*ShowCursor) (SDL_Cursor * cursor); + + /* This is called when a mouse motion event occurs */ + void (*MoveCursor) (SDL_Cursor * cursor); + + /* Free a window manager cursor */ + void (*FreeCursor) (SDL_Cursor * cursor); + + /* Warp the mouse to (x,y) */ + void (*WarpMouse) (SDL_Mouse * mouse, SDL_WindowID windowID, int x, + int y); + + /* Free the mouse when it's time */ + void (*FreeMouse) (SDL_Mouse * mouse); + + /* Data common to all mice */ SDL_WindowID focus; int x; int y; int xdelta; int ydelta; Uint8 buttonstate; -} SDL_Mouse; + SDL_Cursor *cursors; + SDL_Cursor *def_cursor; + SDL_Cursor *cur_cursor; + SDL_bool cursor_shown; + + void *driverdata; +}; + + +/* Initialize the mouse subsystem */ extern int SDL_MouseInit(void); -extern int SDL_AddMouse(SDL_WindowID focus, int x, int y, Uint8 buttonstate); + +/* Get the mouse at an index */ extern SDL_Mouse *SDL_GetMouse(int index); + +/* Add a mouse, possibly reattaching at a particular index (or -1), + returning the index of the mouse, or -1 if there was an error. + */ +extern int SDL_AddMouse(const SDL_Mouse * mouse, int index); + +/* Remove a mouse at an index, clearing the slot for later */ +extern void SDL_DelMouse(int index); + +/* Clear the button state of a mouse at an index */ +extern void SDL_ResetMouse(int index); + +/* Send a mouse motion event for a mouse at an index */ extern int SDL_SendMouseMotion(int index, SDL_WindowID windowID, int relative, int x, int y); + +/* Send a mouse button event for a mouse at an index */ extern int SDL_SendMouseButton(int index, SDL_WindowID windowID, Uint8 state, Uint8 button); + +/* Shutdown the mouse subsystem */ extern void SDL_MouseQuit(void); #endif /* _SDL_mouse_c_h */ diff --git a/src/video/blank_cursor.h b/src/events/blank_cursor.h similarity index 100% rename from src/video/blank_cursor.h rename to src/events/blank_cursor.h diff --git a/src/video/default_cursor.h b/src/events/default_cursor.h similarity index 100% rename from src/video/default_cursor.h rename to src/events/default_cursor.h diff --git a/src/video/SDL_cursor.c b/src/video/SDL_cursor.c deleted file mode 100644 index b0b3b5268..000000000 --- a/src/video/SDL_cursor.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2006 Sam Lantinga - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ -#include "SDL_config.h" - -/* General cursor handling code for SDL */ - -#include "SDL_video.h" -#include "SDL_mouse.h" -#include "SDL_sysvideo.h" -#include "SDL_cursor_c.h" -#include "default_cursor.h" - -/* These are static for our cursor handling code */ -/* FIXME: Add support for multiple simultaneous cursors */ -volatile int SDL_cursorstate = CURSOR_VISIBLE; -SDL_Cursor *SDL_cursor = NULL; -static SDL_Cursor *SDL_defcursor = NULL; - -/* Public functions */ -void -SDL_CursorQuit(void) -{ - if (SDL_cursor != NULL) { - SDL_Cursor *cursor; - - SDL_cursorstate &= ~CURSOR_VISIBLE; - if (SDL_cursor != SDL_defcursor) { - SDL_FreeCursor(SDL_cursor); - } - SDL_cursor = NULL; - if (SDL_defcursor != NULL) { - cursor = SDL_defcursor; - SDL_defcursor = NULL; - SDL_FreeCursor(cursor); - } - } -} - -int -SDL_CursorInit(void) -{ - /* We don't have mouse focus, and the cursor isn't drawn yet */ -#ifndef IPOD - SDL_cursorstate = CURSOR_VISIBLE; -#endif - - /* Create the default cursor */ - if (SDL_defcursor == NULL) { - SDL_defcursor = SDL_CreateCursor(default_cdata, default_cmask, - DEFAULT_CWIDTH, DEFAULT_CHEIGHT, - DEFAULT_CHOTX, DEFAULT_CHOTY); - SDL_SetCursor(SDL_defcursor); - } - - /* That's it! */ - return (0); -} - -SDL_Cursor * -SDL_CreateCursor(Uint8 * data, Uint8 * mask, - int w, int h, int hot_x, int hot_y) -{ - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - SDL_Cursor *cursor; - - /* Make sure the width is a multiple of 8 */ - w = ((w + 7) & ~7); - - /* Sanity check the hot spot */ - if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) { - SDL_SetError("Cursor hot spot doesn't lie within cursor"); - return (NULL); - } - - if (_this->CreateWMCursor) { - cursor = _this->CreateWMCursor(_this, data, mask, w, h, hot_x, hot_y); - } else { - cursor = NULL; - } - return (cursor); -} - -/* SDL_SetCursor(NULL) can be used to force the cursor redraw, - if this is desired for any reason. This is used when setting - the video mode and when the SDL window gains the mouse focus. - */ -void -SDL_SetCursor(SDL_Cursor * cursor) -{ - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - - /* Make sure that the video subsystem has been initialized */ - if (!_this) { - return; - } - - /* Set the new cursor */ - if (cursor && (cursor != SDL_cursor)) { - SDL_cursor = cursor; - } - - /* Draw the new mouse cursor */ - if (SDL_cursor && (SDL_cursorstate & CURSOR_VISIBLE)) { - if (_this->ShowWMCursor) { - _this->ShowWMCursor(_this, SDL_cursor); - } - } else { - /* Erase window manager mouse (cursor not visible) */ - if (_this->ShowWMCursor) { - _this->ShowWMCursor(_this, NULL); - } - } -} - -SDL_Cursor * -SDL_GetCursor(void) -{ - return (SDL_cursor); -} - -void -SDL_FreeCursor(SDL_Cursor * cursor) -{ - if (cursor) { - if (cursor == SDL_cursor) { - SDL_SetCursor(SDL_defcursor); - } - if (cursor != SDL_defcursor) { - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - - if (_this && _this->FreeWMCursor) { - _this->FreeWMCursor(_this, cursor); - } - } - } -} - -int -SDL_ShowCursor(int toggle) -{ - int showing; - - showing = (SDL_cursorstate & CURSOR_VISIBLE); - if (toggle >= 0) { - if (toggle) { - SDL_cursorstate |= CURSOR_VISIBLE; - } else { - SDL_cursorstate &= ~CURSOR_VISIBLE; - } - if ((SDL_cursorstate & CURSOR_VISIBLE) != showing) { - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - - SDL_SetCursor(NULL); - if (_this && _this->CheckMouseMode) { - _this->CheckMouseMode(_this); - } - } - } else { - /* Query current state */ ; - } - return (showing ? 1 : 0); -} - -void -SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y) -{ - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - - /* FIXME: This should specify the target window */ - if (!_this || !SDL_CurrentDisplay.num_windows) { - SDL_SetError("A window must be created before warping mouse"); - return; - } - - if (!windowID) { - windowID = SDL_CurrentWindow; - } - - /* This generates a mouse motion event */ - if (_this->WarpWMCursor) { - _this->WarpWMCursor(_this, windowID, x, y); - } -} - -/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 6ce7098ac..3a5294c7a 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -291,30 +291,6 @@ struct SDL_VideoDevice int is_32bit; #endif - /* * * */ - /* Cursor manager functions */ - - /* Free a window manager cursor - This function can be NULL if CreateWMCursor is also NULL. - */ - void (*FreeCursor) (_THIS, SDL_Cursor * cursor); - - /* If not NULL, create a black/white window manager cursor */ - SDL_Cursor *(*CreateCursor) (_THIS, - Uint8 * data, Uint8 * mask, int w, int h, - int hot_x, int hot_y); - - /* Show the specified cursor, or hide if cursor is NULL */ - int (*ShowCursor) (_THIS, SDL_Cursor * cursor); - - /* Warp the window manager cursor to (x,y) - If NULL, a mouse motion event is posted internally. - */ - void (*WarpCursor) (_THIS, SDL_WindowID windowID, int x, int y); - - /* If not NULL, this is called when a mouse motion event occurs */ - void (*MoveCursor) (_THIS, int x, int y); - /* Determine whether the mouse should be in relative mode or not. This function is called when the input grab state or cursor visibility state changes.