From b0b1f13269b768c4ac640028877042f7c7a36982 Mon Sep 17 00:00:00 2001
From: Marco Antognini <antognini.marco@gmail.com>
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 f190a4de..c85ac699 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 c9fc2c27..44220360 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 146d54c1..29273b0b
--- a/src/SFML/Window/Win32/CursorImpl.cpp
+++ b/src/SFML/Window/Win32/CursorImpl.cpp
@@ -26,6 +26,8 @@
 // Headers
 ////////////////////////////////////////////////////////////
 #include <SFML/Window/Win32/CursorImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <cstring>
 
 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<int>(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<const BITMAPINFO*>(&bitmapHeader),
+        DIB_RGB_COLORS,
+        reinterpret_cast<void**>(&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<HCURSOR>(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 dcab6489..b65aef23
--- a/src/SFML/Window/Win32/CursorImpl.hpp
+++ b/src/SFML/Window/Win32/CursorImpl.hpp
@@ -32,6 +32,7 @@
 #include <SFML/System/NonCopyable.hpp>
 #include <SFML/System/Vector2.hpp>
 
+#include <windows.h>
 
 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 2056296b..78d13d31
--- 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<const BITMAPINFO*>(&bitmapHeader),
-        DIB_RGB_COLORS,
-        reinterpret_cast<void**>(&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<HCURSOR>(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 289d6ae3..8565e88f
--- 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