From 6f5a7d1b1b4a03d06355935ae4deb6c2877285da Mon Sep 17 00:00:00 2001 From: binary1248 Date: Sun, 15 Mar 2015 03:30:01 +0100 Subject: [PATCH] Implemented methods to set the displayed cursor to a system cursor type or custom bitmap image. --- include/SFML/Window/Window.hpp | 60 +++++ src/SFML/Window/Android/WindowImplAndroid.cpp | 14 + src/SFML/Window/Android/WindowImplAndroid.hpp | 20 ++ src/SFML/Window/OSX/WindowImplCocoa.hpp | 20 ++ src/SFML/Window/OSX/WindowImplCocoa.mm | 14 + src/SFML/Window/Unix/GlxContext.cpp | 2 +- src/SFML/Window/Unix/WindowImplX11.cpp | 247 +++++++++++++++++- src/SFML/Window/Unix/WindowImplX11.hpp | 26 +- src/SFML/Window/Win32/WindowImplWin32.cpp | 146 ++++++++++- src/SFML/Window/Win32/WindowImplWin32.hpp | 23 +- src/SFML/Window/Window.cpp | 16 ++ src/SFML/Window/WindowImpl.hpp | 21 ++ src/SFML/Window/iOS/WindowImplUIKit.hpp | 20 ++ src/SFML/Window/iOS/WindowImplUIKit.mm | 14 + 14 files changed, 631 insertions(+), 12 deletions(-) diff --git a/include/SFML/Window/Window.hpp b/include/SFML/Window/Window.hpp index 7135fdfe9..3a0534f89 100644 --- a/include/SFML/Window/Window.hpp +++ b/include/SFML/Window/Window.hpp @@ -56,6 +56,29 @@ class Event; //////////////////////////////////////////////////////////// class SFML_WINDOW_API Window : GlResource, NonCopyable { +public: + + //////////////////////////////////////////////////////////// + /// \brief Enumeration of the native system cursor types + /// + //////////////////////////////////////////////////////////// + enum Cursor + { + Arrow, ///< Arrow cursor (default) + ArrowWait, ///< Busy arrow cursor + Wait, ///< Busy cursor + Text, ///< I-beam, cursor when hovering over a field allowing text entry + Hand, ///< Pointing hand cursor + SizeHorizontal, ///< Horizontal double arrow cursor + SizeVertical, ///< Vertical double arrow cursor + SizeTopLeftBottomRight, ///< Double arrow cursor going from top-left to bottom-right + SizeBottomLeftTopRight, ///< Double arrow cursor going from bottom-left to top-right + SizeAll, ///< Combination of CursorSizeHorizontal and CursorSizeVertical + Cross, ///< Crosshair cursor + Help, ///< Help cursor + NotAllowed ///< Action not allowed cursor + }; + public: //////////////////////////////////////////////////////////// @@ -361,6 +384,43 @@ public: //////////////////////////////////////////////////////////// void setMouseCursorGrabbed(bool grabbed); + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to a native system cursor + /// + /// Upon window creation, the arrow cursor is used by default. + /// + /// \param cursor Native system cursor type to display + /// + //////////////////////////////////////////////////////////// + void setMouseCursor(Cursor cursor); + + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to the provided image + /// + /// \a pixels must be an array of \a width x \a height pixels + /// in 32-bit RGBA format. If not, this will cause undefined behavior. + /// + /// If \a pixels is null or either \a width or \a height are 0, + /// the current cursor is left unchanged. + /// + /// In addition to specifying the pixel data, you can also + /// specify the location of the hotspot of the cursor. The + /// hotspot is the pixel coordinate within the cursor image + /// which will be located exactly where the mouse pointer + /// position is. Any mouse actions that are performed will + /// return the window/screen location of the hotspot. + /// + /// Upon window creation, the arrow cursor is used by default. + /// + /// \param pixels Array of pixels of the image + /// \param width Width of the image + /// \param height Height of the image + /// \param hotspotX X location of the hotspot + /// \param hotspotY Y location of the hotspot + /// + //////////////////////////////////////////////////////////// + void setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY); + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// diff --git a/src/SFML/Window/Android/WindowImplAndroid.cpp b/src/SFML/Window/Android/WindowImplAndroid.cpp index 27d2f10e4..2f83be8ff 100644 --- a/src/SFML/Window/Android/WindowImplAndroid.cpp +++ b/src/SFML/Window/Android/WindowImplAndroid.cpp @@ -185,6 +185,20 @@ void WindowImplAndroid::setMouseCursorGrabbed(bool grabbed) } +//////////////////////////////////////////////////////////// +void WindowImplAndroid::setMouseCursor(Window::Cursor cursor) +{ + // Not applicable +} + + +//////////////////////////////////////////////////////////// +void WindowImplAndroid::setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY) +{ + // Not applicable +} + + //////////////////////////////////////////////////////////// void WindowImplAndroid::setKeyRepeatEnabled(bool enabled) { diff --git a/src/SFML/Window/Android/WindowImplAndroid.hpp b/src/SFML/Window/Android/WindowImplAndroid.hpp index 88250d414..c201f0388 100644 --- a/src/SFML/Window/Android/WindowImplAndroid.hpp +++ b/src/SFML/Window/Android/WindowImplAndroid.hpp @@ -154,6 +154,26 @@ public: //////////////////////////////////////////////////////////// virtual void setMouseCursorGrabbed(bool grabbed); + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to a native system cursor + /// + /// \param cursor Native system cursor type to display + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(Window::Cursor cursor); + + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to the provided image + /// + /// \param pixels Array of pixels of the image + /// \param width Width of the image + /// \param height Height of the image + /// \param hotspotX X location of the hotspot + /// \param hotspotY Y location of the hotspot + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY); + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// diff --git a/src/SFML/Window/OSX/WindowImplCocoa.hpp b/src/SFML/Window/OSX/WindowImplCocoa.hpp index 8daa8f832..4df291ad6 100644 --- a/src/SFML/Window/OSX/WindowImplCocoa.hpp +++ b/src/SFML/Window/OSX/WindowImplCocoa.hpp @@ -321,6 +321,26 @@ public: //////////////////////////////////////////////////////////// virtual void setMouseCursorGrabbed(bool grabbed); + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to a native system cursor + /// + /// \param cursor Native system cursor type to display + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(Window::Cursor cursor); + + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to the provided image + /// + /// \param pixels Array of pixels of the image + /// \param width Width of the image + /// \param height Height of the image + /// \param hotspotX X location of the hotspot + /// \param hotspotY Y location of the hotspot + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY); + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// diff --git a/src/SFML/Window/OSX/WindowImplCocoa.mm b/src/SFML/Window/OSX/WindowImplCocoa.mm index b294881ad..2e966ff1c 100644 --- a/src/SFML/Window/OSX/WindowImplCocoa.mm +++ b/src/SFML/Window/OSX/WindowImplCocoa.mm @@ -493,6 +493,20 @@ void WindowImplCocoa::setMouseCursorGrabbed(bool grabbed) } +//////////////////////////////////////////////////////////// +void WindowImplCocoa::setMouseCursor(Window::Cursor cursor) +{ + // TODO: Implement OS X cursor setting +} + + +//////////////////////////////////////////////////////////// +void WindowImplCocoa::setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY) +{ + // TODO: Implement OS X cursor setting +} + + //////////////////////////////////////////////////////////// void WindowImplCocoa::setKeyRepeatEnabled(bool enabled) { diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index b16c0e289..fcba14782 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -25,8 +25,8 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// +#include // important to be included first (conflict with None) #include -#include #include #include #include diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 91086e14a..63d6f2673 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -900,6 +900,250 @@ void WindowImplX11::setMouseCursorVisible(bool visible) } +//////////////////////////////////////////////////////////// +void WindowImplX11::setMouseCursor(Window::Cursor cursor) +{ + xcb_cursor_t newCursor = 0; + + xcb_cursor_context_t* cursorContext = NULL; + + if (xcb_cursor_context_new(m_connection, m_screen, &cursorContext) < 0) + { + err() << "Could not create XCB cursor context" << std::endl; + return; + } + + switch(cursor) + { + case Window::Arrow: newCursor = xcb_cursor_load_cursor(cursorContext, "left_ptr"); break; + case Window::ArrowWait: newCursor = xcb_cursor_load_cursor(cursorContext, "left_ptr"); break; + case Window::Wait: newCursor = xcb_cursor_load_cursor(cursorContext, "watch"); break; + case Window::Text: newCursor = xcb_cursor_load_cursor(cursorContext, "xterm"); break; + case Window::Hand: newCursor = xcb_cursor_load_cursor(cursorContext, "hand2"); break; + case Window::SizeHorizontal: newCursor = xcb_cursor_load_cursor(cursorContext, "sb_h_double_arrow"); break; + case Window::SizeVertical: newCursor = xcb_cursor_load_cursor(cursorContext, "sb_v_double_arrow"); break; + case Window::SizeTopLeftBottomRight: newCursor = xcb_cursor_load_cursor(cursorContext, "fleur"); break; + case Window::SizeBottomLeftTopRight: newCursor = xcb_cursor_load_cursor(cursorContext, "fleur"); break; + case Window::SizeAll: newCursor = xcb_cursor_load_cursor(cursorContext, "fleur"); break; + case Window::Cross: newCursor = xcb_cursor_load_cursor(cursorContext, "crosshair"); break; + case Window::Help: newCursor = xcb_cursor_load_cursor(cursorContext, "question_arrow"); break; + case Window::NotAllowed: newCursor = xcb_cursor_load_cursor(cursorContext, "left_ptr"); break; + default: break; + } + + xcb_cursor_context_free(cursorContext); + + if (m_loadedCursor) + xcb_free_cursor(m_connection, m_loadedCursor); + + if (!newCursor) + return; + + m_loadedCursor = newCursor; + + if (!m_cursor) + return; + + ScopedXcbPtr changeAttributesError(xcb_request_check( + m_connection, + xcb_change_window_attributes( + m_connection, + m_window, + XCB_CW_CURSOR, + &m_loadedCursor + ) + )); + + if (changeAttributesError) + { + err() << "Failed to change window attributes" << std::endl; + return; + } + + m_cursor = m_loadedCursor; +} + + +//////////////////////////////////////////////////////////// +void WindowImplX11::setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY) +{ + // Get the picture format from XCB + ScopedXcbPtr pictFormatsreply(xcb_render_query_pict_formats_reply( + m_connection, + xcb_render_query_pict_formats( + m_connection + ), + NULL + )); + + xcb_render_pictformat_t pictureFormat = xcb_render_util_find_standard_format(pictFormatsreply.get(), XCB_PICT_STANDARD_ARGB_32)->id; + + if (!pictureFormat) + { + err() << "Failed to get picture format from XCB" << std::endl; + return; + } + + // X11 wants BGRA pixels: swap red and blue channels + Uint8 cursorPixels[width * height * 4]; + for (std::size_t i = 0; i < width * height; ++i) + { + cursorPixels[i * 4 + 0] = pixels[i * 4 + 2]; + cursorPixels[i * 4 + 1] = pixels[i * 4 + 1]; + cursorPixels[i * 4 + 2] = pixels[i * 4 + 0]; + cursorPixels[i * 4 + 3] = pixels[i * 4 + 3]; + } + + xcb_pixmap_t cursorPixmap = xcb_generate_id(m_connection); + ScopedXcbPtr pixmapError(xcb_request_check( + m_connection, + xcb_create_pixmap( + m_connection, + 32, + cursorPixmap, + m_window, + width, + height + ) + )); + + if (pixmapError) + { + err() << "Failed to create XCB cursor pixmap" << std::endl; + return; + } + + xcb_gcontext_t cursorGC = xcb_generate_id(m_connection); + ScopedXcbPtr gcError(xcb_request_check( + m_connection, + xcb_create_gc( + m_connection, + cursorGC, + cursorPixmap, + 0, + NULL + ) + )); + + if (gcError) + { + err() << "Failed to create XCB graphics context" << std::endl; + xcb_free_pixmap(m_connection, cursorPixmap); + return; + } + + xcb_image_t* cursorImage = xcb_image_create_native( + m_connection, + width, + height, + XCB_IMAGE_FORMAT_Z_PIXMAP, + 32, + NULL, + width * height * 4, + cursorPixels + ); + + if (!cursorImage) + { + err() << "Failed to create XCB cursor image" << std::endl; + xcb_free_gc(m_connection, cursorGC); + xcb_free_pixmap(m_connection, cursorPixmap); + return; + } + + ScopedXcbPtr imagePutError(xcb_request_check( + m_connection, + xcb_image_put( + m_connection, + cursorPixmap, + cursorGC, + cursorImage, + 0, + 0, + 0 + ) + )); + + if (imagePutError) + { + err() << "Failed to put XCB image on the X server" << std::endl; + xcb_image_destroy(cursorImage); + xcb_free_gc(m_connection, cursorGC); + xcb_free_pixmap(m_connection, cursorPixmap); + return; + } + + xcb_render_picture_t cursorPicture = xcb_generate_id(m_connection); + ScopedXcbPtr createPictureError(xcb_request_check( + m_connection, + xcb_render_create_picture( + m_connection, + cursorPicture, + cursorPixmap, + pictureFormat, + 0, + NULL + ) + )); + + if (createPictureError) + { + err() << "Failed to create XCB cursor picture" << std::endl; + xcb_image_destroy(cursorImage); + xcb_free_gc(m_connection, cursorGC); + xcb_free_pixmap(m_connection, cursorPixmap); + return; + } + + xcb_cursor_t newCursor = xcb_generate_id(m_connection); + ScopedXcbPtr createCursorError(xcb_request_check( + m_connection, + xcb_render_create_cursor( + m_connection, + newCursor, + cursorPicture, + hotspotX, + hotspotY + ) + )); + + xcb_render_free_picture(m_connection, cursorPicture); + xcb_image_destroy(cursorImage); + xcb_free_gc(m_connection, cursorGC); + xcb_free_pixmap(m_connection, cursorPixmap); + + if (createCursorError) + { + err() << "Failed to create XCB cursor" << std::endl; + return; + } + + xcb_free_cursor(m_connection, m_loadedCursor); + m_loadedCursor = newCursor; + + if (!m_cursor) + return; + + ScopedXcbPtr changeAttributesError(xcb_request_check( + m_connection, + xcb_change_window_attributes( + m_connection, + m_window, + XCB_CW_CURSOR, + &m_loadedCursor + ) + )); + + if (changeAttributesError) + { + err() << "Failed to change window attributes" << std::endl; + return; + } + + m_cursor = m_loadedCursor; +} + + //////////////////////////////////////////////////////////// void WindowImplX11::setMouseCursorGrabbed(bool grabbed) { @@ -1306,9 +1550,6 @@ void WindowImplX11::initialize() // Raise the window and grab input focus grabFocus(); - // Create the hidden cursor - createHiddenCursor(); - // Flush the commands queue XFlush(m_display); diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index 973a57d38..a732b0bd7 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -154,6 +154,26 @@ public: //////////////////////////////////////////////////////////// virtual void setMouseCursorGrabbed(bool grabbed); + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to a native system cursor + /// + /// \param cursor Native system cursor type to display + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(Window::Cursor cursor); + + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to the provided image + /// + /// \param pixels Array of pixels of the image + /// \param width Width of the image + /// \param height Height of the image + /// \param hotspotX X location of the hotspot + /// \param hotspotY Y location of the hotspot + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY); + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// @@ -233,12 +253,6 @@ private: //////////////////////////////////////////////////////////// void initialize(); - //////////////////////////////////////////////////////////// - /// \brief Create a transparent mouse cursor - /// - //////////////////////////////////////////////////////////// - void createHiddenCursor(); - //////////////////////////////////////////////////////////// /// \brief Cleanup graphical resources attached to the window /// diff --git a/src/SFML/Window/Win32/WindowImplWin32.cpp b/src/SFML/Window/Win32/WindowImplWin32.cpp index f8669b216..68f1ee026 100644 --- a/src/SFML/Window/Win32/WindowImplWin32.cpp +++ b/src/SFML/Window/Win32/WindowImplWin32.cpp @@ -40,6 +40,7 @@ #include #include #include +#include // MinGW lacks the definition of some Win32 constants #ifndef XBUTTON1 @@ -132,6 +133,7 @@ WindowImplWin32::WindowImplWin32(WindowHandle handle) : m_handle (handle), m_callback (0), m_cursor (NULL), +m_loadedCursor (NULL), m_icon (NULL), m_keyRepeatEnabled(true), m_lastSize (0, 0), @@ -164,6 +166,7 @@ WindowImplWin32::WindowImplWin32(VideoMode mode, const String& title, Uint32 sty m_handle (NULL), m_callback (0), m_cursor (NULL), +m_loadedCursor (NULL), m_icon (NULL), m_keyRepeatEnabled(true), m_lastSize (mode.width, mode.height), @@ -238,6 +241,10 @@ m_cursorGrabbed (m_fullscreen) //////////////////////////////////////////////////////////// WindowImplWin32::~WindowImplWin32() { + // Destroy the cursor + if (m_loadedCursor) + DestroyCursor(m_loadedCursor); + // Destroy the custom icon, if any if (m_icon) DestroyIcon(m_icon); @@ -389,8 +396,12 @@ 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 = LoadCursorW(NULL, IDC_ARROW); + m_cursor = m_loadedCursor; else m_cursor = NULL; @@ -406,6 +417,139 @@ void WindowImplWin32::setMouseCursorGrabbed(bool grabbed) } +//////////////////////////////////////////////////////////// +void WindowImplWin32::setMouseCursor(Window::Cursor cursor) +{ + HCURSOR newCursor = NULL; + + switch (cursor) + { + case Window::Arrow: newCursor = LoadCursor(NULL, IDC_ARROW); break; + case Window::ArrowWait: newCursor = LoadCursor(NULL, IDC_APPSTARTING); break; + case Window::Wait: newCursor = LoadCursor(NULL, IDC_WAIT); break; + case Window::Text: newCursor = LoadCursor(NULL, IDC_IBEAM); break; + case Window::Hand: newCursor = LoadCursor(NULL, IDC_HAND); break; + case Window::SizeHorizontal: newCursor = LoadCursor(NULL, IDC_SIZEWE); break; + case Window::SizeVertical: newCursor = LoadCursor(NULL, IDC_SIZENS); break; + case Window::SizeTopLeftBottomRight: newCursor = LoadCursor(NULL, IDC_SIZENWSE); break; + case Window::SizeBottomLeftTopRight: newCursor = LoadCursor(NULL, IDC_SIZENESW); break; + case Window::SizeAll: newCursor = LoadCursor(NULL, IDC_SIZEALL); break; + case Window::Cross: newCursor = LoadCursor(NULL, IDC_CROSS); break; + case Window::Help: newCursor = LoadCursor(NULL, IDC_HELP); break; + case Window::NotAllowed: newCursor = LoadCursor(NULL, IDC_NO); break; + default: return; + } + + // Create a copy of the shared system cursor that we can destroy later + newCursor = CopyCursor(newCursor); + + if (!newCursor) + { + err() << "Could not create copy of a system cursor" << std::endl; + return; + } + + HCURSOR oldCursor = m_loadedCursor; + m_loadedCursor = newCursor; + + if (m_cursor) + { + m_cursor = m_loadedCursor; + SetCursor(m_cursor); + } + + if (oldCursor) + DestroyCursor(oldCursor); +} + + +//////////////////////////////////////////////////////////// +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); +} + + //////////////////////////////////////////////////////////// void WindowImplWin32::setKeyRepeatEnabled(bool enabled) { diff --git a/src/SFML/Window/Win32/WindowImplWin32.hpp b/src/SFML/Window/Win32/WindowImplWin32.hpp index 6c29e0b42..9dfe16719 100644 --- a/src/SFML/Window/Win32/WindowImplWin32.hpp +++ b/src/SFML/Window/Win32/WindowImplWin32.hpp @@ -153,6 +153,26 @@ public: //////////////////////////////////////////////////////////// virtual void setMouseCursorGrabbed(bool grabbed); + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to a native system cursor + /// + /// \param cursor Native system cursor type to display + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(Window::Cursor cursor); + + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to the provided image + /// + /// \param pixels Array of pixels of the image + /// \param width Width of the image + /// \param height Height of the image + /// \param hotspotX X location of the hotspot + /// \param hotspotY Y location of the hotspot + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY); + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// @@ -266,7 +286,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 to display into the window + 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 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 diff --git a/src/SFML/Window/Window.cpp b/src/SFML/Window/Window.cpp index 6618e5bb9..2e7a329cd 100644 --- a/src/SFML/Window/Window.cpp +++ b/src/SFML/Window/Window.cpp @@ -296,6 +296,22 @@ void Window::setMouseCursorGrabbed(bool grabbed) } +//////////////////////////////////////////////////////////// +void Window::setMouseCursor(Cursor cursor) +{ + if (m_impl) + m_impl->setMouseCursor(cursor); +} + + +//////////////////////////////////////////////////////////// +void Window::setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY) +{ + if (m_impl && pixels && width && height) + m_impl->setMouseCursor(pixels, width, height, hotspotX, hotspotY); +} + + //////////////////////////////////////////////////////////// void Window::setKeyRepeatEnabled(bool enabled) { diff --git a/src/SFML/Window/WindowImpl.hpp b/src/SFML/Window/WindowImpl.hpp index 96f4436eb..1ade7f8cd 100644 --- a/src/SFML/Window/WindowImpl.hpp +++ b/src/SFML/Window/WindowImpl.hpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -194,6 +195,26 @@ public: //////////////////////////////////////////////////////////// virtual void setMouseCursorGrabbed(bool grabbed) = 0; + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to a native system cursor + /// + /// \param cursor Native system cursor type to display + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(Window::Cursor cursor) = 0; + + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to the provided image + /// + /// \param pixels Array of pixels of the image + /// \param width Width of the image + /// \param height Height of the image + /// \param hotspotX X location of the hotspot + /// \param hotspotY Y location of the hotspot + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY) = 0; + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// diff --git a/src/SFML/Window/iOS/WindowImplUIKit.hpp b/src/SFML/Window/iOS/WindowImplUIKit.hpp index 51e890a7f..7bc188ac4 100644 --- a/src/SFML/Window/iOS/WindowImplUIKit.hpp +++ b/src/SFML/Window/iOS/WindowImplUIKit.hpp @@ -157,6 +157,26 @@ public: //////////////////////////////////////////////////////////// virtual void setMouseCursorGrabbed(bool grabbed); + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to a native system cursor + /// + /// \param cursor Native system cursor type to display + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(Window::Cursor cursor); + + //////////////////////////////////////////////////////////// + /// \brief Set the displayed cursor to the provided image + /// + /// \param pixels Array of pixels of the image + /// \param width Width of the image + /// \param height Height of the image + /// \param hotspotX X location of the hotspot + /// \param hotspotY Y location of the hotspot + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY); + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// diff --git a/src/SFML/Window/iOS/WindowImplUIKit.mm b/src/SFML/Window/iOS/WindowImplUIKit.mm index 49791ce32..cc0e5b7f0 100644 --- a/src/SFML/Window/iOS/WindowImplUIKit.mm +++ b/src/SFML/Window/iOS/WindowImplUIKit.mm @@ -190,6 +190,20 @@ void WindowImplUIKit::setMouseCursorGrabbed(bool grabbed) } +//////////////////////////////////////////////////////////// +void WindowImplUIKit::setMouseCursor(Window::Cursor cursor) +{ + // Not applicable +} + + +//////////////////////////////////////////////////////////// +void WindowImplUIKit::setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY) +{ + // Not applicable +} + + //////////////////////////////////////////////////////////// void WindowImplUIKit::setKeyRepeatEnabled(bool enabled) {