From b0b1f13269b768c4ac640028877042f7c7a36982 Mon Sep 17 00:00:00 2001 From: Marco Antognini Date: Sat, 4 Mar 2017 00:10:57 +0100 Subject: [PATCH] Added Win32 implementation --- include/SFML/Window/Cursor.hpp | 28 ++--- include/SFML/Window/Window.hpp | 3 + src/SFML/Window/Win32/CursorImpl.cpp | 127 +++++++++++++++++++++- src/SFML/Window/Win32/CursorImpl.hpp | 8 ++ src/SFML/Window/Win32/WindowImplWin32.cpp | 121 +++------------------ src/SFML/Window/Win32/WindowImplWin32.hpp | 4 +- 6 files changed, 165 insertions(+), 126 deletions(-) mode change 100644 => 100755 src/SFML/Window/Win32/CursorImpl.cpp mode change 100644 => 100755 src/SFML/Window/Win32/CursorImpl.hpp mode change 100644 => 100755 src/SFML/Window/Win32/WindowImplWin32.cpp mode change 100644 => 100755 src/SFML/Window/Win32/WindowImplWin32.hpp diff --git a/include/SFML/Window/Cursor.hpp b/include/SFML/Window/Cursor.hpp index f190a4de9..c85ac6996 100644 --- a/include/SFML/Window/Cursor.hpp +++ b/include/SFML/Window/Cursor.hpp @@ -56,18 +56,18 @@ public: /// Type | Linux | Mac OS X | Windows /// ------------------------------------|:-----:|:--------:|:--------: /// sf::Cursor::Arrow | yes | yes | yes - /// sf::Cursor::ArrowWait | no | no | no - /// sf::Cursor::Wait | no | no | no - /// sf::Cursor::Text | no | yes | no - /// sf::Cursor::Hand | no | yes | no - /// sf::Cursor::SizeHorizontal | no | yes | no - /// sf::Cursor::SizeVertical | no | yes | no - /// sf::Cursor::SizeTopLeftBottomRight | no | no | no - /// sf::Cursor::SizeBottomLeftTopRight | no | no | no - /// sf::Cursor::SizeAll | no | no | no - /// sf::Cursor::Cross | no | yes | no - /// sf::Cursor::Help | no | no | no - /// sf::Cursor::NotAllowed | no | yes | no + /// sf::Cursor::ArrowWait | no | no | yes + /// sf::Cursor::Wait | no | no | yes + /// sf::Cursor::Text | no | yes | yes + /// sf::Cursor::Hand | no | yes | yes + /// sf::Cursor::SizeHorizontal | no | yes | yes + /// sf::Cursor::SizeVertical | no | yes | yes + /// sf::Cursor::SizeTopLeftBottomRight | no | no | yes + /// sf::Cursor::SizeBottomLeftTopRight | no | no | yes + /// sf::Cursor::SizeAll | no | no | yes + /// sf::Cursor::Cross | no | yes | yes + /// sf::Cursor::Help | no | no | yes + /// sf::Cursor::NotAllowed | no | yes | yes /// //////////////////////////////////////////////////////////// enum Type @@ -195,8 +195,8 @@ private: /// with either loadFromPixels() or loadFromSystem(), the /// cursor can be changed with sf::Window::setMouseCursor(). /// -/// \todo Does Windows or Linux requires the Cursor instance -/// to outlive it's usage? +/// The behaviour is undefined if the cursor is destroyed while +/// in use by the window. /// /// Usage example: /// \code diff --git a/include/SFML/Window/Window.hpp b/include/SFML/Window/Window.hpp index c9fc2c275..44220360b 100644 --- a/include/SFML/Window/Window.hpp +++ b/include/SFML/Window/Window.hpp @@ -367,6 +367,9 @@ public: /// /// Upon window creation, the arrow cursor is used by default. /// + /// \warning The cursor must not be destroyed while in use by + /// the window. + /// /// \warning Features related to Cursor are not supported on /// iOS and Android. /// diff --git a/src/SFML/Window/Win32/CursorImpl.cpp b/src/SFML/Window/Win32/CursorImpl.cpp old mode 100644 new mode 100755 index 146d54c15..29273b0bb --- a/src/SFML/Window/Win32/CursorImpl.cpp +++ b/src/SFML/Window/Win32/CursorImpl.cpp @@ -26,6 +26,8 @@ // Headers //////////////////////////////////////////////////////////// #include +#include +#include namespace sf { @@ -33,33 +35,148 @@ namespace priv { //////////////////////////////////////////////////////////// -CursorImpl::CursorImpl() +CursorImpl::CursorImpl() : +m_cursor(NULL) { - // TODO + // That's it. } //////////////////////////////////////////////////////////// CursorImpl::~CursorImpl() { - // TODO + release(); } //////////////////////////////////////////////////////////// bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot) { - // TODO + release(); + + // Create the bitmap that will hold our color data + BITMAPV5HEADER bitmapHeader; + std::memset(&bitmapHeader, 0, sizeof(BITMAPV5HEADER)); + + bitmapHeader.bV5Size = sizeof(BITMAPV5HEADER); + bitmapHeader.bV5Width = size.x; + bitmapHeader.bV5Height = -static_cast(size.y); // Negative indicates origin is in upper-left corner + bitmapHeader.bV5Planes = 1; + bitmapHeader.bV5BitCount = 32; + bitmapHeader.bV5Compression = BI_BITFIELDS; + bitmapHeader.bV5RedMask = 0x00ff0000; + bitmapHeader.bV5GreenMask = 0x0000ff00; + bitmapHeader.bV5BlueMask = 0x000000ff; + bitmapHeader.bV5AlphaMask = 0xff000000; + + Uint8* bitmapData = NULL; + + HDC screenDC = GetDC(NULL); + HBITMAP color = CreateDIBSection( + screenDC, + reinterpret_cast(&bitmapHeader), + DIB_RGB_COLORS, + reinterpret_cast(&bitmapData), + NULL, + 0 + ); + ReleaseDC(NULL, screenDC); + + if (!color) + { + err() << "Failed to create cursor color bitmap" << std::endl; + return false; + } + + // Fill our bitmap with the cursor color data + std::memcpy(bitmapData, pixels, size.x * size.y * 4); + + // Create a dummy mask bitmap (it won't be used) + HBITMAP mask = CreateBitmap(size.x, size.y, 1, 1, NULL); + + if (!mask) + { + DeleteObject(color); + err() << "Failed to create cursor mask bitmap" << std::endl; + return false; + } + + // Create the structure that describes our cursor + ICONINFO cursorInfo; + std::memset(&cursorInfo, 0, sizeof(ICONINFO)); + + cursorInfo.fIcon = FALSE; // This is a cursor and not an icon + cursorInfo.xHotspot = hotspot.x; + cursorInfo.yHotspot = hotspot.y; + cursorInfo.hbmColor = color; + cursorInfo.hbmMask = mask; + + // Create the cursor + m_cursor = reinterpret_cast(CreateIconIndirect(&cursorInfo)); + + // The data has been copied into the cursor, so get rid of these + DeleteObject(color); + DeleteObject(mask); + + if (m_cursor) + { + return true; + } + else + { + err() << "Failed to create cursor from bitmaps" << std::endl; + return false; + } } //////////////////////////////////////////////////////////// bool CursorImpl::loadFromSystem(Cursor::Type type) { - // TODO + release(); + + LPCTSTR shape; + switch (type) + { + case Cursor::Arrow: shape = IDC_ARROW; break; + case Cursor::ArrowWait: shape = IDC_APPSTARTING; break; + case Cursor::Wait: shape = IDC_WAIT; break; + case Cursor::Text: shape = IDC_IBEAM; break; + case Cursor::Hand: shape = IDC_HAND; break; + case Cursor::SizeHorizontal: shape = IDC_SIZEWE; break; + case Cursor::SizeVertical: shape = IDC_SIZENS; break; + case Cursor::SizeTopLeftBottomRight: shape = IDC_SIZENWSE; break; + case Cursor::SizeBottomLeftTopRight: shape = IDC_SIZENESW; break; + case Cursor::SizeAll: shape = IDC_SIZEALL; break; + case Cursor::Cross: shape = IDC_CROSS; break; + case Cursor::Help: shape = IDC_HELP; break; + case Cursor::NotAllowed: shape = IDC_NO; break; + } + + // Create a copy of the shared system cursor that we can destroy later + m_cursor = CopyCursor(LoadCursor(NULL, shape)); + + if (m_cursor) + { + return true; + } + else + { + err() << "Could not create copy of a system cursor" << std::endl; + return false; + } } +//////////////////////////////////////////////////////////// +void CursorImpl::release() +{ + if (m_cursor) { + DestroyCursor(m_cursor); + m_cursor = NULL; + } +} + } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Win32/CursorImpl.hpp b/src/SFML/Window/Win32/CursorImpl.hpp old mode 100644 new mode 100755 index dcab6489d..b65aef232 --- a/src/SFML/Window/Win32/CursorImpl.hpp +++ b/src/SFML/Window/Win32/CursorImpl.hpp @@ -32,6 +32,7 @@ #include #include +#include namespace sf { @@ -82,9 +83,16 @@ private: friend class WindowImplWin32; + //////////////////////////////////////////////////////////// + /// \brief Release the cursor, if we have loaded one. + /// + //////////////////////////////////////////////////////////// + void release(); + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// + HCURSOR m_cursor; }; } // namespace priv diff --git a/src/SFML/Window/Win32/WindowImplWin32.cpp b/src/SFML/Window/Win32/WindowImplWin32.cpp old mode 100644 new mode 100755 index 2056296b8..78d13d31b --- a/src/SFML/Window/Win32/WindowImplWin32.cpp +++ b/src/SFML/Window/Win32/WindowImplWin32.cpp @@ -132,8 +132,8 @@ namespace priv WindowImplWin32::WindowImplWin32(WindowHandle handle) : m_handle (handle), m_callback (0), -m_cursor (NULL), -m_loadedCursor (NULL), +m_cursorVisible (true), // might need to call GetCursorInfo +m_lastCursor (LoadCursor(NULL, IDC_ARROW)), m_icon (NULL), m_keyRepeatEnabled(true), m_lastSize (0, 0), @@ -165,8 +165,8 @@ m_cursorGrabbed (false) WindowImplWin32::WindowImplWin32(VideoMode mode, const String& title, Uint32 style, const ContextSettings& /*settings*/) : m_handle (NULL), m_callback (0), -m_cursor (NULL), -m_loadedCursor (NULL), +m_cursorVisible (true), // might need to call GetCursorInfo +m_lastCursor (LoadCursor(NULL, IDC_ARROW)), m_icon (NULL), m_keyRepeatEnabled(true), m_lastSize (mode.width, mode.height), @@ -241,9 +241,7 @@ m_cursorGrabbed (m_fullscreen) //////////////////////////////////////////////////////////// WindowImplWin32::~WindowImplWin32() { - // Destroy the cursor - if (m_loadedCursor) - DestroyCursor(m_loadedCursor); + // TODO should we restore the cursor shape and visibility? // Destroy the custom icon, if any if (m_icon) @@ -396,16 +394,14 @@ void WindowImplWin32::setVisible(bool visible) //////////////////////////////////////////////////////////// void WindowImplWin32::setMouseCursorVisible(bool visible) { - // Set the default mouse cursor if none has been loaded yet - if (!m_loadedCursor) - setMouseCursor(Window::Arrow); - - if (visible) - m_cursor = m_loadedCursor; - else - m_cursor = NULL; - - SetCursor(m_cursor); + // Don't call twice ShowCursor with the same parameter value; + // we don't want to increment/decrement the internal counter + // more than once. + if (visible != m_cursorVisible) + { + m_cursorVisible = visible; + ShowCursor(visible); + } } @@ -420,93 +416,8 @@ void WindowImplWin32::setMouseCursorGrabbed(bool grabbed) //////////////////////////////////////////////////////////// void WindowImplWin32::setMouseCursor(const CursorImpl& cursor) { -} - - -//////////////////////////////////////////////////////////// -void WindowImplWin32::setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY) -{ - // Create the bitmap that will hold our color data - BITMAPV5HEADER bitmapHeader; - std::memset(&bitmapHeader, 0, sizeof(BITMAPV5HEADER)); - - bitmapHeader.bV5Size = sizeof(BITMAPV5HEADER); - bitmapHeader.bV5Width = width; - bitmapHeader.bV5Height = -height; // Negative indicates origin is in upper-left corner - bitmapHeader.bV5Planes = 1; - bitmapHeader.bV5BitCount = 32; - bitmapHeader.bV5Compression = BI_BITFIELDS; - bitmapHeader.bV5RedMask = 0x00ff0000; - bitmapHeader.bV5GreenMask = 0x0000ff00; - bitmapHeader.bV5BlueMask = 0x000000ff; - bitmapHeader.bV5AlphaMask = 0xff000000; - - Uint8* bitmapData = NULL; - - HDC screenDC = GetDC(NULL); - HBITMAP color = CreateDIBSection( - screenDC, - reinterpret_cast(&bitmapHeader), - DIB_RGB_COLORS, - reinterpret_cast(&bitmapData), - NULL, - 0 - ); - ReleaseDC(NULL, screenDC); - - if (!color) - { - err() << "Failed to create cursor color bitmap" << std::endl; - return; - } - - // Fill our bitmap with the cursor color data - std::memcpy(bitmapData, pixels, width * height * 4); - - // Create a dummy mask bitmap (it won't be used) - HBITMAP mask = CreateBitmap(width, height, 1, 1, NULL); - - if (!mask) - { - DeleteObject(color); - err() << "Failed to create cursor mask bitmap" << std::endl; - return; - } - - // Create the structure that describes our cursor - ICONINFO cursorInfo; - std::memset(&cursorInfo, 0, sizeof(ICONINFO)); - - cursorInfo.fIcon = FALSE; // This is a cursor and not an icon - cursorInfo.xHotspot = hotspotX; - cursorInfo.yHotspot = hotspotY; - cursorInfo.hbmColor = color; - cursorInfo.hbmMask = mask; - - // Create the cursor - HCURSOR newCursor = reinterpret_cast(CreateIconIndirect(&cursorInfo)); - - // The data has been copied into the cursor, so get rid of these - DeleteObject(color); - DeleteObject(mask); - - if (!newCursor) - { - err() << "Failed to create cursor from bitmaps" << std::endl; - return; - } - - HCURSOR oldCursor = m_loadedCursor; - m_loadedCursor = newCursor; - - if (m_cursor) - { - m_cursor = m_loadedCursor; - SetCursor(m_cursor); - } - - if (oldCursor) - DestroyCursor(oldCursor); + m_lastCursor = cursor.m_cursor; + SetCursor(m_lastCursor); } @@ -671,7 +582,7 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) { // The mouse has moved, if the cursor is in our window we must refresh the cursor if (LOWORD(lParam) == HTCLIENT) - SetCursor(m_cursor); + SetCursor(m_lastCursor); break; } diff --git a/src/SFML/Window/Win32/WindowImplWin32.hpp b/src/SFML/Window/Win32/WindowImplWin32.hpp old mode 100644 new mode 100755 index 289d6ae33..8565e88f1 --- a/src/SFML/Window/Win32/WindowImplWin32.hpp +++ b/src/SFML/Window/Win32/WindowImplWin32.hpp @@ -274,8 +274,8 @@ private: //////////////////////////////////////////////////////////// HWND m_handle; ///< Win32 handle of the window LONG_PTR m_callback; ///< Stores the original event callback function of the control - HCURSOR m_cursor; ///< The system cursor currently displayed into the window, NULL if hidden - HCURSOR m_loadedCursor; ///< The system cursor selected to be displayed into the window + bool m_cursorVisible; ///< Is the cursor visible or hidden? + HCURSOR m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid HICON m_icon; ///< Custom icon assigned to the window bool m_keyRepeatEnabled; ///< Automatic key-repeat state for keydown events Vector2u m_lastSize; ///< The last handled size of the window