From f72888fac340724f26d4b487bb6e2803a1c96b9f Mon Sep 17 00:00:00 2001 From: binary1248 Date: Tue, 10 May 2016 02:07:17 +0200 Subject: [PATCH 01/16] Fixed not being able to set the window icon properly on some Unix window managers (#1087) and added support for setting the window icon via ICCCM (_NET_WM_ICON). --- src/SFML/Window/Unix/WindowImplX11.cpp | 199 +++++++++++++++++-------- src/SFML/Window/Unix/WindowImplX11.hpp | 2 + 2 files changed, 141 insertions(+), 60 deletions(-) diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 88176bf7..5fe6eb16 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -372,7 +372,9 @@ m_previousSize (-1, -1), m_useSizeHints (false), m_fullscreen (false), m_cursorGrabbed (false), -m_windowMapped (false) +m_windowMapped (false), +m_iconPixmap (0), +m_iconMaskPixmap (0) { // Open a connection with the X server m_display = OpenDisplay(); @@ -428,7 +430,9 @@ m_previousSize (-1, -1), m_useSizeHints (false), m_fullscreen ((style & Style::Fullscreen) != 0), m_cursorGrabbed (m_fullscreen), -m_windowMapped (false) +m_windowMapped (false), +m_iconPixmap (0), +m_iconMaskPixmap (0) { // Open a connection with the X server m_display = OpenDisplay(); @@ -562,6 +566,42 @@ WindowImplX11::~WindowImplX11() // Cleanup graphical resources cleanup(); + // Destroy icon pixmap + if (m_iconPixmap) + { + ScopedXcbPtr freePixmapError(xcb_request_check( + m_connection, + xcb_free_pixmap_checked( + m_connection, + m_iconPixmap + ) + )); + + if (freePixmapError) + { + err() << "Failed to free icon pixmap: "; + err() << "Error code " << static_cast(freePixmapError->error_code) << std::endl; + } + } + + // Destroy icon mask pixmap + if (m_iconMaskPixmap) + { + ScopedXcbPtr freePixmapMaskError(xcb_request_check( + m_connection, + xcb_free_pixmap_checked( + m_connection, + m_iconMaskPixmap + ) + )); + + if (freePixmapMaskError) + { + err() << "Failed to free icon mask pixmap: "; + err() << "Error code " << static_cast(freePixmapMaskError->error_code) << std::endl; + } + } + // Destroy the cursor if (m_hiddenCursor) xcb_free_cursor(m_connection, m_hiddenCursor); @@ -756,25 +796,67 @@ void WindowImplX11::setTitle(const String& title) //////////////////////////////////////////////////////////// void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels) { - // X11 wants BGRA pixels: swap red and blue channels - Uint8 iconPixels[width * height * 4]; + // X11 and ICCCM want BGRA pixels: swap red and blue channels + // ICCCM also wants the first 2 unsigned 32-bit values to be width and height + Uint8 iconPixels[8 + width * height * 4]; for (std::size_t i = 0; i < width * height; ++i) { - iconPixels[i * 4 + 0] = pixels[i * 4 + 2]; - iconPixels[i * 4 + 1] = pixels[i * 4 + 1]; - iconPixels[i * 4 + 2] = pixels[i * 4 + 0]; - iconPixels[i * 4 + 3] = pixels[i * 4 + 3]; + iconPixels[8 + i * 4 + 0] = pixels[i * 4 + 2]; + iconPixels[8 + i * 4 + 1] = pixels[i * 4 + 1]; + iconPixels[8 + i * 4 + 2] = pixels[i * 4 + 0]; + iconPixels[8 + i * 4 + 3] = pixels[i * 4 + 3]; + } + + reinterpret_cast(iconPixels)[0] = width; + reinterpret_cast(iconPixels)[1] = height; + + if (m_iconPixmap) + { + ScopedXcbPtr freePixmapError(xcb_request_check( + m_connection, + xcb_free_pixmap_checked( + m_connection, + m_iconPixmap + ) + )); + + if (freePixmapError) + { + err() << "Failed to free icon pixmap: "; + err() << "Error code " << static_cast(freePixmapError->error_code) << std::endl; + } + + m_iconPixmap = 0; + } + + if (m_iconMaskPixmap) + { + ScopedXcbPtr freePixmapMaskError(xcb_request_check( + m_connection, + xcb_free_pixmap_checked( + m_connection, + m_iconMaskPixmap + ) + )); + + if (freePixmapMaskError) + { + err() << "Failed to free icon mask pixmap: "; + err() << "Error code " << static_cast(freePixmapMaskError->error_code) << std::endl; + } + + m_iconMaskPixmap = 0; } // Create the icon pixmap - xcb_pixmap_t iconPixmap = xcb_generate_id(m_connection); + m_iconPixmap = xcb_generate_id(m_connection); ScopedXcbPtr createPixmapError(xcb_request_check( m_connection, xcb_create_pixmap_checked( m_connection, m_screen->root_depth, - iconPixmap, + m_iconPixmap, m_screen->root, width, height @@ -788,6 +870,42 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 return; } + // Create the mask pixmap (must have 1 bit depth) + std::size_t pitch = (width + 7) / 8; + std::vector maskPixels(pitch * height, 0); + for (std::size_t j = 0; j < height; ++j) + { + for (std::size_t i = 0; i < pitch; ++i) + { + for (std::size_t k = 0; k < 8; ++k) + { + if (i * 8 + k < width) + { + Uint8 opacity = (pixels[(i * 8 + k + j * width) * 4 + 3] > 0) ? 1 : 0; + maskPixels[i + j * pitch] |= (opacity << k); + } + } + } + } + + m_iconMaskPixmap = xcb_create_pixmap_from_bitmap_data( + m_connection, + m_window, + reinterpret_cast(&maskPixels[0]), + width, + height, + 1, + 0, + 1, + NULL + ); + + if (!m_iconMaskPixmap) + { + err() << "Failed to set the window's icon (create_pixmap_from_bitmap_data)" << std::endl; + return; + } + xcb_gcontext_t iconGC = xcb_generate_id(m_connection); ScopedXcbPtr createGcError(xcb_request_check( @@ -795,7 +913,7 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 xcb_create_gc( m_connection, iconGC, - iconPixmap, + m_iconPixmap, 0, NULL ) @@ -813,7 +931,7 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 xcb_put_image_checked( m_connection, XCB_IMAGE_FORMAT_Z_PIXMAP, - iconPixmap, + m_iconPixmap, iconGC, width, height, @@ -821,8 +939,8 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 0, 0, m_screen->root_depth, - sizeof(iconPixels), - iconPixels + width * height * 4, + iconPixels + 8 ) )); @@ -847,60 +965,21 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 return; } - // Create the mask pixmap (must have 1 bit depth) - std::size_t pitch = (width + 7) / 8; - static std::vector maskPixels(pitch * height, 0); - for (std::size_t j = 0; j < height; ++j) - { - for (std::size_t i = 0; i < pitch; ++i) - { - for (std::size_t k = 0; k < 8; ++k) - { - if (i * 8 + k < width) - { - Uint8 opacity = (pixels[(i * 8 + k + j * width) * 4 + 3] > 0) ? 1 : 0; - maskPixels[i + j * pitch] |= (opacity << k); - } - } - } - } - - xcb_pixmap_t maskPixmap = xcb_create_pixmap_from_bitmap_data( - m_connection, - m_window, - reinterpret_cast(&maskPixels[0]), - width, - height, - 1, - 0, - 1, - NULL - ); - // Send our new icon to the window through the WMHints WMHints hints; std::memset(&hints, 0, sizeof(hints)); hints.flags |= ((1 << 2) | (1 << 5)); - hints.icon_pixmap = iconPixmap; - hints.icon_mask = maskPixmap; + hints.icon_pixmap = m_iconPixmap; + hints.icon_mask = m_iconMaskPixmap; setWMHints(hints); + xcb_atom_t netWmIcon = getAtom("_NET_WM_ICON"); + + if (!changeWindowProperty(netWmIcon, XCB_ATOM_CARDINAL, 32, 2 + width * height, iconPixels)) + err() << "Failed to set the window's icon (changeWindowProperty)" << std::endl; + xcb_flush(m_connection); - - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - iconPixmap - ) - )); - - if (freePixmapError) - { - err() << "Failed to free icon pixmap: "; - err() << "Error code " << static_cast(freePixmapError->error_code) << std::endl; - } } diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index ea6f7412..3c31f4e7 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -329,6 +329,8 @@ private: bool m_fullscreen; ///< Is the window in fullscreen? bool m_cursorGrabbed; ///< Is the mouse cursor trapped? bool m_windowMapped; ///< Has the window been mapped by the window manager? + xcb_pixmap_t m_iconPixmap; ///< The current icon pixmap if in use + xcb_pixmap_t m_iconMaskPixmap; ///< The current icon mask pixmap if in use }; } // namespace priv From cb097ff8d84d5aa2054e2a4410cbb96f7c04c7cf Mon Sep 17 00:00:00 2001 From: Manu343726 Date: Wed, 27 Jul 2016 12:30:59 +0200 Subject: [PATCH 02/16] Correctly add XCB components if no components are requested This commit fixes the FindXCB.cmake module for the case no components are requested. The previous version assigned `XCB_FIND_COMPONENTS` list to an empty variable name. I was lucky enough to catch the bug in a corner case where both `XCB_COMPONENTS` and `XCB_FIND_COMPONENTS` were empty and `set()` command failed, but note this awesome CMake language supports more annoying corner cases like `XCB_COMPONENTS` empty and `XCB_FIND_COMPONENTS` with two elements, which results in the following `set()` invocation: ``` cmake set(${XCB_FIND_COMPONENTS[0]} ${XCB_FIND_COMPONENTS[1]}) ``` So always beware of CMake secret charms... --- cmake/Modules/FindXCB.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/FindXCB.cmake b/cmake/Modules/FindXCB.cmake index d6914610..4915f723 100644 --- a/cmake/Modules/FindXCB.cmake +++ b/cmake/Modules/FindXCB.cmake @@ -68,7 +68,7 @@ IF(NOT WIN32) endif() ELSE() # Add component name to the component list - set(${XCB_COMPONENTS} ${XCB_FIND_COMPONENTS}) + set(XCB_COMPONENTS ${XCB_FIND_COMPONENTS}) ENDIF() # Loop through requested xcb components (does not contain xlib_xcb) From e2c4bca779e2362060fbe24d87cc85d81ba358b9 Mon Sep 17 00:00:00 2001 From: Dka8 Date: Mon, 1 Aug 2016 18:59:39 +0300 Subject: [PATCH 03/16] UdpSocket.hpp typo in comment for void unbind() Function void unbind(); The suggested text by @binary1248 Added "If the socket is not bound to a port, this function has no effect." --- include/SFML/Network/UdpSocket.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/SFML/Network/UdpSocket.hpp b/include/SFML/Network/UdpSocket.hpp index 20cb7c6f..86fd1f6b 100644 --- a/include/SFML/Network/UdpSocket.hpp +++ b/include/SFML/Network/UdpSocket.hpp @@ -95,9 +95,11 @@ public: //////////////////////////////////////////////////////////// /// \brief Unbind the socket from the local port to which it is bound /// - /// The port that the socket was previously using is immediately - /// available after this function is called. If the - /// socket is not bound to a port, this function has no effect. + /// The port that the socket was previously bound to is immediately + /// made available to the operating system after this function is called. + /// This means that a subsequent call to bind() will be able to re-bind + /// the port if no other process has done so in the mean time. + /// If the socket is not bound to a port, this function has no effect. /// /// \see bind /// From fea5d472217dd125432079de695c3f2b6ce46617 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Thu, 11 Aug 2016 21:46:26 +0100 Subject: [PATCH 04/16] Define SFML_OS_FREEBSD when compiling for kFreeBSD --- cmake/Config.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Config.cmake b/cmake/Config.cmake index 6506ac02..02e45ed0 100644 --- a/cmake/Config.cmake +++ b/cmake/Config.cmake @@ -27,7 +27,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") # don't use the OpenGL ES implementation on Linux set(OPENGL_ES 0) endif() -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") +elseif(CMAKE_SYSTEM_NAME MATCHES "^k?FreeBSD$") set(SFML_OS_FREEBSD 1) # don't use the OpenGL ES implementation on FreeBSD set(OPENGL_ES 0) From d9056ad5b3d1a13280df8d45c2785e45fdd0df85 Mon Sep 17 00:00:00 2001 From: Hapax Date: Sat, 13 Aug 2016 12:35:08 +0100 Subject: [PATCH 05/16] Changed uniform error message Changed the error message for using uniforms to use the word uniform instead of the word parameter since parameter's deprecation. A minor text output alteration to keep consistent with the new interface. --- src/SFML/Graphics/Shader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SFML/Graphics/Shader.cpp b/src/SFML/Graphics/Shader.cpp index 8010ff28..d8258aee 100644 --- a/src/SFML/Graphics/Shader.cpp +++ b/src/SFML/Graphics/Shader.cpp @@ -1022,7 +1022,7 @@ int Shader::getUniformLocation(const std::string& name) m_uniforms.insert(std::make_pair(name, location)); if (location == -1) - err() << "Parameter \"" << name << "\" not found in shader" << std::endl; + err() << "Uniform \"" << name << "\" not found in shader" << std::endl; return location; } From 42146ea0704e4fec994431cf4cf53983e806ced1 Mon Sep 17 00:00:00 2001 From: binary1248 Date: Sat, 20 Aug 2016 14:20:15 +0200 Subject: [PATCH 06/16] Fixed leak of XVisualInfo objects during GlxContext creation. --- src/SFML/Window/Unix/GlxContext.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index 7251db2b..4d4d8312 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -482,8 +482,11 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned if (visual->visualid == visualInfo.visualid) { config = &configs[i]; + XFree(visual); break; } + + XFree(visual); } if (config) @@ -640,8 +643,11 @@ void GlxContext::createContext(GlxContext* shared) if (visual->visualid == visualInfo->visualid) { config = &configs[i]; + XFree(visual); break; } + + XFree(visual); } if (!config) From 946dbce6c471955fbd8291c11a4d9bc44fc7cd5f Mon Sep 17 00:00:00 2001 From: binary1248 Date: Sun, 21 Aug 2016 14:01:24 +0200 Subject: [PATCH 07/16] Fixed possible hang when setting visibility if external window sources e.g. Qt don't forward visibility notify events to us. --- src/SFML/Window/Unix/WindowImplX11.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 5fe6eb16..9e7fca76 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -1003,7 +1003,7 @@ void WindowImplX11::setVisible(bool visible) // Before continuing, make sure the WM has // internally marked the window as viewable - while (!m_windowMapped) + while (!m_windowMapped && !m_isExternal) processEvents(); } else @@ -1023,7 +1023,7 @@ void WindowImplX11::setVisible(bool visible) // Before continuing, make sure the WM has // internally marked the window as unviewable - while (m_windowMapped) + while (m_windowMapped && !m_isExternal) processEvents(); } } From 1424fa4dc3b44c8080520641e9137c360e217b38 Mon Sep 17 00:00:00 2001 From: Hapaxia Date: Tue, 16 Aug 2016 15:23:16 +0100 Subject: [PATCH 08/16] update Window documentation removed part of the sentence that stated that cursor grabbing is different for fullscreen windows as this is not the case. --- include/SFML/Window/Window.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/SFML/Window/Window.hpp b/include/SFML/Window/Window.hpp index 08392876..83cb879d 100644 --- a/include/SFML/Window/Window.hpp +++ b/include/SFML/Window/Window.hpp @@ -354,9 +354,7 @@ public: /// If set, grabs the mouse cursor inside this window's client /// area so it may no longer be moved outside its bounds. /// Note that grabbing is only active while the window has - /// focus and calling this function for fullscreen windows - /// won't have any effect (fullscreen windows always grab the - /// cursor). + /// focus. /// /// \param grabbed True to enable, false to disable /// From eacdafe9d772e6074e091c89ffd9cdb8d5b9000a Mon Sep 17 00:00:00 2001 From: louis-langholtz Date: Tue, 26 Jan 2016 14:11:52 -0700 Subject: [PATCH 09/16] Fixes bug #1049: iOS orientation change handling re-scales window size by backingScaleFactor. --- src/SFML/Window/iOS/SFAppDelegate.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SFML/Window/iOS/SFAppDelegate.mm b/src/SFML/Window/iOS/SFAppDelegate.mm index 3284b9ac..09fa42e0 100644 --- a/src/SFML/Window/iOS/SFAppDelegate.mm +++ b/src/SFML/Window/iOS/SFAppDelegate.mm @@ -214,8 +214,8 @@ namespace // Send a Resized event to the current window sf::Event event; event.type = sf::Event::Resized; - event.size.width = size.x * backingScaleFactor; - event.size.height = size.y * backingScaleFactor; + event.size.width = size.x; + event.size.height = size.y; sfWindow->forwardEvent(event); } } From 555d0c484bd8523759c2a116d195a86b9a7ad971 Mon Sep 17 00:00:00 2001 From: binary1248 Date: Sun, 14 Aug 2016 02:52:49 +0200 Subject: [PATCH 10/16] Converted Unix Window implementation from XCB back to Xlib. --- cmake/Modules/FindSFML.cmake | 9 +- cmake/Modules/FindXCB.cmake | 97 -- examples/X11/X11.cpp | 119 +- src/SFML/Window/CMakeLists.txt | 16 +- src/SFML/Window/Unix/Display.cpp | 82 +- src/SFML/Window/Unix/Display.hpp | 56 +- src/SFML/Window/Unix/GlxContext.cpp | 38 +- src/SFML/Window/Unix/GlxContext.hpp | 3 +- src/SFML/Window/Unix/InputImpl.cpp | 190 +-- src/SFML/Window/Unix/ScopedXcbPtr.hpp | 102 -- src/SFML/Window/Unix/ScopedXcbPtr.inl | 72 -- src/SFML/Window/Unix/VideoModeImpl.cpp | 272 ++--- src/SFML/Window/Unix/WindowImplX11.cpp | 1535 +++++++++--------------- src/SFML/Window/Unix/WindowImplX11.hpp | 100 +- 14 files changed, 831 insertions(+), 1860 deletions(-) delete mode 100644 cmake/Modules/FindXCB.cmake delete mode 100644 src/SFML/Window/Unix/ScopedXcbPtr.hpp delete mode 100644 src/SFML/Window/Unix/ScopedXcbPtr.inl diff --git a/cmake/Modules/FindSFML.cmake b/cmake/Modules/FindSFML.cmake index fdea1eb2..fe84c961 100644 --- a/cmake/Modules/FindSFML.cmake +++ b/cmake/Modules/FindSFML.cmake @@ -285,10 +285,7 @@ if(SFML_STATIC_LIBRARIES) # find libraries if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD) find_sfml_dependency(X11_LIBRARY "X11" X11) - find_sfml_dependency(LIBXCB_LIBRARIES "XCB" xcb libxcb) - find_sfml_dependency(X11_XCB_LIBRARY "X11-xcb" X11-xcb libX11-xcb) - find_sfml_dependency(XCB_RANDR_LIBRARY "xcb-randr" xcb-randr libxcb-randr) - find_sfml_dependency(XCB_IMAGE_LIBRARY "xcb-image" xcb-image libxcb-image) + find_sfml_dependency(XRANDR_LIBRARY "Xrandr" Xrandr) endif() if(FIND_SFML_OS_LINUX) @@ -299,9 +296,9 @@ if(SFML_STATIC_LIBRARIES) if(FIND_SFML_OS_WINDOWS) set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "opengl32" "winmm" "gdi32") elseif(FIND_SFML_OS_LINUX) - set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${LIBXCB_LIBRARIES} ${X11_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} ${XCB_IMAGE_LIBRARY} ${UDEV_LIBRARIES}) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${XRANDR_LIBRARY} ${UDEV_LIBRARIES}) elseif(FIND_SFML_OS_FREEBSD) - set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${LIBXCB_LIBRARIES} ${X11_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} ${XCB_IMAGE_LIBRARY} "usbhid") + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${XRANDR_LIBRARY} "usbhid") elseif(FIND_SFML_OS_MACOSX) set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "-framework OpenGL -framework Foundation -framework AppKit -framework IOKit -framework Carbon") endif() diff --git a/cmake/Modules/FindXCB.cmake b/cmake/Modules/FindXCB.cmake deleted file mode 100644 index 4915f723..00000000 --- a/cmake/Modules/FindXCB.cmake +++ /dev/null @@ -1,97 +0,0 @@ -# Try to find libxcb -# -# -# Once done this will define: -# LIBXCB_FOUND - True if xcb was found -# LIBXCB_INCLUDE_DIRS - Directories containing the headers -# LIBXCB_LIBRARIES - List of libraries to link to -# -# Also for each requested component: -# LIBXCB_${UPPER_COMPONENT_NAME}_FOUND -# LIBXCB_${UPPER_COMPONENT_NAME}_INCLUDE_DIRS -# LIBXCB_${UPPER_COMPONENT_NAME}_LIBRARIES - -include(FindPackageHandleStandardArgs) - -IF(NOT WIN32) - IF(LIBXCB_LIBRARIES AND LIBXCB_INCLUDE_DIR) - set(XCB_FIND_QUIETLY TRUE) - ENDIF() - - # Find xcb - FIND_PATH(LIBXCB_INCLUDE_DIR xcb/xcb.h) - FIND_LIBRARY(LIBXCB_LIBRARY NAMES xcb libxcb) - - # Add xcb info to LIBXCB_LIBRARIES and LIBXCB_INCLUDE_DIRS - SET(LIBXCB_LIBRARIES ${LIBXCB_LIBRARY}) - SET(LIBXCB_INCLUDE_DIRS ${LIBXCB_INCLUDE_DIR}) - - find_package_handle_standard_args(LIBXCB DEFAULT_MSG - LIBXCB_LIBRARY LIBXCB_INCLUDE_DIR) - - mark_as_advanced(LIBXCB_LIBRARY LIBXCB_INCLUDE_DIR) - - # Check whether we should search for XLIB_XCB - set(FIND_XLIB_XCB FALSE) - FOREACH(XCB_COMPONENT ${XCB_FIND_COMPONENTS}) - # Generate upper string of the component name - string(TOUPPER ${XCB_COMPONENT} XCB_COMPONENT_UPPER) - - IF(${XCB_COMPONENT_UPPER} MATCHES "XLIB_XCB") - set(FIND_XLIB_XCB TRUE) - ELSE() - # XCB_COMPONENTS is generated to be a copy of XCB_FIND_COMPONENTS - # without XLIB_XCB (for later component search) - set(XCB_COMPONENTS ${XCB_COMPONENTS} ${XCB_COMPONENT}) - ENDIF() - ENDFOREACH() - - # Find XLIB_XCB if requested - IF(FIND_XLIB_XCB) - FIND_PATH(XLIB_XCB_INCLUDE_DIR X11/Xlib-xcb.h) - FIND_LIBRARY(XLIB_XCB_LIBRARY NAMES X11-xcb libX11-xcb) - - SET(XLIB_XCB_LIBRARIES ${XLIB_XCB_LIBRARY}) - SET(XLIB_XCB_INCLUDE_DIRS ${XLIB_XCB_INCLUDE_DIR}) - - find_package_handle_standard_args(XLIB_XCB DEFAULT_MSG - XLIB_XCB_LIBRARY LIBXCB_INCLUDE_DIR) - - mark_as_advanced(XLIB_XCB_LIBRARY XLIB_XCB_INCLUDE_DIR) - - # Add xlib_xcb info to LIBXCB_LIBRARIES and LIBXCB_INCLUDE_DIRS - set(LIBXCB_LIBRARIES ${LIBXCB_LIBRARIES} ${XLIB_XCB_LIBRARIES}) - set(LIBXCB_INCLUDE_DIRS ${LIBXCB_INCLUDE_DIRS} ${XLIB_XCB_INCLUDE_DIR}) - - if(NOT XLIB_XCB_FOUND) - message(FATAL_ERROR "XlibXcb library not found") - endif() - ELSE() - # Add component name to the component list - set(XCB_COMPONENTS ${XCB_FIND_COMPONENTS}) - ENDIF() - - # Loop through requested xcb components (does not contain xlib_xcb) - FOREACH(XCB_COMPONENT ${XCB_COMPONENTS}) - # Generate lower and upper string of the component name - string(TOLOWER ${XCB_COMPONENT} XCB_COMPONENT_LOWER) - string(TOUPPER ${XCB_COMPONENT} XCB_COMPONENT_UPPER) - - # Find the specific component - FIND_LIBRARY(LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY - NAMES libxcb-${XCB_COMPONENT_LOWER} xcb-${XCB_COMPONENT_LOWER}) - - find_package_handle_standard_args(LIBXCB_${XCB_COMPONENT_UPPER} DEFAULT_MSG - LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY LIBXCB_INCLUDE_DIR) - - mark_as_advanced(LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY) - - # Append the component's library path to LIBXCB_LIBRARIES - set(LIBXCB_LIBRARIES ${LIBXCB_LIBRARIES} ${LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY}) - - if(NOT LIBXCB_${XCB_COMPONENT_UPPER}_FOUND) - message(FATAL_ERROR "xcb-${XCB_COMPONENT_LOWER} not found") - endif() - ENDFOREACH() - -endif() diff --git a/examples/X11/X11.cpp b/examples/X11/X11.cpp index 2c2419b7..746bf075 100644 --- a/examples/X11/X11.cpp +++ b/examples/X11/X11.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -133,77 +133,46 @@ int main() if (!display) return EXIT_FAILURE; - // Get the XCB connection for the opened display. - xcb_connection_t* xcbConnection = XGetXCBConnection(display); + // Get the default screen + int screen = DefaultScreen(display); - if (!xcbConnection) - { - sf::err() << "Failed to get the XCB connection for opened display." << std::endl; + // Let's create the main window + XSetWindowAttributes attributes; + attributes.background_pixel = BlackPixel(display, screen); + attributes.event_mask = KeyPressMask; + Window window = XCreateWindow(display, RootWindow(display, screen), + 0, 0, 650, 330, 0, + DefaultDepth(display, screen), + InputOutput, + DefaultVisual(display, screen), + CWBackPixel | CWEventMask, &attributes); + if (!window) return EXIT_FAILURE; - } - // Get XCB screen. - const xcb_setup_t* xcbSetup = xcb_get_setup(xcbConnection); - xcb_screen_iterator_t xcbScreenIter = xcb_setup_roots_iterator(xcbSetup); - xcb_screen_t* screen = xcbScreenIter.data; + // Set the window's name + XStoreName(display, window , "SFML Window"); - if (!screen) - { - sf::err() << "Failed to get the XCB screen." << std::endl; - return EXIT_FAILURE; - } + // Let's create the windows which will serve as containers for our SFML views + Window view1 = XCreateWindow(display, window, + 10, 10, 310, 310, 0, + DefaultDepth(display, screen), + InputOutput, + DefaultVisual(display, screen), + 0, NULL); + Window view2 = XCreateWindow(display, window, + 330, 10, 310, 310, 0, + DefaultDepth(display, screen), + InputOutput, + DefaultVisual(display, screen), + 0, NULL); - // Generate the XCB window IDs. - xcb_window_t rootWindowId = xcb_generate_id(xcbConnection); - xcb_window_t view1WindowId = xcb_generate_id(xcbConnection); - xcb_window_t view2WindowId = xcb_generate_id(xcbConnection); - - // Create the root window with a black background. - uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; - uint32_t attributes[2] = {screen->black_pixel, XCB_EVENT_MASK_KEY_PRESS}; - - xcb_create_window(xcbConnection, - XCB_COPY_FROM_PARENT, - rootWindowId, - screen->root, - 0, 0, 650, 330, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - screen->root_visual, - mask, attributes); - - // Create windows for the SFML views. - xcb_create_window(xcbConnection, - XCB_COPY_FROM_PARENT, - view1WindowId, - rootWindowId, - 10, 10, 310, 310, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - screen->root_visual, - mask, attributes); - - xcb_create_window(xcbConnection, - XCB_COPY_FROM_PARENT, - view2WindowId, - rootWindowId, - 330, 10, 310, 310, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - screen->root_visual, - mask, attributes); - - // Map windows to screen. - xcb_map_window(xcbConnection, rootWindowId); - xcb_map_window(xcbConnection, view1WindowId); - xcb_map_window(xcbConnection, view2WindowId); - - // Flush commands. - xcb_flush(xcbConnection); + // Show our windows + XMapWindow(display, window); + XFlush(display); // Create our SFML views - sf::Window sfmlView1(view1WindowId); - sf::Window sfmlView2(view2WindowId); + sf::Window sfmlView1(view1); + sf::Window sfmlView2(view2); // Create a clock for measuring elapsed time sf::Clock clock; @@ -214,13 +183,22 @@ int main() // Start the event loop bool running = true; - xcb_generic_event_t* event = NULL; - while (running) { - while ((event = xcb_poll_for_event(xcbConnection))) + while (XPending(display)) { - running = false; + // Get the next pending event + XEvent event; + XNextEvent(display, &event); + + // Process it + switch (event.type) + { + // Any key is pressed: quit + case KeyPress: + running = false; + break; + } } // Draw something into our views @@ -232,5 +210,8 @@ int main() sfmlView2.display(); } + // Close the display + XCloseDisplay(display); + return EXIT_SUCCESS; } diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index 231dee8f..a887766e 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -75,8 +75,6 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD) ${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/InputImpl.cpp ${SRCROOT}/Unix/InputImpl.hpp - ${SRCROOT}/Unix/ScopedXcbPtr.hpp - ${SRCROOT}/Unix/ScopedXcbPtr.inl ${SRCROOT}/Unix/SensorImpl.cpp ${SRCROOT}/Unix/SensorImpl.hpp ${SRCROOT}/Unix/VideoModeImpl.cpp @@ -200,18 +198,14 @@ if(SFML_OS_LINUX OR SFML_OS_FREEBSD) if(NOT X11_FOUND) message(FATAL_ERROR "X11 library not found") endif() + if(NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "Xrandr library not found") + endif() include_directories(${X11_INCLUDE_DIR}) endif() if(NOT SFML_OPENGL_ES) find_package(OpenGL REQUIRED) include_directories(${OPENGL_INCLUDE_DIR}) - if(SFML_OS_LINUX OR SFML_OS_FREEBSD) - find_package(XCB COMPONENTS xlib_xcb image randr REQUIRED) - if(NOT LIBXCB_FOUND) - message(FATAL_ERROR "Xcb library not found") - endif() - include_directories(${LIBXCB_INCLUDE_DIRS}) - endif() endif() if(SFML_OPENGL_ES AND SFML_OS_LINUX) find_package(EGL REQUIRED) @@ -231,9 +225,9 @@ endif() if(SFML_OS_WINDOWS) list(APPEND WINDOW_EXT_LIBS winmm gdi32) elseif(SFML_OS_LINUX) - list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) + list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} ${UDEV_LIBRARIES}) elseif(SFML_OS_FREEBSD) - list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${LIBXCB_LIBRARIES} usbhid) + list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} usbhid) elseif(SFML_OS_MACOSX) list(APPEND WINDOW_EXT_LIBS "-framework Foundation -framework AppKit -framework IOKit -framework Carbon") elseif(SFML_OS_IOS) diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp index a078b975..fce86015 100644 --- a/src/SFML/Window/Unix/Display.cpp +++ b/src/SFML/Window/Unix/Display.cpp @@ -27,9 +27,9 @@ //////////////////////////////////////////////////////////// #include #include -#include #include #include +#include #include @@ -39,7 +39,7 @@ namespace Display* sharedDisplay = NULL; unsigned int referenceCount = 0; - typedef std::map AtomMap; + typedef std::map AtomMap; AtomMap atoms; } @@ -68,13 +68,6 @@ Display* OpenDisplay() } -//////////////////////////////////////////////////////////// -xcb_connection_t* OpenConnection() -{ - return XGetXCBConnection(OpenDisplay()); -} - - //////////////////////////////////////////////////////////// void CloseDisplay(Display* display) { @@ -87,81 +80,22 @@ void CloseDisplay(Display* display) //////////////////////////////////////////////////////////// -void CloseConnection(xcb_connection_t* connection) -{ - assert(connection == XGetXCBConnection(sharedDisplay)); - return CloseDisplay(sharedDisplay); -} - - -//////////////////////////////////////////////////////////// -xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr) -{ - xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); - - for (; iter.rem; --screen_nbr, xcb_screen_next (&iter)) - { - if (screen_nbr == 0) - return iter.data; - } - - return NULL; -} - - -//////////////////////////////////////////////////////////// -xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection) -{ - assert(connection == XGetXCBConnection(sharedDisplay)); - return XCBScreenOfDisplay(connection, XDefaultScreen(sharedDisplay)); -} - - -//////////////////////////////////////////////////////////// -xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection) -{ - assert(connection == XGetXCBConnection(sharedDisplay)); - xcb_screen_t* screen = XCBScreenOfDisplay(connection, XDefaultScreen(sharedDisplay)); - if (screen) - return screen->root; - return 0; -} - - -//////////////////////////////////////////////////////////// -xcb_atom_t getAtom(const std::string& name, bool onlyIfExists) +Atom getAtom(const std::string& name, bool onlyIfExists) { AtomMap::const_iterator iter = atoms.find(name); if (iter != atoms.end()) return iter->second; - ScopedXcbPtr error(NULL); + Display* display = OpenDisplay(); - xcb_connection_t* connection = OpenConnection(); + Atom atom = XInternAtom(display, name.c_str(), onlyIfExists ? True : False); - ScopedXcbPtr reply(xcb_intern_atom_reply( - connection, - xcb_intern_atom( - connection, - onlyIfExists, - name.size(), - name.c_str() - ), - &error - )); + CloseDisplay(display); - CloseConnection(connection); + atoms[name] = atom; - if (error || !reply) - { - err() << "Failed to get " << name << " atom." << std::endl; - return XCB_ATOM_NONE; - } - - atoms[name] = reply->atom; - - return reply->atom; + return atom; } } // namespace priv diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp index 2743678c..f0eb3020 100644 --- a/src/SFML/Window/Unix/Display.hpp +++ b/src/SFML/Window/Unix/Display.hpp @@ -28,7 +28,7 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include +#include #include @@ -47,17 +47,6 @@ namespace priv //////////////////////////////////////////////////////////// Display* OpenDisplay(); -//////////////////////////////////////////////////////////// -/// \brief Get the xcb connection of the shared Display -/// -/// This function increments the reference count of the display, -/// it must be matched with a call to CloseConnection. -/// -/// \return Pointer to the shared connection -/// -//////////////////////////////////////////////////////////// -xcb_connection_t* OpenConnection(); - //////////////////////////////////////////////////////////// /// \brief Release a reference to the shared display /// @@ -66,55 +55,16 @@ xcb_connection_t* OpenConnection(); //////////////////////////////////////////////////////////// void CloseDisplay(Display* display); -//////////////////////////////////////////////////////////// -/// \brief Release a reference to the shared display -/// -/// \param connection Connection of display to release -/// -//////////////////////////////////////////////////////////// -void CloseConnection(xcb_connection_t* connection); - -//////////////////////////////////////////////////////////// -/// \brief Get screen of a display by index (equivalent to XScreenOfDisplay) -/// -/// \param connection Connection of display -/// \param screen_nbr The index of the screen -/// -/// \return Pointer to the screen -/// -//////////////////////////////////////////////////////////// -xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr); - -//////////////////////////////////////////////////////////// -/// \brief Get default screen of a display (equivalent to XDefaultScreen) -/// -/// \param connection Connection of display -/// -/// \return Pointer to the default screen of the display -/// -//////////////////////////////////////////////////////////// -xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection); - -//////////////////////////////////////////////////////////// -/// \brief Get default root window of a display (equivalent to XDefaultRootWindow) -/// -/// \param connection Connection of display -/// -/// \return Root window of the display -/// -//////////////////////////////////////////////////////////// -xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection); - //////////////////////////////////////////////////////////// /// \brief Get the atom with the specified name /// /// \param name Name of the atom /// \param onlyIfExists Don't try to create the atom if it doesn't already exist /// -/// \return Atom if it exists or XCB_ATOM_NONE (0) if it doesn't +/// \return Atom if it exists or None (0) if it doesn't /// //////////////////////////////////////////////////////////// -xcb_atom_t getAtom(const std::string& name, bool onlyIfExists = false); +Atom getAtom(const std::string& name, bool onlyIfExists = false); } // namespace priv diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index 4d4d8312..8b4711d4 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -194,8 +194,8 @@ GlxContext::~GlxContext() // Destroy the window if we own it if (m_window && m_ownsWindow) { - xcb_destroy_window(m_connection, m_window); - xcb_flush(m_connection); + XDestroyWindow(m_display, m_window); + XFlush(m_display); } // Close the connection with the X server @@ -444,7 +444,6 @@ void GlxContext::updateSettingsFromWindow() void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel) { m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); // Choose the visual according to the context settings XVisualInfo visualInfo = selectBestVisual(m_display, bitsPerPixel, m_settings); @@ -513,28 +512,22 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned } // If pbuffers are not available we use a hidden window as the off-screen surface to draw to - xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display)); + int screen = DefaultScreen(m_display); // Define the window attributes - xcb_colormap_t colormap = xcb_generate_id(m_connection); - xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, screen->root, visualInfo.visualid); - const uint32_t value_list[] = {colormap}; + XSetWindowAttributes attributes; + attributes.colormap = XCreateColormap(m_display, RootWindow(m_display, screen), visualInfo.visual, AllocNone); - // Create a dummy window (disabled and hidden) - m_window = xcb_generate_id(m_connection); - xcb_create_window( - m_connection, - static_cast(visualInfo.depth), - m_window, - screen->root, - 0, 0, - width, height, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - visualInfo.visualid, - XCB_CW_COLORMAP, - value_list - ); + m_window = XCreateWindow(m_display, + RootWindow(m_display, screen), + 0, 0, + width, height, + 0, + DefaultDepth(m_display, screen), + InputOutput, + visualInfo.visual, + CWColormap, + &attributes); m_ownsWindow = true; @@ -546,7 +539,6 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned void GlxContext::createSurface(::Window window) { m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); // A window already exists, so just use it m_window = window; diff --git a/src/SFML/Window/Unix/GlxContext.hpp b/src/SFML/Window/Unix/GlxContext.hpp index 4a9444f2..959c3299 100644 --- a/src/SFML/Window/Unix/GlxContext.hpp +++ b/src/SFML/Window/Unix/GlxContext.hpp @@ -30,7 +30,7 @@ //////////////////////////////////////////////////////////// #include #include -#include +#include namespace sf @@ -178,7 +178,6 @@ private: //////////////////////////////////////////////////////////// ::Display* m_display; ///< Connection to the X server ::Window m_window; ///< Window to which the context is attached - xcb_connection_t* m_connection; ///< Pointer to the xcb connection GLXContext m_context; ///< OpenGL context GLXPbuffer m_pbuffer; ///< GLX pbuffer ID if one was created bool m_ownsWindow; ///< Do we own the window associated to the context? diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp index ad62cd50..90cae1a2 100644 --- a/src/SFML/Window/Unix/InputImpl.cpp +++ b/src/SFML/Window/Unix/InputImpl.cpp @@ -28,9 +28,8 @@ #include // important to be included first (conflict with None) #include #include -#include #include -#include +#include #include @@ -157,36 +156,26 @@ bool InputImpl::isKeyPressed(Keyboard::Key key) Display* display = OpenDisplay(); // Convert to keycode - xcb_keycode_t keycode = XKeysymToKeycode(display, keysym); - - CloseDisplay(display); - - ScopedXcbPtr error(NULL); - - // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Get the whole keyboard state - ScopedXcbPtr keymap( - xcb_query_keymap_reply( - connection, - xcb_query_keymap(connection), - &error - ) - ); - - // Close the connection with the X server - CloseConnection(connection); - - if (error) + KeyCode keycode = XKeysymToKeycode(display, keysym); + if (keycode != 0) { - err() << "Failed to query keymap" << std::endl; + // Get the whole keyboard state + char keys[32]; + XQueryKeymap(display, keys); + + // Close the connection with the X server + CloseDisplay(display); + + // Check our keycode + return (keys[keycode / 8] & (1 << (keycode % 8))) != 0; + } + else + { + // Close the connection with the X server + CloseDisplay(display); return false; } - - // Check our keycode - return (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0; } @@ -201,43 +190,30 @@ void InputImpl::setVirtualKeyboardVisible(bool /*visible*/) bool InputImpl::isMouseButtonPressed(Mouse::Button button) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(NULL); + // we don't care about these but they are required + ::Window root, child; + int wx, wy; + int gx, gy; - // Get pointer mask - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - XCBDefaultRootWindow(connection) - ), - &error - ) - ); + unsigned int buttons = 0; + XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &wx, &wy, &buttons); // Close the connection with the X server - CloseConnection(connection); - - if (error) - { - err() << "Failed to query pointer" << std::endl; - - return false; - } - - uint16_t buttons = pointer->mask; + CloseDisplay(display); switch (button) { - case Mouse::Left: return buttons & XCB_BUTTON_MASK_1; - case Mouse::Right: return buttons & XCB_BUTTON_MASK_3; - case Mouse::Middle: return buttons & XCB_BUTTON_MASK_2; + case Mouse::Left: return buttons & Button1Mask; + case Mouse::Right: return buttons & Button3Mask; + case Mouse::Middle: return buttons & Button2Mask; case Mouse::XButton1: return false; // not supported by X case Mouse::XButton2: return false; // not supported by X default: return false; } + + return false; } @@ -245,32 +221,21 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button) Vector2i InputImpl::getMousePosition() { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(NULL); + // we don't care about these but they are required + ::Window root, child; + int x, y; + unsigned int buttons; - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - XCBDefaultRootWindow(connection) - ), - &error - ) - ); + int gx = 0; + int gy = 0; + XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &x, &y, &buttons); // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); - if (error) - { - err() << "Failed to query pointer" << std::endl; - - return Vector2i(0, 0); - } - - return Vector2i(pointer->root_x, pointer->root_y); + return Vector2i(gx, gy); } @@ -281,32 +246,21 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo) if (handle) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(NULL); + // we don't care about these but they are required + ::Window root, child; + int gx, gy; + unsigned int buttons; - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - handle - ), - &error - ) - ); + int x = 0; + int y = 0; + XQueryPointer(display, handle, &root, &child, &gx, &gy, &x, &y, &buttons); // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); - if (error) - { - err() << "Failed to query pointer" << std::endl; - - return Vector2i(0, 0); - } - - return Vector2i(pointer->win_x, pointer->win_y); + return Vector2i(x, y); } else { @@ -319,27 +273,13 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo) void InputImpl::setMousePosition(const Vector2i& position) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(xcb_request_check( - connection, - xcb_warp_pointer( - connection, - None, // Source window - XCBDefaultRootWindow(connection), // Destination window - 0, 0, // Source position - 0, 0, // Source size - position.x, position.y // Destination position - ) - )); - - if (error) - err() << "Failed to set mouse position" << std::endl; - - xcb_flush(connection); + XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y); + XFlush(display); // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); } @@ -347,31 +287,17 @@ void InputImpl::setMousePosition(const Vector2i& position) void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); WindowHandle handle = relativeTo.getSystemHandle(); if (handle) { - ScopedXcbPtr error(xcb_request_check( - connection, - xcb_warp_pointer( - connection, - None, // Source window - handle, // Destination window - 0, 0, // Source position - 0, 0, // Source size - position.x, position.y // Destination position - ) - )); - - if (error) - err() << "Failed to set mouse position" << std::endl; - - xcb_flush(connection); + XWarpPointer(display, None, handle, 0, 0, 0, 0, position.x, position.y); + XFlush(display); } // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); } diff --git a/src/SFML/Window/Unix/ScopedXcbPtr.hpp b/src/SFML/Window/Unix/ScopedXcbPtr.hpp deleted file mode 100644 index f610d81d..00000000 --- a/src/SFML/Window/Unix/ScopedXcbPtr.hpp +++ /dev/null @@ -1,102 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -#ifndef SFML_SCOPEDXCBPTR_HPP -#define SFML_SCOPEDXCBPTR_HPP - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include - - -namespace sf -{ -namespace priv -{ -//////////////////////////////////////////////////////////// -/// \brief Scoped pointer that frees memory returned in XCB replies -/// -//////////////////////////////////////////////////////////// -template -class ScopedXcbPtr -{ -public: - //////////////////////////////////////////////////////////// - /// \brief Constructor - /// - /// \param pointer Pointer value to store - /// - //////////////////////////////////////////////////////////// - ScopedXcbPtr(T* pointer); - - //////////////////////////////////////////////////////////// - /// \brief Destructor, calls std::free() on the stored pointer - /// - //////////////////////////////////////////////////////////// - ~ScopedXcbPtr(); - - //////////////////////////////////////////////////////////// - /// \brief Structure dereference operator - /// - /// \return Stored pointer - /// - //////////////////////////////////////////////////////////// - T* operator ->() const; - - //////////////////////////////////////////////////////////// - /// \brief Address operator. - /// - /// \return Address of the stored pointer - /// - //////////////////////////////////////////////////////////// - T** operator &(); - - //////////////////////////////////////////////////////////// - /// \brief Check if stored pointer is valid - /// - /// \return true if stored pointer is valid - /// - //////////////////////////////////////////////////////////// - operator bool() const; - - //////////////////////////////////////////////////////////// - /// \brief Retrieve the stored pointer. - /// - /// \return The stored pointer - /// - //////////////////////////////////////////////////////////// - T* get() const; - -private: - T* m_pointer; ///< Stored pointer -}; - -#include - -} // namespace priv - -} // namespace sf - -#endif // SFML_SCOPEDXCBPTR_HPP diff --git a/src/SFML/Window/Unix/ScopedXcbPtr.inl b/src/SFML/Window/Unix/ScopedXcbPtr.inl deleted file mode 100644 index 5869d916..00000000 --- a/src/SFML/Window/Unix/ScopedXcbPtr.inl +++ /dev/null @@ -1,72 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////// -template -inline ScopedXcbPtr::ScopedXcbPtr(T* pointer) : -m_pointer(pointer) -{ - -} - - -//////////////////////////////////////////////////////////// -template -inline ScopedXcbPtr::~ScopedXcbPtr() -{ - std::free(m_pointer); -} - - -//////////////////////////////////////////////////////////// -template -inline T* ScopedXcbPtr::operator ->() const -{ - return m_pointer; -} - - -//////////////////////////////////////////////////////////// -template -inline T** ScopedXcbPtr::operator &() -{ - return &m_pointer; -} - - -//////////////////////////////////////////////////////////// -template -inline ScopedXcbPtr::operator bool() const -{ - return m_pointer != NULL; -} - - -//////////////////////////////////////////////////////////// -template -inline T* ScopedXcbPtr::get() const -{ - return m_pointer; -} diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp index f95d3232..cd78c548 100644 --- a/src/SFML/Window/Unix/VideoModeImpl.cpp +++ b/src/SFML/Window/Unix/VideoModeImpl.cpp @@ -27,9 +27,9 @@ //////////////////////////////////////////////////////////// #include #include -#include #include -#include +#include +#include #include @@ -43,95 +43,78 @@ std::vector VideoModeImpl::getFullscreenModes() std::vector modes; // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Retrieve the default screen - xcb_screen_t* screen = XCBDefaultScreen(connection); - - ScopedXcbPtr error(NULL); - - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) + Display* display = OpenDisplay(); + if (display) { - // Randr extension is not supported: we cannot get the video modes - err() << "Failed to use the RandR extension while trying to get the supported video modes" << std::endl; + // Retrieve the default screen number + int screen = DefaultScreen(display); - // Close the connection with the X server - CloseConnection(connection); - - return modes; - } - - // Load RandR and check its version - ScopedXcbPtr randrVersion(xcb_randr_query_version_reply( - connection, - xcb_randr_query_version( - connection, - 1, - 1 - ), - &error - )); - - if (error) - { - err() << "Failed to load the RandR extension while trying to get the supported video modes" << std::endl; - - // Close the connection with the X server - CloseConnection(connection); - - return modes; - } - - // Get the current configuration - ScopedXcbPtr config(xcb_randr_get_screen_info_reply( - connection, - xcb_randr_get_screen_info( - connection, - screen->root - ), - &error - )); - - if (error) - { - // Failed to get the screen configuration - err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl; - - // Close the connection with the X server - CloseConnection(connection); - - return modes; - } - - // Get the available screen sizes - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - if (sizes && (config->nSizes > 0)) - { - // Get the list of supported depths - xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen); - // Combine depths and sizes to fill the array of supported modes - for (; iter.rem; xcb_depth_next(&iter)) + // Check if the XRandR extension is present + int version; + if (XQueryExtension(display, "RANDR", &version, &version, &version)) { - for (int j = 0; j < config->nSizes; ++j) + // Get the current configuration + XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); + if (config) { - // Convert to VideoMode - VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth); + // Get the available screen sizes + int nbSizes; + XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); + if (sizes && (nbSizes > 0)) + { + // Get the list of supported depths + int nbDepths = 0; + int* depths = XListDepths(display, screen, &nbDepths); + if (depths && (nbDepths > 0)) + { + // Combine depths and sizes to fill the array of supported modes + for (int i = 0; i < nbDepths; ++i) + { + for (int j = 0; j < nbSizes; ++j) + { + // Convert to VideoMode + VideoMode mode(sizes[j].width, sizes[j].height, depths[i]); - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(mode.width, mode.height); + Rotation currentRotation; + XRRConfigRotations(config, ¤tRotation); - // Add it only if it is not already in the array - if (std::find(modes.begin(), modes.end(), mode) == modes.end()) - modes.push_back(mode); + if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) + std::swap(mode.width, mode.height); + + // Add it only if it is not already in the array + if (std::find(modes.begin(), modes.end(), mode) == modes.end()) + modes.push_back(mode); + } + } + + // Free the array of depths + XFree(depths); + } + } + + // Free the configuration instance + XRRFreeScreenConfigInfo(config); + } + else + { + // Failed to get the screen configuration + err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl; } } - } + else + { + // XRandr extension is not supported: we cannot get the video modes + err() << "Failed to use the XRandR extension while trying to get the supported video modes" << std::endl; + } - // Close the connection with the X server - CloseConnection(connection); + // Close the connection with the X server + CloseDisplay(display); + } + else + { + // We couldn't connect to the X server + err() << "Failed to connect to the X server while trying to get the supported video modes" << std::endl; + } return modes; } @@ -143,91 +126,62 @@ VideoMode VideoModeImpl::getDesktopMode() VideoMode desktopMode; // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Retrieve the default screen - xcb_screen_t* screen = XCBDefaultScreen(connection); - - ScopedXcbPtr error(NULL); - - // Check if the RandR extension is present - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) + Display* display = OpenDisplay(); + if (display) { - // Randr extension is not supported: we cannot get the video modes - err() << "Failed to use the RandR extension while trying to get the desktop video mode" << std::endl; + // Retrieve the default screen number + int screen = DefaultScreen(display); + + // Check if the XRandR extension is present + int version; + if (XQueryExtension(display, "RANDR", &version, &version, &version)) + { + // Get the current configuration + XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); + if (config) + { + // Get the current video mode + Rotation currentRotation; + int currentMode = XRRConfigCurrentConfiguration(config, ¤tRotation); + + // Get the available screen sizes + int nbSizes; + XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); + if (sizes && (nbSizes > 0)) + { + desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, DefaultDepth(display, screen)); + + Rotation currentRotation; + XRRConfigRotations(config, ¤tRotation); + + if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) + std::swap(desktopMode.width, desktopMode.height); + } + + // Free the configuration instance + XRRFreeScreenConfigInfo(config); + } + else + { + // Failed to get the screen configuration + err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl; + } + } + else + { + // XRandr extension is not supported: we cannot get the video modes + err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl; + } // Close the connection with the X server - CloseConnection(connection); - - return desktopMode; - } - - // Load RandR and check its version - ScopedXcbPtr randrVersion(xcb_randr_query_version_reply( - connection, - xcb_randr_query_version( - connection, - 1, - 1 - ), - &error - )); - - if (error) - { - err() << "Failed to load the RandR extension while trying to get the desktop video mode" << std::endl; - - // Close the connection with the X server - CloseConnection(connection); - - return desktopMode; - } - - // Get the current configuration - ScopedXcbPtr config(xcb_randr_get_screen_info_reply( - connection, - xcb_randr_get_screen_info( - connection, - screen->root - ), - &error - )); - - if (error) - { - // Failed to get the screen configuration - err() << "Failed to retrieve the screen configuration while trying to get the desktop video mode" << std::endl; - - // Close the connection with the X server - CloseConnection(connection); - - return desktopMode; - } - - // Get the current video mode - xcb_randr_mode_t currentMode = config->sizeID; - - // Get the available screen sizes - int nbSizes = xcb_randr_get_screen_info_sizes_length(config.get()); - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - if (sizes && (nbSizes > 0)) - { - desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth); - - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(desktopMode.width, desktopMode.height); + CloseDisplay(display); } else { - err() << "Failed to retrieve any screen sizes while trying to get the desktop video mode" << std::endl; + // We couldn't connect to the X server + err() << "Failed to connect to the X server while trying to get the desktop video modes" << std::endl; } - // Close the connection with the X server - CloseConnection(connection); - return desktopMode; } diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 9e7fca76..530bea50 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -29,15 +29,16 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include +#include +#include +#include +#include #include #include #include @@ -66,12 +67,12 @@ namespace sf::Mutex allWindowsMutex; sf::String windowManagerName; - static const unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | - XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS | - XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | - XCB_EVENT_MASK_VISIBILITY_CHANGE; + static const unsigned long eventMask = FocusChangeMask | ButtonPressMask | + ButtonReleaseMask | ButtonMotionMask | + PointerMotionMask | KeyPressMask | + KeyReleaseMask | StructureNotifyMask | + EnterWindowMask | LeaveWindowMask | + VisibilityChangeMask | PropertyChangeMask; static const unsigned int maxTrialsCount = 5; @@ -127,76 +128,88 @@ namespace checked = true; - xcb_connection_t* connection = sf::priv::OpenConnection(); - - xcb_atom_t netSupportingWmCheck = sf::priv::getAtom("_NET_SUPPORTING_WM_CHECK", true); - xcb_atom_t netSupported = sf::priv::getAtom("_NET_SUPPORTED", true); + Atom netSupportingWmCheck = sf::priv::getAtom("_NET_SUPPORTING_WM_CHECK", true); + Atom netSupported = sf::priv::getAtom("_NET_SUPPORTED", true); if (!netSupportingWmCheck || !netSupported) return false; - sf::priv::ScopedXcbPtr error(NULL); + ::Display* display = sf::priv::OpenDisplay(); - sf::priv::ScopedXcbPtr rootSupportingWindow(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - sf::priv::XCBDefaultRootWindow(connection), - netSupportingWmCheck, - XCB_ATOM_WINDOW, - 0, - 1 - ), - &error - )); + Atom actualType; + int actualFormat; + unsigned long numItems; + unsigned long numBytes; + unsigned char* data; - if (!rootSupportingWindow || rootSupportingWindow->length != 1) + int result = XGetWindowProperty(display, + DefaultRootWindow(display), + netSupportingWmCheck, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); + + if (result != Success || actualType != XA_WINDOW || numItems != 1) { - sf::priv::CloseConnection(connection); + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return false; } - xcb_window_t* rootWindow = reinterpret_cast(xcb_get_property_value(rootSupportingWindow.get())); + ::Window rootWindow = *reinterpret_cast< ::Window* >(data); + + XFree(data); if (!rootWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } - sf::priv::ScopedXcbPtr childSupportingWindow(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - *rootWindow, - netSupportingWmCheck, - XCB_ATOM_WINDOW, - 0, - 1 - ), - &error - )); + result = XGetWindowProperty(display, + rootWindow, + netSupportingWmCheck, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); - if (!childSupportingWindow || childSupportingWindow->length != 1) + if (result != Success || actualType != XA_WINDOW || numItems != 1) { - sf::priv::CloseConnection(connection); + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return false; } - xcb_window_t* childWindow = reinterpret_cast(xcb_get_property_value(childSupportingWindow.get())); + ::Window childWindow = *reinterpret_cast< ::Window* >(data); + + XFree(data); if (!childWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } // Conforming window managers should return the same window for both queries - if (*rootWindow != *childWindow) + if (rootWindow != childWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } @@ -204,45 +217,51 @@ namespace // We try to get the name of the window manager // for window manager specific workarounds - xcb_atom_t netWmName = sf::priv::getAtom("_NET_WM_NAME", true); - xcb_atom_t utf8StringType = sf::priv::getAtom("UTF8_STRING"); - - if (!utf8StringType) - utf8StringType = XCB_ATOM_STRING; + Atom netWmName = sf::priv::getAtom("_NET_WM_NAME", true); if (!netWmName) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return true; } - sf::priv::ScopedXcbPtr wmName(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - *childWindow, - netWmName, - utf8StringType, - 0, - 0x7fffffff - ), - &error - )); + Atom utf8StringType = sf::priv::getAtom("UTF8_STRING"); - sf::priv::CloseConnection(connection); + if (!utf8StringType) + utf8StringType = XA_STRING; - // It seems the wm name string reply is not necessarily - // null-terminated. The work around is to get its actual - // length to build a proper string - const char* begin = reinterpret_cast(xcb_get_property_value(wmName.get())); - const char* end = begin + xcb_get_property_value_length(wmName.get()); - windowManagerName = sf::String::fromUtf8(begin, end); + result = XGetWindowProperty(display, + rootWindow, + netWmName, + 0, + 0x7fffffff, + False, + utf8StringType, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); + + if (actualType && numItems) + { + // It seems the wm name string reply is not necessarily + // null-terminated. The work around is to get its actual + // length to build a proper string + const char* begin = reinterpret_cast(data); + const char* end = begin + numItems; + windowManagerName = sf::String::fromUtf8(begin, end); + } + + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return true; } - sf::Keyboard::Key keysymToSF(xcb_keysym_t symbol) + sf::Keyboard::Key keysymToSF(KeySym symbol) { switch (symbol) { @@ -362,10 +381,11 @@ namespace priv //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(WindowHandle handle) : m_window (0), -m_screen (NULL), +m_screen (0), m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (true), +m_oldVideoMode (0), m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), @@ -374,24 +394,16 @@ m_fullscreen (false), m_cursorGrabbed (false), m_windowMapped (false), m_iconPixmap (0), -m_iconMaskPixmap (0) +m_iconMaskPixmap (0), +m_lastInputTime (0) { // Open a connection with the X server m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); - - std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); - - if (!m_connection) - { - err() << "Failed cast Display object to an XCB connection object" << std::endl; - return; - } // Make sure to check for EWMH support before we do anything ewmhSupported(); - m_screen = XCBDefaultScreen(m_connection); + m_screen = DefaultScreen(m_display); // Save the window handle m_window = handle; @@ -399,14 +411,10 @@ m_iconMaskPixmap (0) if (m_window) { // Make sure the window is listening to all the required events - const uint32_t value_list[] = {static_cast(eventMask)}; + XSetWindowAttributes attributes; + attributes.event_mask = eventMask; - xcb_change_window_attributes( - m_connection, - m_window, - XCB_CW_EVENT_MASK, - value_list - ); + XChangeWindowAttributes(m_display, m_window, CWEventMask, &attributes); // Set the WM protocols setProtocols(); @@ -420,10 +428,11 @@ m_iconMaskPixmap (0) //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) : m_window (0), -m_screen (NULL), +m_screen (0), m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (false), +m_oldVideoMode (0), m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), @@ -432,28 +441,20 @@ m_fullscreen ((style & Style::Fullscreen) != 0), m_cursorGrabbed (m_fullscreen), m_windowMapped (false), m_iconPixmap (0), -m_iconMaskPixmap (0) +m_iconMaskPixmap (0), +m_lastInputTime (0) { // Open a connection with the X server m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); - - std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); - - if (!m_connection) - { - err() << "Failed cast Display object to an XCB connection object" << std::endl; - return; - } // Make sure to check for EWMH support before we do anything ewmhSupported(); - m_screen = XCBDefaultScreen(m_connection); + m_screen = DefaultScreen(m_display); // Compute position and size - int left = m_fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2; - int top = m_fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2; + int left = m_fullscreen ? 0 : (DisplayWidth(m_display, m_screen) - mode.width) / 2; + int top = m_fullscreen ? 0 : (DisplayHeight(m_display, m_screen) - mode.height) / 2; int width = mode.width; int height = mode.height; @@ -461,31 +462,23 @@ m_iconMaskPixmap (0) XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings); // Define the window attributes - xcb_colormap_t colormap = xcb_generate_id(m_connection); - xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, m_screen->root, visualInfo.visualid); - const uint32_t value_list[] = {m_fullscreen && !ewmhSupported(), static_cast(eventMask), colormap}; + XSetWindowAttributes attributes; + attributes.colormap = XCreateColormap(m_display, DefaultRootWindow(m_display), visualInfo.visual, AllocNone); + attributes.event_mask = eventMask; + attributes.override_redirect = (m_fullscreen && !ewmhSupported()) ? True : False; - // Create the window - m_window = xcb_generate_id(m_connection); + m_window = XCreateWindow(m_display, + DefaultRootWindow(m_display), + left, top, + width, height, + 0, + visualInfo.depth, + InputOutput, + visualInfo.visual, + CWEventMask | CWOverrideRedirect | CWColormap, + &attributes); - ScopedXcbPtr errptr(xcb_request_check( - m_connection, - xcb_create_window_checked( - m_connection, - static_cast(visualInfo.depth), - m_window, - m_screen->root, - left, top, - width, height, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - visualInfo.visualid, - XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP, - value_list - ) - )); - - if (errptr) + if (!m_window) { err() << "Failed to create window" << std::endl; return; @@ -495,54 +488,113 @@ m_iconMaskPixmap (0) setProtocols(); // Set the WM initial state to the normal state - WMHints hints; - std::memset(&hints, 0, sizeof(hints)); - hints.initial_state = 1; - hints.flags |= 1 << 1; - setWMHints(hints); + XWMHints* hints = XAllocWMHints(); + hints->flags = StateHint; + hints->initial_state = NormalState; + XSetWMHints(m_display, m_window, hints); + XFree(hints); // If not in fullscreen, set the window's style (tell the window manager to // change our window's decorations and functions according to the requested style) if (!m_fullscreen) - setMotifHints(style); - - WMSizeHints sizeHints; - std::memset(&sizeHints, 0, sizeof(sizeHints)); - - // This is a hack to force some windows managers to disable resizing - // Fullscreen is bugged on Openbox. Unless size hints are set, there - // will be a region of the window that is off-screen. We try to workaround - // this by setting size hints even in fullscreen just for Openbox. - if ((!m_fullscreen || (windowManagerName == "Openbox")) && !(style & Style::Resize)) { - m_useSizeHints = true; - sizeHints.flags |= ((1 << 4) | (1 << 5)); - sizeHints.min_width = width; - sizeHints.max_width = width; - sizeHints.min_height = height; - sizeHints.max_height = height; + Atom WMHintsAtom = getAtom("_MOTIF_WM_HINTS", false); + if (WMHintsAtom) + { + static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; + static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1; + + //static const unsigned long MWM_DECOR_ALL = 1 << 0; + static const unsigned long MWM_DECOR_BORDER = 1 << 1; + static const unsigned long MWM_DECOR_RESIZEH = 1 << 2; + static const unsigned long MWM_DECOR_TITLE = 1 << 3; + static const unsigned long MWM_DECOR_MENU = 1 << 4; + static const unsigned long MWM_DECOR_MINIMIZE = 1 << 5; + static const unsigned long MWM_DECOR_MAXIMIZE = 1 << 6; + + //static const unsigned long MWM_FUNC_ALL = 1 << 0; + static const unsigned long MWM_FUNC_RESIZE = 1 << 1; + static const unsigned long MWM_FUNC_MOVE = 1 << 2; + static const unsigned long MWM_FUNC_MINIMIZE = 1 << 3; + static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4; + static const unsigned long MWM_FUNC_CLOSE = 1 << 5; + + struct WMHints + { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long inputMode; + unsigned long state; + }; + + WMHints hints; + std::memset(&hints, 0, sizeof(hints)); + hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; + hints.decorations = 0; + hints.functions = 0; + + if (style & Style::Titlebar) + { + hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; + hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; + } + if (style & Style::Resize) + { + hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; + hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; + } + if (style & Style::Close) + { + hints.decorations |= 0; + hints.functions |= MWM_FUNC_CLOSE; + } + + XChangeProperty(m_display, + m_window, + WMHintsAtom, + WMHintsAtom, + 32, + PropModeReplace, + reinterpret_cast(&hints), + 5); + } } - // Set the WM hints of the normal state - setWMSizeHints(sizeHints); + // This is a hack to force some windows managers to disable resizing + if (!(style & Style::Resize)) + { + m_useSizeHints = true; + XSizeHints* sizeHints = XAllocSizeHints(); + sizeHints->flags = PMinSize | PMaxSize; + sizeHints->min_width = sizeHints->max_width = width; + sizeHints->min_height = sizeHints->max_height = height; + XSetWMNormalHints(m_display, m_window, sizeHints); + XFree(sizeHints); + } // Set the window's WM class (this can be used by window managers) - // The WM_CLASS property actually consists of 2 parts, - // the instance name and the class name both of which should be - // null terminated strings. - // The instance name should be something unique to this invokation + XClassHint* hint = XAllocClassHint(); + + // The instance name should be something unique to this invocation // of the application but is rarely if ever used these days. // For simplicity, we retrieve it via the base executable name. + std::string executableName = findExecutableName(); + std::vector windowInstance(executableName.size() + 1, 0); + std::copy(executableName.begin(), executableName.end(), windowInstance.begin()); + hint->res_name = &windowInstance[0]; + // The class name identifies a class of windows that // "are of the same type". We simply use the initial window name as // the class name. - std::string windowClass = findExecutableName(); - windowClass += '\0'; // Important to separate instance from class - windowClass += title.toAnsiString(); + std::string ansiTitle = title.toAnsiString(); + std::vector windowClass(ansiTitle.size() + 1, 0); + std::copy(ansiTitle.begin(), ansiTitle.end(), windowClass.begin()); + hint->res_class = &windowClass[0]; - // We add 1 to the size of the string to include the null at the end - if (!changeWindowProperty(XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, windowClass.size() + 1, windowClass.c_str())) - sf::err() << "Failed to set WM_CLASS property" << std::endl; + XSetClassHint(m_display, m_window, hint); + + XFree(hint); // Set the window's name setTitle(title); @@ -567,53 +619,26 @@ WindowImplX11::~WindowImplX11() cleanup(); // Destroy icon pixmap - if (m_iconPixmap) - { - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - m_iconPixmap - ) - )); - - if (freePixmapError) - { - err() << "Failed to free icon pixmap: "; - err() << "Error code " << static_cast(freePixmapError->error_code) << std::endl; - } - } + if(m_iconPixmap) + XFreePixmap(m_display, m_iconPixmap); // Destroy icon mask pixmap - if (m_iconMaskPixmap) - { - ScopedXcbPtr freePixmapMaskError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - m_iconMaskPixmap - ) - )); - - if (freePixmapMaskError) - { - err() << "Failed to free icon mask pixmap: "; - err() << "Error code " << static_cast(freePixmapMaskError->error_code) << std::endl; - } - } + if(m_iconMaskPixmap) + XFreePixmap(m_display, m_iconMaskPixmap); // Destroy the cursor if (m_hiddenCursor) - xcb_free_cursor(m_connection, m_hiddenCursor); + XFreeCursor(m_display, m_hiddenCursor); // Destroy the input context if (m_inputContext) XDestroyIC(m_inputContext); + // Destroy the window if (m_window && !m_isExternal) { - xcb_destroy_window(m_connection, m_window); - xcb_flush(m_connection); + XDestroyWindow(m_display, m_window); + XFlush(m_display); } // Close the input method @@ -650,70 +675,31 @@ void WindowImplX11::processEvents() //////////////////////////////////////////////////////////// Vector2i WindowImplX11::getPosition() const { - ::Window topLevelWindow = m_window; - ::Window nextWindow = topLevelWindow; + ::Window root, child; + int localX, localY, x, y; + unsigned int width, height, border, depth; - ScopedXcbPtr error(NULL); + XGetGeometry(m_display, m_window, &root, &localX, &localY, &width, &height, &border, &depth); + XTranslateCoordinates(m_display, m_window, root, localX, localY, &x, &y, &child); - // Get "top level" window, i.e. the window with the root window as its parent. - while (nextWindow != m_screen->root) - { - topLevelWindow = nextWindow; - - ScopedXcbPtr treeReply(xcb_query_tree_reply( - m_connection, - xcb_query_tree( - m_connection, - topLevelWindow - ), - &error - )); - - if (error) - { - err() << "Failed to get window position (query_tree)" << std::endl; - return Vector2i(0, 0); - } - - nextWindow = treeReply->parent; - } - - ScopedXcbPtr geometryReply(xcb_get_geometry_reply( - m_connection, - xcb_get_geometry( - m_connection, - topLevelWindow - ), - &error - )); - - if (error) - { - err() << "Failed to get window position (get_geometry)" << std::endl; - return Vector2i(0, 0); - } - - return Vector2i(geometryReply->x, geometryReply->y); + return Vector2i(x, y); } //////////////////////////////////////////////////////////// void WindowImplX11::setPosition(const Vector2i& position) { - uint32_t values[] = {static_cast(position.x), static_cast(position.y)}; - xcb_configure_window(m_connection, m_window, - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, - values); - xcb_flush(m_connection); + XMoveWindow(m_display, m_window, position.x, position.y); + XFlush(m_display); } //////////////////////////////////////////////////////////// Vector2u WindowImplX11::getSize() const { - ScopedXcbPtr reply(xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL)); - - return Vector2u(reply->width, reply->height); + XWindowAttributes attributes; + XGetWindowAttributes(m_display, m_window, &attributes); + return Vector2u(attributes.width, attributes.height); } @@ -721,84 +707,74 @@ Vector2u WindowImplX11::getSize() const void WindowImplX11::setSize(const Vector2u& size) { // If resizing is disable for the window we have to update the size hints (required by some window managers). - if( m_useSizeHints ) { - WMSizeHints sizeHints; - std::memset(&sizeHints, 0, sizeof(sizeHints)); - - sizeHints.flags |= (1 << 4 | 1 << 5); - sizeHints.min_width = size.x; - sizeHints.max_width = size.x; - sizeHints.min_height = size.y; - sizeHints.max_height = size.y; - - setWMSizeHints(sizeHints); + if (m_useSizeHints) + { + XSizeHints* sizeHints = XAllocSizeHints(); + sizeHints->flags = PMinSize | PMaxSize; + sizeHints->min_width = sizeHints->max_width = size.x; + sizeHints->min_height = sizeHints->max_height = size.y; + XSetWMNormalHints(m_display, m_window, sizeHints); + XFree(sizeHints); } - uint32_t values[] = {size.x, size.y}; - - ScopedXcbPtr configureWindowError(xcb_request_check( - m_connection, - xcb_configure_window( - m_connection, - m_window, - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - values - ) - )); - - if (configureWindowError) - err() << "Failed to set window size" << std::endl; - - xcb_flush(m_connection); + XResizeWindow(m_display, m_window, size.x, size.y); + XFlush(m_display); } //////////////////////////////////////////////////////////// void WindowImplX11::setTitle(const String& title) { - // XCB takes UTF-8-encoded strings. - xcb_atom_t utf8StringType = getAtom("UTF8_STRING"); + // Bare X11 has no Unicode window title support. + // There is however an option to tell the window manager your Unicode title via hints. - if (!utf8StringType) - utf8StringType = XCB_ATOM_STRING; + // Convert to UTF-8 encoding. + std::basic_string utf8Title; + Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title)); - std::string utf8String; - Utf<32>::toUtf8(title.begin(), title.end(), std::back_inserter(utf8String)); + Atom useUtf8 = getAtom("UTF8_STRING", false); - if (!changeWindowProperty(XCB_ATOM_WM_NAME, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set window title" << std::endl; + // Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title. + Atom wmName = getAtom("_NET_WM_NAME", false); + XChangeProperty(m_display, m_window, wmName, useUtf8, 8, + PropModeReplace, utf8Title.c_str(), utf8Title.size()); - if (!changeWindowProperty(XCB_ATOM_WM_ICON_NAME, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set WM_ICON_NAME property" << std::endl; + // Set the _NET_WM_ICON_NAME atom, which specifies a UTF-8 encoded window title. + Atom wmIconName = getAtom("_NET_WM_ICON_NAME", false); + XChangeProperty(m_display, m_window, wmIconName, useUtf8, 8, + PropModeReplace, utf8Title.c_str(), utf8Title.size()); - if (ewmhSupported()) - { - xcb_atom_t netWmName = getAtom("_NET_WM_NAME", true); - xcb_atom_t netWmIconName = getAtom("_NET_WM_ICON_NAME", true); - - if (utf8StringType && netWmName) - { - if (!changeWindowProperty(netWmName, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set _NET_WM_NAME property" << std::endl; - } - - if (utf8StringType && netWmIconName) - { - if (!changeWindowProperty(netWmIconName, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set _NET_WM_ICON_NAME property" << std::endl; - } - } - - xcb_flush(m_connection); + // Set the non-Unicode title as a fallback for window managers who don't support _NET_WM_NAME. + #ifdef X_HAVE_UTF8_STRING + Xutf8SetWMProperties(m_display, + m_window, + title.toAnsiString().c_str(), + title.toAnsiString().c_str(), + NULL, + 0, + NULL, + NULL, + NULL); + #else + XmbSetWMProperties(m_display, + m_window, + title.toAnsiString().c_str(), + title.toAnsiString().c_str(), + NULL, + 0, + NULL, + NULL, + NULL); + #endif } //////////////////////////////////////////////////////////// void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels) { - // X11 and ICCCM want BGRA pixels: swap red and blue channels - // ICCCM also wants the first 2 unsigned 32-bit values to be width and height - Uint8 iconPixels[8 + width * height * 4]; + // X11 wants BGRA pixels: swap red and blue channels + // Note: this memory will be freed by XDestroyImage + Uint8* iconPixels = static_cast(std::malloc(width * height * 4)); for (std::size_t i = 0; i < width * height; ++i) { iconPixels[8 + i * 4 + 0] = pixels[i * 4 + 2]; @@ -807,69 +783,29 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 iconPixels[8 + i * 4 + 3] = pixels[i * 4 + 3]; } - reinterpret_cast(iconPixels)[0] = width; - reinterpret_cast(iconPixels)[1] = height; - - if (m_iconPixmap) - { - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - m_iconPixmap - ) - )); - - if (freePixmapError) - { - err() << "Failed to free icon pixmap: "; - err() << "Error code " << static_cast(freePixmapError->error_code) << std::endl; - } - - m_iconPixmap = 0; - } - - if (m_iconMaskPixmap) - { - ScopedXcbPtr freePixmapMaskError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - m_iconMaskPixmap - ) - )); - - if (freePixmapMaskError) - { - err() << "Failed to free icon mask pixmap: "; - err() << "Error code " << static_cast(freePixmapMaskError->error_code) << std::endl; - } - - m_iconMaskPixmap = 0; - } - // Create the icon pixmap - m_iconPixmap = xcb_generate_id(m_connection); - - ScopedXcbPtr createPixmapError(xcb_request_check( - m_connection, - xcb_create_pixmap_checked( - m_connection, - m_screen->root_depth, - m_iconPixmap, - m_screen->root, - width, - height - ) - )); - - if (createPixmapError) + Visual* defVisual = DefaultVisual(m_display, m_screen); + unsigned int defDepth = DefaultDepth(m_display, m_screen); + XImage* iconImage = XCreateImage(m_display, defVisual, defDepth, ZPixmap, 0, (char*)iconPixels, width, height, 32, 0); + if (!iconImage) { - err() << "Failed to set the window's icon (create_pixmap): "; - err() << "Error code " << static_cast(createPixmapError->error_code) << std::endl; + err() << "Failed to set the window's icon" << std::endl; return; } + if(m_iconPixmap) + XFreePixmap(m_display, m_iconPixmap); + + if(m_iconMaskPixmap) + XFreePixmap(m_display, m_iconMaskPixmap); + + m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth); + XGCValues values; + GC iconGC = XCreateGC(m_display, m_iconPixmap, 0, &values); + XPutImage(m_display, m_iconPixmap, iconGC, iconImage, 0, 0, 0, 0, width, height); + XFreeGC(m_display, iconGC); + XDestroyImage(iconImage); + // Create the mask pixmap (must have 1 bit depth) std::size_t pitch = (width + 7) / 8; std::vector maskPixels(pitch * height, 0); @@ -887,99 +823,42 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 } } } - - m_iconMaskPixmap = xcb_create_pixmap_from_bitmap_data( - m_connection, - m_window, - reinterpret_cast(&maskPixels[0]), - width, - height, - 1, - 0, - 1, - NULL - ); - - if (!m_iconMaskPixmap) - { - err() << "Failed to set the window's icon (create_pixmap_from_bitmap_data)" << std::endl; - return; - } - - xcb_gcontext_t iconGC = xcb_generate_id(m_connection); - - ScopedXcbPtr createGcError(xcb_request_check( - m_connection, - xcb_create_gc( - m_connection, - iconGC, - m_iconPixmap, - 0, - NULL - ) - )); - - if (createGcError) - { - err() << "Failed to set the window's icon (create_gc): "; - err() << "Error code " << static_cast(createGcError->error_code) << std::endl; - return; - } - - ScopedXcbPtr putImageError(xcb_request_check( - m_connection, - xcb_put_image_checked( - m_connection, - XCB_IMAGE_FORMAT_Z_PIXMAP, - m_iconPixmap, - iconGC, - width, - height, - 0, - 0, - 0, - m_screen->root_depth, - width * height * 4, - iconPixels + 8 - ) - )); - - ScopedXcbPtr freeGcError(xcb_request_check( - m_connection, - xcb_free_gc( - m_connection, - iconGC - ) - )); - - if (freeGcError) - { - err() << "Failed to free icon GC: "; - err() << "Error code " << static_cast(freeGcError->error_code) << std::endl; - } - - if (putImageError) - { - err() << "Failed to set the window's icon (put_image): "; - err() << "Error code " << static_cast(putImageError->error_code) << std::endl; - return; - } + m_iconMaskPixmap = XCreatePixmapFromBitmapData(m_display, m_window, (char*)&maskPixels[0], width, height, 1, 0, 1); // Send our new icon to the window through the WMHints - WMHints hints; - std::memset(&hints, 0, sizeof(hints)); - hints.flags |= ((1 << 2) | (1 << 5)); - hints.icon_pixmap = m_iconPixmap; - hints.icon_mask = m_iconMaskPixmap; + XWMHints* hints = XAllocWMHints(); + hints->flags = IconPixmapHint | IconMaskHint; + hints->icon_pixmap = m_iconPixmap; + hints->icon_mask = m_iconMaskPixmap; + XSetWMHints(m_display, m_window, hints); + XFree(hints); - setWMHints(hints); + // ICCCM wants BGRA pixels: swap red and blue channels + // ICCCM also wants the first 2 unsigned 32-bit values to be width and height + std::vector icccmIconPixels(8 + width * height * 4, 0); + for (std::size_t i = 0; i < width * height; ++i) + { + icccmIconPixels[8 + i * 4 + 0] = pixels[i * 4 + 2]; + icccmIconPixels[8 + i * 4 + 1] = pixels[i * 4 + 1]; + icccmIconPixels[8 + i * 4 + 2] = pixels[i * 4 + 0]; + icccmIconPixels[8 + i * 4 + 3] = pixels[i * 4 + 3]; + } - xcb_atom_t netWmIcon = getAtom("_NET_WM_ICON"); + reinterpret_cast(&icccmIconPixels[0])[0] = width; + reinterpret_cast(&icccmIconPixels[0])[1] = height; - if (!changeWindowProperty(netWmIcon, XCB_ATOM_CARDINAL, 32, 2 + width * height, iconPixels)) - err() << "Failed to set the window's icon (changeWindowProperty)" << std::endl; + Atom netWmIcon = getAtom("_NET_WM_ICON"); - xcb_flush(m_connection); + XChangeProperty(m_display, + m_window, + netWmIcon, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&icccmIconPixels[0]), + 2 + width * height); + + XFlush(m_display); } @@ -988,18 +867,9 @@ void WindowImplX11::setVisible(bool visible) { if (visible) { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_map_window( - m_connection, - m_window - ) - )); + XMapWindow(m_display, m_window); - if (error) - err() << "Failed to change window visibility" << std::endl; - - xcb_flush(m_connection); + XFlush(m_display); // Before continuing, make sure the WM has // internally marked the window as viewable @@ -1008,18 +878,9 @@ void WindowImplX11::setVisible(bool visible) } else { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_unmap_window( - m_connection, - m_window - ) - )); + XUnmapWindow(m_display, m_window); - if (error) - err() << "Failed to change window visibility" << std::endl; - - xcb_flush(m_connection); + XFlush(m_display); // Before continuing, make sure the WM has // internally marked the window as unviewable @@ -1032,22 +893,8 @@ void WindowImplX11::setVisible(bool visible) //////////////////////////////////////////////////////////// void WindowImplX11::setMouseCursorVisible(bool visible) { - const uint32_t values = visible ? XCB_NONE : m_hiddenCursor; - - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_change_window_attributes( - m_connection, - m_window, - XCB_CW_CURSOR, - &values - ) - )); - - if (error) - err() << "Failed to change mouse cursor visibility" << std::endl; - - xcb_flush(m_connection); + XDefineCursor(m_display, m_window, visible ? None : m_hiddenCursor); + XFlush(m_display); } @@ -1063,25 +910,9 @@ void WindowImplX11::setMouseCursorGrabbed(bool grabbed) // Try multiple times to grab the cursor for (unsigned int trial = 0; trial < maxTrialsCount; ++trial) { - sf::priv::ScopedXcbPtr error(NULL); + int result = XGrabPointer(m_display, m_window, True, None, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); - sf::priv::ScopedXcbPtr grabPointerReply(xcb_grab_pointer_reply( - m_connection, - xcb_grab_pointer( - m_connection, - true, - m_window, - XCB_NONE, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, - m_window, - XCB_NONE, - XCB_CURRENT_TIME - ), - &error - )); - - if (!error && grabPointerReply && (grabPointerReply->status == XCB_GRAB_STATUS_SUCCESS)) + if (result == GrabSuccess) { m_cursorGrabbed = true; break; @@ -1096,22 +927,7 @@ void WindowImplX11::setMouseCursorGrabbed(bool grabbed) } else { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_ungrab_pointer_checked( - m_connection, - XCB_CURRENT_TIME - ) - )); - - if (!error) - { - m_cursorGrabbed = false; - } - else - { - err() << "Failed to ungrab mouse cursor" << std::endl; - } + XUngrabPointer(m_display, CurrentTime); } } @@ -1143,26 +959,16 @@ void WindowImplX11::requestFocus() } } - ScopedXcbPtr error(NULL); - // Check if window is viewable (not on other desktop, ...) // TODO: Check also if minimized - ScopedXcbPtr attributes(xcb_get_window_attributes_reply( - m_connection, - xcb_get_window_attributes( - m_connection, - m_window - ), - &error - )); - - if (error || !attributes) + XWindowAttributes attributes; + if (XGetWindowAttributes(m_display, m_window, &attributes) == 0) { - err() << "Failed to check if window is viewable while requesting focus" << std::endl; + sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl; return; // error getting attribute } - bool windowViewable = (attributes->map_state == XCB_MAP_STATE_VIEWABLE); + bool windowViewable = (attributes.map_state == IsViewable); if (sfmlWindowFocused && windowViewable) { @@ -1172,31 +978,16 @@ void WindowImplX11::requestFocus() } else { - // Get current WM hints. - ScopedXcbPtr hintsReply(xcb_get_property_reply( - m_connection, - xcb_get_property(m_connection, 0, m_window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9), - &error - )); + // Otherwise: display urgency hint (flashing application logo) + // Ensure WM hints exist, allocate if necessary + XWMHints* hints = XGetWMHints(m_display, m_window); + if (hints == NULL) + hints = XAllocWMHints(); - if (error || !hintsReply) - { - err() << "Failed to get WM hints while requesting focus" << std::endl; - return; - } - - WMHints* hints = reinterpret_cast(xcb_get_property_value(hintsReply.get())); - - if (!hints) - { - err() << "Failed to get WM hints while requesting focus" << std::endl; - return; - } - - // Even if no hints were returned, we can simply set the proper flags we need and go on. This is - // different from Xlib where XAllocWMHints() has to be called. - hints->flags |= (1 << 8); - setWMHints(*hints); + // Add urgency (notification) flag to hints + hints->flags |= XUrgencyHint; + XSetWMHints(m_display, m_window, hints); + XFree(hints); } } @@ -1204,91 +995,59 @@ void WindowImplX11::requestFocus() //////////////////////////////////////////////////////////// bool WindowImplX11::hasFocus() const { - ScopedXcbPtr error(NULL); + ::Window focusedWindow = 0; + int revertToReturn = 0; + XGetInputFocus(m_display, &focusedWindow, &revertToReturn); - ScopedXcbPtr reply(xcb_get_input_focus_reply( - m_connection, - xcb_get_input_focus_unchecked( - m_connection - ), - &error - )); - - if (error) - err() << "Failed to check if window has focus" << std::endl; - - return (reply->focus == m_window); + return (m_window == focusedWindow); } //////////////////////////////////////////////////////////// void WindowImplX11::grabFocus() { - xcb_atom_t netActiveWindow = XCB_ATOM_NONE; + Atom netActiveWindow = None; if (ewmhSupported()) netActiveWindow = getAtom("_NET_ACTIVE_WINDOW"); + // Only try to grab focus if the window is mapped + XWindowAttributes attr; + + XGetWindowAttributes(m_display, m_window, &attr); + + if (attr.map_state == IsUnmapped) + return; + if (netActiveWindow) { - xcb_client_message_event_t event; + XEvent event; std::memset(&event, 0, sizeof(event)); - event.response_type = XCB_CLIENT_MESSAGE; - event.window = m_window; - event.format = 32; - event.sequence = 0; - event.type = netActiveWindow; - event.data.data32[0] = 1; // Normal application - event.data.data32[1] = XCB_CURRENT_TIME; - event.data.data32[2] = 0; // We don't know the currently active window + event.type = ClientMessage; + event.xclient.window = m_window; + event.xclient.format = 32; + event.xclient.message_type = netActiveWindow; + event.xclient.data.l[0] = 1; // Normal application + event.xclient.data.l[1] = m_lastInputTime; + event.xclient.data.l[2] = 0; // We don't know the currently active window - ScopedXcbPtr activeWindowError(xcb_request_check( - m_connection, - xcb_send_event_checked( - m_connection, - 0, - XCBDefaultRootWindow(m_connection), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - reinterpret_cast(&event) - ) - )); + int result = XSendEvent(m_display, + DefaultRootWindow(m_display), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); - if (activeWindowError) + XFlush(m_display); + + if (!result) err() << "Setting fullscreen failed, could not send \"_NET_ACTIVE_WINDOW\" event" << std::endl; } else { - ScopedXcbPtr setInputFocusError(xcb_request_check( - m_connection, - xcb_set_input_focus( - m_connection, - XCB_INPUT_FOCUS_POINTER_ROOT, - m_window, - XCB_CURRENT_TIME - ) - )); - - if (setInputFocusError) - { - err() << "Failed to change active window (set_input_focus)" << std::endl; - return; - } - - const uint32_t values[] = {XCB_STACK_MODE_ABOVE}; - - ScopedXcbPtr configureWindowError(xcb_request_check( - m_connection, - xcb_configure_window( - m_connection, - m_window, - XCB_CONFIG_WINDOW_STACK_MODE, - values - ) - )); - - if (configureWindowError) - err() << "Failed to change active window (configure_window)" << std::endl; + XRaiseWindow(m_display, m_window); + XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); + XFlush(m_display); } } @@ -1300,46 +1059,19 @@ void WindowImplX11::setVideoMode(const VideoMode& mode) if (mode == VideoMode::getDesktopMode()) return; - ScopedXcbPtr error(NULL); - - // Check if the RandR extension is present - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(m_connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) + // Check if the XRandR extension is present + int version; + if (!XQueryExtension(m_display, "RANDR", &version, &version, &version)) { - // RandR extension is not supported: we cannot use fullscreen mode + // XRandR extension is not supported: we cannot use fullscreen mode err() << "Fullscreen is not supported, switching to window mode" << std::endl; return; } - // Load RandR and check its version - ScopedXcbPtr randrVersion(xcb_randr_query_version_reply( - m_connection, - xcb_randr_query_version( - m_connection, - 1, - 1 - ), - &error - )); - - if (error) - { - err() << "Failed to load RandR, switching to window mode" << std::endl; - return; - } - // Get the current configuration - ScopedXcbPtr config(xcb_randr_get_screen_info_reply( - m_connection, - xcb_randr_get_screen_info( - m_connection, - m_screen->root - ), - &error - )); + XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); - if (error || !config) + if (!config) { // Failed to get the screen configuration err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl; @@ -1347,52 +1079,34 @@ void WindowImplX11::setVideoMode(const VideoMode& mode) } // Save the current video mode before we switch to fullscreen - m_oldVideoMode = *config.get(); + Rotation currentRotation; + m_oldVideoMode = XRRConfigCurrentConfiguration(config, ¤tRotation); // Get the available screen sizes - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - - if (!sizes || !config->nSizes) - { - err() << "Failed to get the fullscreen sizes, switching to window mode" << std::endl; - return; - } + int nbSizes; + XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); // Search for a matching size - for (int i = 0; i < config->nSizes; ++i) + for (int i = 0; (sizes && i < nbSizes); ++i) { - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) + XRRConfigRotations(config, ¤tRotation); + + if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) std::swap(sizes[i].height, sizes[i].width); - if ((sizes[i].width == static_cast(mode.width)) && - (sizes[i].height == static_cast(mode.height))) + if ((sizes[i].width == static_cast(mode.width)) && (sizes[i].height == static_cast(mode.height))) { // Switch to fullscreen mode - ScopedXcbPtr setScreenConfig(xcb_randr_set_screen_config_reply( - m_connection, - xcb_randr_set_screen_config( - m_connection, - config->root, - XCB_CURRENT_TIME, - config->config_timestamp, - i, - config->rotation, - config->rate - ), - &error - )); - - if (error) - err() << "Failed to set new screen configuration" << std::endl; + XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime); // Set "this" as the current fullscreen window fullscreenWindow = this; - return; + break; } } - err() << "Failed to find matching fullscreen size, switching to window mode" << std::endl; + // Free the configuration instance + XRRFreeScreenConfigInfo(config); } @@ -1402,25 +1116,19 @@ void WindowImplX11::resetVideoMode() if (fullscreenWindow == this) { // Get current screen info - ScopedXcbPtr error(NULL); + XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); + if (config) + { + // Get the current rotation + Rotation currentRotation; + XRRConfigCurrentConfiguration(config, ¤tRotation); - // Reset the video mode - ScopedXcbPtr setScreenConfig(xcb_randr_set_screen_config_reply( - m_connection, - xcb_randr_set_screen_config( - m_connection, - m_oldVideoMode.root, - XCB_CURRENT_TIME, - m_oldVideoMode.config_timestamp, - m_oldVideoMode.sizeID, - m_oldVideoMode.rotation, - m_oldVideoMode.rate - ), - &error - )); + // Reset the video mode + XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime); - if (error) - err() << "Failed to reset old screen configuration" << std::endl; + // Free the configuration instance + XRRFreeScreenConfigInfo(config); + } // Reset the fullscreen window fullscreenWindow = NULL; @@ -1435,19 +1143,24 @@ void WindowImplX11::switchToFullscreen() if (ewmhSupported()) { - xcb_atom_t netWmBypassCompositor = getAtom("_NET_WM_BYPASS_COMPOSITOR"); + Atom netWmBypassCompositor = getAtom("_NET_WM_BYPASS_COMPOSITOR"); if (netWmBypassCompositor) { static const Uint32 bypassCompositor = 1; - // Not being able to bypass the compositor is not a fatal error - if (!changeWindowProperty(netWmBypassCompositor, XCB_ATOM_CARDINAL, 32, 1, &bypassCompositor)) - err() << "xcb_change_property failed, unable to set _NET_WM_BYPASS_COMPOSITOR" << std::endl; + XChangeProperty(m_display, + m_window, + netWmBypassCompositor, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&bypassCompositor), + 1); } - xcb_atom_t netWmState = getAtom("_NET_WM_STATE", true); - xcb_atom_t netWmStateFullscreen = getAtom("_NET_WM_STATE_FULLSCREEN", true); + Atom netWmState = getAtom("_NET_WM_STATE", true); + Atom netWmStateFullscreen = getAtom("_NET_WM_STATE_FULLSCREEN", true); if (!netWmState || !netWmStateFullscreen) { @@ -1455,32 +1168,26 @@ void WindowImplX11::switchToFullscreen() return; } - xcb_client_message_event_t event; + XEvent event; std::memset(&event, 0, sizeof(event)); - event.response_type = XCB_CLIENT_MESSAGE; - event.window = m_window; - event.format = 32; - event.sequence = 0; - event.type = netWmState; - event.data.data32[0] = 1; // _NET_WM_STATE_ADD - event.data.data32[1] = netWmStateFullscreen; - event.data.data32[2] = 0; // No second property - event.data.data32[3] = 1; // Normal window + event.type = ClientMessage; + event.xclient.window = m_window; + event.xclient.format = 32; + event.xclient.message_type = netWmState; + event.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD + event.xclient.data.l[1] = netWmStateFullscreen; + event.xclient.data.l[2] = 0; // No second property + event.xclient.data.l[3] = 1; // Normal window - ScopedXcbPtr wmStateError(xcb_request_check( - m_connection, - xcb_send_event_checked( - m_connection, - 0, - XCBDefaultRootWindow(m_connection), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - reinterpret_cast(&event) - ) - )); + int result = XSendEvent(m_display, + DefaultRootWindow(m_display), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); - if (wmStateError) - err() << "Setting fullscreen failed. Could not send \"_NET_WM_STATE\" event" << std::endl; + if (!result) + err() << "Setting fullscreen failed, could not send \"_NET_WM_STATE\" event" << std::endl; } } @@ -1488,8 +1195,8 @@ void WindowImplX11::switchToFullscreen() //////////////////////////////////////////////////////////// void WindowImplX11::setProtocols() { - xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); - xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); + Atom wmProtocols = getAtom("WM_PROTOCOLS"); + Atom wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); if (!wmProtocols) { @@ -1497,7 +1204,7 @@ void WindowImplX11::setProtocols() return; } - std::vector atoms; + std::vector atoms; if (wmDeleteWindow) { @@ -1508,8 +1215,8 @@ void WindowImplX11::setProtocols() err() << "Failed to request WM_DELETE_WINDOW atom." << std::endl; } - xcb_atom_t netWmPing = XCB_ATOM_NONE; - xcb_atom_t netWmPid = XCB_ATOM_NONE; + Atom netWmPing = None; + Atom netWmPid = None; if (ewmhSupported()) { @@ -1517,20 +1224,32 @@ void WindowImplX11::setProtocols() netWmPid = getAtom("_NET_WM_PID", true); } - ScopedXcbPtr error(NULL); - if (netWmPing && netWmPid) { uint32_t pid = getpid(); - if (changeWindowProperty(netWmPid, XCB_ATOM_CARDINAL, 32, 1, &pid)) - atoms.push_back(netWmPing); + XChangeProperty(m_display, + m_window, + netWmPid, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&pid), + 1); + + atoms.push_back(netWmPing); } if (!atoms.empty()) { - if (!changeWindowProperty(wmProtocols, XCB_ATOM_ATOM, 32, atoms.size(), &atoms[0])) - err() << "Failed to set window protocols" << std::endl; + XChangeProperty(m_display, + m_window, + wmProtocols, + XA_ATOM, + 32, + PropModeReplace, + reinterpret_cast(&atoms[0]), + atoms.size()); } else { @@ -1539,122 +1258,6 @@ void WindowImplX11::setProtocols() } -//////////////////////////////////////////////////////////// -void WindowImplX11::setMotifHints(unsigned long style) -{ - ScopedXcbPtr error(NULL); - - static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS"; - ScopedXcbPtr hintsAtomReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - 0, - MOTIF_WM_HINTS.size(), - MOTIF_WM_HINTS.c_str() - ), - &error - )); - - if (!error && hintsAtomReply) - { - static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; - static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1; - - //static const unsigned long MWM_DECOR_ALL = 1 << 0; - static const unsigned long MWM_DECOR_BORDER = 1 << 1; - static const unsigned long MWM_DECOR_RESIZEH = 1 << 2; - static const unsigned long MWM_DECOR_TITLE = 1 << 3; - static const unsigned long MWM_DECOR_MENU = 1 << 4; - static const unsigned long MWM_DECOR_MINIMIZE = 1 << 5; - static const unsigned long MWM_DECOR_MAXIMIZE = 1 << 6; - - //static const unsigned long MWM_FUNC_ALL = 1 << 0; - static const unsigned long MWM_FUNC_RESIZE = 1 << 1; - static const unsigned long MWM_FUNC_MOVE = 1 << 2; - static const unsigned long MWM_FUNC_MINIMIZE = 1 << 3; - static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4; - static const unsigned long MWM_FUNC_CLOSE = 1 << 5; - - struct MotifWMHints - { - uint32_t flags; - uint32_t functions; - uint32_t decorations; - int32_t inputMode; - uint32_t state; - }; - - MotifWMHints hints; - hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; - hints.decorations = 0; - hints.functions = 0; - hints.inputMode = 0; - hints.state = 0; - - if (style & Style::Titlebar) - { - hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; - hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; - } - if (style & Style::Resize) - { - hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; - hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; - } - if (style & Style::Close) - { - hints.decorations |= 0; - hints.functions |= MWM_FUNC_CLOSE; - } - - if (!changeWindowProperty(hintsAtomReply->atom, hintsAtomReply->atom, 32, 5, &hints)) - err() << "xcb_change_property failed, could not set window hints" << std::endl; - } - else - { - err() << "Failed to request _MOTIF_WM_HINTS atom." << std::endl; - } -} - - -//////////////////////////////////////////////////////////// -void WindowImplX11::setWMHints(const WMHints& hints) -{ - if (!changeWindowProperty(XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, sizeof(hints) / 4, &hints)) - sf::err() << "Failed to set WM_HINTS property" << std::endl; -} - - -//////////////////////////////////////////////////////////// -void WindowImplX11::setWMSizeHints(const WMSizeHints& hints) -{ - if (!changeWindowProperty(XCB_ATOM_WM_NORMAL_HINTS, XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) / 4, &hints)) - sf::err() << "Failed to set XCB_ATOM_WM_NORMAL_HINTS property" << std::endl; -} - - -//////////////////////////////////////////////////////////// -bool WindowImplX11::changeWindowProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void* data) -{ - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_change_property_checked( - m_connection, - XCB_PROP_MODE_REPLACE, - m_window, - property, - type, - format, - length, - data - ) - )); - - return !error; -} - - //////////////////////////////////////////////////////////// void WindowImplX11::initialize() { @@ -1663,16 +1266,14 @@ void WindowImplX11::initialize() if (m_inputMethod) { - m_inputContext = XCreateIC( - m_inputMethod, - XNClientWindow, - m_window, - XNFocusWindow, - m_window, - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - reinterpret_cast(NULL) - ); + m_inputContext = XCreateIC(m_inputMethod, + XNClientWindow, + m_window, + XNFocusWindow, + m_window, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + reinterpret_cast(NULL)); } else { @@ -1682,6 +1283,21 @@ void WindowImplX11::initialize() if (!m_inputContext) err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl; + Atom wmWindowType = getAtom("_NET_WM_WINDOW_TYPE", false); + Atom wmWindowTypeNormal = getAtom("_NET_WM_WINDOW_TYPE_NORMAL", false); + + if (wmWindowType && wmWindowTypeNormal) + { + XChangeProperty(m_display, + m_window, + wmWindowType, + XA_ATOM, + 32, + PropModeReplace, + reinterpret_cast(&wmWindowTypeNormal), + 1); + } + // Show the window setVisible(true); @@ -1692,7 +1308,7 @@ void WindowImplX11::initialize() createHiddenCursor(); // Flush the commands queue - xcb_flush(m_connection); + XFlush(m_display); // Add this window to the global list of windows (required for focus request) Lock lock(allWindowsMutex); @@ -1700,61 +1316,47 @@ void WindowImplX11::initialize() } +//////////////////////////////////////////////////////////// +void WindowImplX11::updateLastInputTime(::Time time) +{ + if (time && (time != m_lastInputTime)) + { + Atom netWmUserTime = getAtom("_NET_WM_USER_TIME", true); + + if(netWmUserTime) + { + XChangeProperty(m_display, + m_window, + netWmUserTime, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&time), + 1); + } + + m_lastInputTime = time; + } +} + + //////////////////////////////////////////////////////////// void WindowImplX11::createHiddenCursor() { - xcb_pixmap_t cursorPixmap = xcb_generate_id(m_connection); - // Create the cursor's pixmap (1x1 pixels) - ScopedXcbPtr createPixmapError(xcb_request_check( - m_connection, - xcb_create_pixmap( - m_connection, - 1, - cursorPixmap, - m_window, - 1, - 1 - ) - )); - - if (createPixmapError) - { - err() << "Failed to create pixmap for hidden cursor" << std::endl; - return; - } - - m_hiddenCursor = xcb_generate_id(m_connection); + Pixmap cursorPixmap = XCreatePixmap(m_display, m_window, 1, 1, 1); + GC graphicsContext = XCreateGC(m_display, cursorPixmap, 0, NULL); + XDrawPoint(m_display, cursorPixmap, graphicsContext, 0, 0); + XFreeGC(m_display, graphicsContext); // Create the cursor, using the pixmap as both the shape and the mask of the cursor - ScopedXcbPtr createCursorError(xcb_request_check( - m_connection, - xcb_create_cursor( - m_connection, - m_hiddenCursor, - cursorPixmap, - cursorPixmap, - 0, 0, 0, // Foreground RGB color - 0, 0, 0, // Background RGB color - 0, // X - 0 // Y - ) - )); - - if (createCursorError) - err() << "Failed to create hidden cursor" << std::endl; + XColor color; + color.flags = DoRed | DoGreen | DoBlue; + color.red = color.blue = color.green = 0; + m_hiddenCursor = XCreatePixmapCursor(m_display, cursorPixmap, cursorPixmap, &color, &color, 0, 0); // We don't need the pixmap any longer, free it - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap( - m_connection, - cursorPixmap - ) - )); - - if (freePixmapError) - err() << "Failed to free pixmap for hidden cursor" << std::endl; + XFreePixmap(m_display, cursorPixmap); } @@ -1831,25 +1433,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Try multiple times to grab the cursor for (unsigned int trial = 0; trial < maxTrialsCount; ++trial) { - sf::priv::ScopedXcbPtr error(NULL); + int result = XGrabPointer(m_display, m_window, True, None, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); - sf::priv::ScopedXcbPtr grabPointerReply(xcb_grab_pointer_reply( - m_connection, - xcb_grab_pointer( - m_connection, - true, - m_window, - XCB_NONE, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, - m_window, - XCB_NONE, - XCB_CURRENT_TIME - ), - &error - )); - - if (!error && grabPointerReply && (grabPointerReply->status == XCB_GRAB_STATUS_SUCCESS)) + if (result == GrabSuccess) { m_cursorGrabbed = true; break; @@ -1868,33 +1454,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) pushEvent(event); // If the window has been previously marked urgent (notification) as a result of a focus request, undo that - ScopedXcbPtr error(NULL); - - ScopedXcbPtr hintsReply(xcb_get_property_reply( - m_connection, - xcb_get_property(m_connection, 0, m_window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9), - &error - )); - - if (error || !hintsReply) + XWMHints* hints = XGetWMHints(m_display, m_window); + if (hints != NULL) { - err() << "Failed to get WM hints in XCB_FOCUS_IN" << std::endl; - break; + // Remove urgency (notification) flag from hints + hints->flags &= ~XUrgencyHint; + XSetWMHints(m_display, m_window, hints); + XFree(hints); } - WMHints* hints = reinterpret_cast(xcb_get_property_value(hintsReply.get())); - - if (!hints) - { - err() << "Failed to get WM hints in XCB_FOCUS_IN" << std::endl; - break; - } - - // Remove urgency (notification) flag from hints - hints->flags &= ~(1 << 8); - - setWMHints(*hints); - break; } @@ -1907,18 +1475,7 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Release cursor if (m_cursorGrabbed) - { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_ungrab_pointer_checked( - m_connection, - XCB_CURRENT_TIME - ) - )); - - if (error) - err() << "Failed to ungrab mouse cursor" << std::endl; - } + XUngrabPointer(m_display, CurrentTime); Event event; event.type = Event::LostFocus; @@ -1947,13 +1504,13 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Close event case ClientMessage: { - static xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); + static Atom wmProtocols = getAtom("WM_PROTOCOLS"); // Handle window manager protocol messages we support if (windowEvent.xclient.message_type == wmProtocols) { - static xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); - static xcb_atom_t netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : XCB_ATOM_NONE; + static Atom wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); + static Atom netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : None; if ((windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast(wmDeleteWindow)) { @@ -1965,9 +1522,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) else if (netWmPing && (windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast(netWmPing)) { // Handle the _NET_WM_PING message, send pong back to WM to show that we are responsive - windowEvent.xclient.window = XCBDefaultRootWindow(m_connection); + windowEvent.xclient.window = DefaultRootWindow(m_display); - XSendEvent(m_display, windowEvent.xclient.window, False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent); + XSendEvent(m_display, DefaultRootWindow(m_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent); } } break; @@ -2045,6 +1602,8 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) } } + updateLastInputTime(windowEvent.xkey.time); + break; } @@ -2102,6 +1661,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) } pushEvent(event); } + + updateLastInputTime(windowEvent.xbutton.time); + break; } @@ -2223,6 +1785,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) break; } + + // Window property change + case PropertyNotify: + { + if (!m_lastInputTime) + m_lastInputTime = windowEvent.xproperty.time; + + break; + } } return true; diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index 3c31f4e7..fd2295e9 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -31,8 +31,7 @@ #include #include #include -#include -#include +#include #include @@ -188,33 +187,6 @@ protected: private: - struct WMHints - { - int32_t flags; - uint32_t input; - int32_t initial_state; - xcb_pixmap_t icon_pixmap; - xcb_window_t icon_window; - int32_t icon_x; - int32_t icon_y; - xcb_pixmap_t icon_mask; - xcb_window_t window_group; - }; - - struct WMSizeHints - { - uint32_t flags; - int32_t x, y; - int32_t width, height; - int32_t min_width, min_height; - int32_t max_width, max_height; - int32_t width_inc, height_inc; - int32_t min_aspect_num, min_aspect_den; - int32_t max_aspect_num, max_aspect_den; - int32_t base_width, base_height; - uint32_t win_gravity; - }; - //////////////////////////////////////////////////////////// /// \brief Request the WM to make the current window active /// @@ -248,40 +220,12 @@ private: void setProtocols(); //////////////////////////////////////////////////////////// - /// \brief Set Motif WM hints + /// \brief Update the last time we received user input + /// + /// \param time Last time we received user input /// //////////////////////////////////////////////////////////// - void setMotifHints(unsigned long style); - - //////////////////////////////////////////////////////////// - /// \brief Set WM hints - /// - /// \param hints Hints - /// - //////////////////////////////////////////////////////////// - void setWMHints(const WMHints& hints); - - //////////////////////////////////////////////////////////// - /// \brief Set WM size hints - /// - /// \param hints Size hints - /// - //////////////////////////////////////////////////////////// - void setWMSizeHints(const WMSizeHints& hints); - - //////////////////////////////////////////////////////////// - /// \brief Change a XCB window property - /// - /// \param property Property to change - /// \param type Type of the property - /// \param format Format of the property - /// \param length Length of the new value - /// \param data The new value of the property - /// - /// \return True if successful, false if unsuccessful - /// - //////////////////////////////////////////////////////////// - bool changeWindowProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void* data); + void updateLastInputTime(::Time time); //////////////////////////////////////////////////////////// /// \brief Do some common initializations after the window has been created @@ -314,23 +258,23 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - xcb_window_t m_window; ///< xcb identifier defining our window - ::Display* m_display; ///< Pointer to the display - xcb_connection_t* m_connection; ///< Pointer to the xcb connection - xcb_screen_t* m_screen; ///< Screen identifier - XIM m_inputMethod; ///< Input method linked to the X display - XIC m_inputContext; ///< Input context used to get unicode input in our window - bool m_isExternal; ///< Tell whether the window has been created externally or by SFML - xcb_randr_get_screen_info_reply_t m_oldVideoMode; ///< Video mode in use before we switch to fullscreen - Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one - bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? - Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) - bool m_useSizeHints; ///< Is the size of the window fixed with size hints? - bool m_fullscreen; ///< Is the window in fullscreen? - bool m_cursorGrabbed; ///< Is the mouse cursor trapped? - bool m_windowMapped; ///< Has the window been mapped by the window manager? - xcb_pixmap_t m_iconPixmap; ///< The current icon pixmap if in use - xcb_pixmap_t m_iconMaskPixmap; ///< The current icon mask pixmap if in use + ::Window m_window; ///< X identifier defining our window + ::Display* m_display; ///< Pointer to the display + int m_screen; ///< Screen identifier + XIM m_inputMethod; ///< Input method linked to the X display + XIC m_inputContext; ///< Input context used to get unicode input in our window + bool m_isExternal; ///< Tell whether the window has been created externally or by SFML + int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen + Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one + bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? + Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) + bool m_useSizeHints; ///< Is the size of the window fixed with size hints? + bool m_fullscreen; ///< Is the window in fullscreen? + bool m_cursorGrabbed; ///< Is the mouse cursor trapped? + bool m_windowMapped; ///< Has the window been mapped by the window manager? + Pixmap m_iconPixmap; ///< The current icon pixmap if in use + Pixmap m_iconMaskPixmap; ///< The current icon mask pixmap if in use + ::Time m_lastInputTime; ///< Last time we received user input }; } // namespace priv From bc121e9bdaec38742eedf014a7585a8465709434 Mon Sep 17 00:00:00 2001 From: Marco Antognini Date: Fri, 16 Sep 2016 09:24:39 +0200 Subject: [PATCH 11/16] Fixed inconsistency between doc and impl on OS X for the grab feature Patch for #1133 and #1148. --- src/SFML/Window/OSX/SFOpenGLView+mouse.mm | 2 +- src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse.mm b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm index 63490814..5cc1f897 100644 --- a/src/SFML/Window/OSX/SFOpenGLView+mouse.mm +++ b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm @@ -230,7 +230,7 @@ //////////////////////////////////////////////////////// -(BOOL)isCursorCurrentlyGrabbed { - return [[self window] isKeyWindow] && (m_cursorGrabbed || m_fullscreen); + return [[self window] isKeyWindow] && m_cursorGrabbed; } diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h b/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h index f9b2ab75..27cd388c 100644 --- a/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h +++ b/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h @@ -70,8 +70,7 @@ /// \brief Check whether the cursor is grabbed or not /// /// The cursor is grabbed if the window is active (key) and -/// either it is in fullscreen mode or the user wants to -/// grab it. +/// the user wants to grab it. /// //////////////////////////////////////////////////////////// -(BOOL)isCursorCurrentlyGrabbed; From 3d7f354d25dfd423ce3c3d196956e5eb67b18a9a Mon Sep 17 00:00:00 2001 From: Mischa Aster Alff Date: Sat, 17 Sep 2016 17:41:10 +0200 Subject: [PATCH 12/16] Clarify documentation on Rect::contains function bounds --- include/SFML/Graphics/Rect.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/SFML/Graphics/Rect.hpp b/include/SFML/Graphics/Rect.hpp index 1b093880..782b7994 100644 --- a/include/SFML/Graphics/Rect.hpp +++ b/include/SFML/Graphics/Rect.hpp @@ -95,6 +95,9 @@ public: //////////////////////////////////////////////////////////// /// \brief Check if a point is inside the rectangle's area /// + /// This check is non-inclusive. If the point lies on the + /// edge of the rectangle, this function will return false. + /// /// \param x X coordinate of the point to test /// \param y Y coordinate of the point to test /// @@ -108,6 +111,9 @@ public: //////////////////////////////////////////////////////////// /// \brief Check if a point is inside the rectangle's area /// + /// This check is non-inclusive. If the point lies on the + /// edge of the rectangle, this function will return false. + /// /// \param point Point to test /// /// \return True if the point is inside, false otherwise From 6c0b7857f9c3c3c727c70570b47848d1709ec284 Mon Sep 17 00:00:00 2001 From: Mario Liebisch Date: Thu, 22 Sep 2016 15:26:07 +0200 Subject: [PATCH 13/16] Added some simple messaging when trying to build under Cygwin --- CMakeLists.txt | 5 +++++ cmake/Config.cmake | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index aeed46a3..fe33ac29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,9 @@ endmacro() # determine whether to create a debug or release build sfml_set_option(CMAKE_BUILD_TYPE Release STRING "Choose the type of build (Debug or Release)") +# Suppress Cygwin legacy warning +set(CMAKE_LEGACY_CYGWIN_WIN32 0) + # set Android specific options # define the minimum API level to be used @@ -31,6 +34,8 @@ if(NOT ANDROID_ABI) set(ANDROID_ABI armeabi-v7a) endif() +#end of Android specific options + # project name project(SFML) diff --git a/cmake/Config.cmake b/cmake/Config.cmake index 02e45ed0..cff54d00 100644 --- a/cmake/Config.cmake +++ b/cmake/Config.cmake @@ -64,6 +64,10 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android") # use the OpenGL ES implementation on Android set(OPENGL_ES 1) +# comparing CMAKE_SYSTEM_NAME with "CYGWIN" generates a false warning depending on the CMake version +# let's avoid it so the actual error is more visible +elseif(${CYGWIN}) + message(FATAL_ERROR "Unfortunately SFML doesn't support Cygwin's 'hybrid' status between both Windows and Linux derivatives.\nIf you insist on using the GCC, please use a standalone build of MinGW without the Cygwin environment instead.") else() message(FATAL_ERROR "Unsupported operating system or environment") return() From b74391cf971e1f5404407e867b3889fc52303ec8 Mon Sep 17 00:00:00 2001 From: binary1248 Date: Sun, 4 Oct 2015 17:03:43 +0200 Subject: [PATCH 14/16] Removed internal OpenGL contexts, reduced the number of temporary contexts that get created during runtime. --- include/SFML/Window/GlResource.hpp | 25 ++- src/SFML/Graphics/Font.cpp | 4 - src/SFML/Graphics/GLExtensions.cpp | 43 ++++- src/SFML/Graphics/RenderTextureImplFBO.cpp | 4 +- src/SFML/Graphics/Shader.cpp | 111 +++++------ src/SFML/Graphics/Texture.cpp | 79 ++++---- src/SFML/Window/Context.cpp | 80 +------- src/SFML/Window/EglContext.cpp | 10 +- src/SFML/Window/EglContext.hpp | 4 +- src/SFML/Window/GlContext.cpp | 206 +++++++++++++++------ src/SFML/Window/GlContext.hpp | 24 ++- src/SFML/Window/GlResource.cpp | 46 +++-- src/SFML/Window/OSX/SFContext.hpp | 4 +- src/SFML/Window/OSX/SFContext.mm | 29 ++- src/SFML/Window/Unix/Display.cpp | 7 + src/SFML/Window/Unix/GlxContext.cpp | 35 +++- src/SFML/Window/Unix/GlxContext.hpp | 4 +- src/SFML/Window/Win32/WglContext.cpp | 22 ++- src/SFML/Window/Win32/WglContext.hpp | 4 +- src/SFML/Window/iOS/EaglContext.hpp | 4 +- src/SFML/Window/iOS/EaglContext.mm | 21 ++- 21 files changed, 477 insertions(+), 289 deletions(-) diff --git a/include/SFML/Window/GlResource.hpp b/include/SFML/Window/GlResource.hpp index 9deb35a5..876f177c 100644 --- a/include/SFML/Window/GlResource.hpp +++ b/include/SFML/Window/GlResource.hpp @@ -29,10 +29,14 @@ // Headers //////////////////////////////////////////////////////////// #include +#include namespace sf { + +class Context; + //////////////////////////////////////////////////////////// /// \brief Base class for classes that require an OpenGL context /// @@ -54,10 +58,27 @@ protected: ~GlResource(); //////////////////////////////////////////////////////////// - /// \brief Make sure that a valid OpenGL context exists in the current thread + /// \brief RAII helper class to temporarily lock an available context for use /// //////////////////////////////////////////////////////////// - static void ensureGlContext(); + class SFML_WINDOW_API TransientContextLock : NonCopyable + { + public: + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + TransientContextLock(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~TransientContextLock(); + + private: + Context* m_context; ///< Temporary context, in case we needed to create one + }; }; } // namespace sf diff --git a/src/SFML/Graphics/Font.cpp b/src/SFML/Graphics/Font.cpp index f58454aa..b786b9d4 100644 --- a/src/SFML/Graphics/Font.cpp +++ b/src/SFML/Graphics/Font.cpp @@ -645,10 +645,6 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, f // Delete the FT glyph FT_Done_Glyph(glyphDesc); - // Force an OpenGL flush, so that the font's texture will appear updated - // in all contexts immediately (solves problems in multi-threaded apps) - glCheck(glFlush()); - // Done :) return glyph; } diff --git a/src/SFML/Graphics/GLExtensions.cpp b/src/SFML/Graphics/GLExtensions.cpp index 21f718b8..865fa38b 100644 --- a/src/SFML/Graphics/GLExtensions.cpp +++ b/src/SFML/Graphics/GLExtensions.cpp @@ -29,6 +29,14 @@ #include #include +#if !defined(GL_MAJOR_VERSION) + #define GL_MAJOR_VERSION 0x821B +#endif + +#if !defined(GL_MINOR_VERSION) + #define GL_MINOR_VERSION 0x821C +#endif + namespace sf { @@ -41,22 +49,41 @@ void ensureExtensionsInit() static bool initialized = false; if (!initialized) { - const Context* context = Context::getActiveContext(); - - if (!context) - return; + initialized = true; sfogl_LoadFunctions(); - ContextSettings settings = context->getSettings(); + // Retrieve the context version number + int majorVersion = 0; + int minorVersion = 0; - if ((settings.majorVersion < 1) || ((settings.majorVersion == 1) && (settings.minorVersion < 1))) + // Try the new way first + glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); + glGetIntegerv(GL_MINOR_VERSION, &minorVersion); + + if (glGetError() == GL_INVALID_ENUM) + { + // Try the old way + const GLubyte* version = glGetString(GL_VERSION); + if (version) + { + // The beginning of the returned string is "major.minor" (this is standard) + majorVersion = version[0] - '0'; + minorVersion = version[2] - '0'; + } + else + { + // Can't get the version number, assume 1.1 + majorVersion = 1; + minorVersion = 1; + } + } + + if ((majorVersion < 1) || ((majorVersion == 1) && (minorVersion < 1))) { err() << "sfml-graphics requires support for OpenGL 1.1 or greater" << std::endl; err() << "Ensure that hardware acceleration is enabled if available" << std::endl; } - - initialized = true; } #endif } diff --git a/src/SFML/Graphics/RenderTextureImplFBO.cpp b/src/SFML/Graphics/RenderTextureImplFBO.cpp index 3ce7006f..33adfb07 100644 --- a/src/SFML/Graphics/RenderTextureImplFBO.cpp +++ b/src/SFML/Graphics/RenderTextureImplFBO.cpp @@ -48,7 +48,7 @@ m_depthBuffer(0) //////////////////////////////////////////////////////////// RenderTextureImplFBO::~RenderTextureImplFBO() { - ensureGlContext(); + m_context->setActive(true); // Destroy the depth buffer if (m_depthBuffer) @@ -72,7 +72,7 @@ RenderTextureImplFBO::~RenderTextureImplFBO() //////////////////////////////////////////////////////////// bool RenderTextureImplFBO::isAvailable() { - ensureGlContext(); + TransientContextLock lock; // Make sure that extensions are initialized priv::ensureExtensionsInit(); diff --git a/src/SFML/Graphics/Shader.cpp b/src/SFML/Graphics/Shader.cpp index d8258aee..14a300c6 100644 --- a/src/SFML/Graphics/Shader.cpp +++ b/src/SFML/Graphics/Shader.cpp @@ -56,7 +56,8 @@ namespace { - sf::Mutex mutex; + sf::Mutex maxTextureUnitsMutex; + sf::Mutex isAvailableMutex; GLint checkMaxTextureUnits() { @@ -70,7 +71,7 @@ namespace GLint getMaxTextureUnits() { // TODO: Remove this lock when it becomes unnecessary in C++11 - sf::Lock lock(mutex); + sf::Lock lock(maxTextureUnitsMutex); static GLint maxUnits = checkMaxTextureUnits(); @@ -116,53 +117,6 @@ namespace return success; } - bool checkShadersAvailable() - { - // Create a temporary context in case the user checks - // before a GlResource is created, thus initializing - // the shared context - if (!sf::Context::getActiveContext()) - { - sf::Context context; - - // Make sure that extensions are initialized - sf::priv::ensureExtensionsInit(); - - bool available = GLEXT_multitexture && - GLEXT_shading_language_100 && - GLEXT_shader_objects && - GLEXT_vertex_shader && - GLEXT_fragment_shader; - - return available; - } - - // Make sure that extensions are initialized - sf::priv::ensureExtensionsInit(); - - bool available = GLEXT_multitexture && - GLEXT_shading_language_100 && - GLEXT_shader_objects && - GLEXT_vertex_shader && - GLEXT_fragment_shader; - - return available; - } - bool checkGeometryShadersAvailable() - { - // Create a temporary context in case the user checks - // before a GlResource is created, thus initializing - // the shared context - sf::Context context; - - // Make sure that extensions are initialized - sf::priv::ensureExtensionsInit(); - - bool available = checkShadersAvailable() && GLEXT_geometry_shader4; - - return available; - } - // Transforms an array of 2D vectors into a contiguous array of scalars template std::vector flatten(const sf::Vector2* vectorArray, std::size_t length) @@ -236,8 +190,6 @@ struct Shader::UniformBinder : private NonCopyable { if (currentProgram) { - ensureGlContext(); - // Enable program object glCheck(savedProgram = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT)); if (currentProgram != savedProgram) @@ -259,9 +211,10 @@ struct Shader::UniformBinder : private NonCopyable glCheck(GLEXT_glUseProgramObject(savedProgram)); } - GLEXT_GLhandle savedProgram; ///< Handle to the previously active program object - GLEXT_GLhandle currentProgram; ///< Handle to the program object of the modified sf::Shader instance - GLint location; ///< Uniform location, used by the surrounding sf::Shader code + TransientContextLock lock; ///< Lock to keep context active while uniform is bound + GLEXT_GLhandle savedProgram; ///< Handle to the previously active program object + GLEXT_GLhandle currentProgram; ///< Handle to the program object of the modified sf::Shader instance + GLint location; ///< Uniform location, used by the surrounding sf::Shader code }; @@ -278,7 +231,7 @@ m_uniforms () //////////////////////////////////////////////////////////// Shader::~Shader() { - ensureGlContext(); + TransientContextLock lock; // Destroy effect program if (m_shaderProgram) @@ -592,7 +545,7 @@ void Shader::setUniform(const std::string& name, const Texture& texture) { if (m_shaderProgram) { - ensureGlContext(); + TransientContextLock lock; // Find the location of the variable in the shader int location = getUniformLocation(name); @@ -627,7 +580,7 @@ void Shader::setUniform(const std::string& name, CurrentTextureType) { if (m_shaderProgram) { - ensureGlContext(); + TransientContextLock lock; // Find the location of the variable in the shader m_currentTexture = getUniformLocation(name); @@ -787,7 +740,7 @@ unsigned int Shader::getNativeHandle() const //////////////////////////////////////////////////////////// void Shader::bind(const Shader* shader) { - ensureGlContext(); + TransientContextLock lock; // Make sure that we can use shaders if (!isAvailable()) @@ -820,10 +773,26 @@ void Shader::bind(const Shader* shader) //////////////////////////////////////////////////////////// bool Shader::isAvailable() { - // TODO: Remove this lock when it becomes unnecessary in C++11 - Lock lock(mutex); + Lock lock(isAvailableMutex); - static bool available = checkShadersAvailable(); + static bool checked = false; + static bool available = false; + + if (!checked) + { + checked = true; + + TransientContextLock contextLock; + + // Make sure that extensions are initialized + sf::priv::ensureExtensionsInit(); + + available = GLEXT_multitexture && + GLEXT_shading_language_100 && + GLEXT_shader_objects && + GLEXT_vertex_shader && + GLEXT_fragment_shader; + } return available; } @@ -832,10 +801,22 @@ bool Shader::isAvailable() //////////////////////////////////////////////////////////// bool Shader::isGeometryAvailable() { - // TODO: Remove this lock when it becomes unnecessary in C++11 - Lock lock(mutex); + Lock lock(isAvailableMutex); - static bool available = checkGeometryShadersAvailable(); + static bool checked = false; + static bool available = false; + + if (!checked) + { + checked = true; + + TransientContextLock contextLock; + + // Make sure that extensions are initialized + sf::priv::ensureExtensionsInit(); + + available = isAvailable() && GLEXT_geometry_shader4; + } return available; } @@ -844,7 +825,7 @@ bool Shader::isGeometryAvailable() //////////////////////////////////////////////////////////// bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode) { - ensureGlContext(); + TransientContextLock lock; // First make sure that we can use shaders if (!isAvailable()) diff --git a/src/SFML/Graphics/Texture.cpp b/src/SFML/Graphics/Texture.cpp index a3e813f2..75e1313c 100644 --- a/src/SFML/Graphics/Texture.cpp +++ b/src/SFML/Graphics/Texture.cpp @@ -40,39 +40,19 @@ namespace { - sf::Mutex mutex; + sf::Mutex idMutex; + sf::Mutex maximumSizeMutex; // Thread-safe unique identifier generator, // is used for states cache (see RenderTarget) sf::Uint64 getUniqueId() { - sf::Lock lock(mutex); + sf::Lock lock(idMutex); static sf::Uint64 id = 1; // start at 1, zero is "no texture" return id++; } - - unsigned int checkMaximumTextureSize() - { - // Create a temporary context in case the user queries - // the size before a GlResource is created, thus - // initializing the shared context - if (!sf::Context::getActiveContext()) - { - sf::Context context; - - GLint size; - glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size)); - - return static_cast(size); - } - - GLint size; - glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size)); - - return static_cast(size); - } } @@ -118,7 +98,7 @@ Texture::~Texture() // Destroy the OpenGL texture if (m_texture) { - ensureGlContext(); + TransientContextLock lock; GLuint texture = static_cast(m_texture); glCheck(glDeleteTextures(1, &texture)); @@ -157,7 +137,7 @@ bool Texture::create(unsigned int width, unsigned int height) m_pixelsFlipped = false; m_fboAttachment = false; - ensureGlContext(); + TransientContextLock lock; // Create the OpenGL texture if it doesn't exist yet if (!m_texture) @@ -265,10 +245,6 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area) { update(image); - // Force an OpenGL flush, so that the texture will appear updated - // in all contexts immediately (solves problems in multi-threaded apps) - glCheck(glFlush()); - return true; } else @@ -290,6 +266,8 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area) // Create the texture and upload the pixels if (create(rectangle.width, rectangle.height)) { + TransientContextLock lock; + // Make sure that the current texture binding will be preserved priv::TextureSaver save; @@ -333,7 +311,7 @@ Image Texture::copyToImage() const if (!m_texture) return Image(); - ensureGlContext(); + TransientContextLock lock; // Make sure that the current texture binding will be preserved priv::TextureSaver save; @@ -424,7 +402,7 @@ void Texture::update(const Uint8* pixels, unsigned int width, unsigned int heigh if (pixels && m_texture) { - ensureGlContext(); + TransientContextLock lock; // Make sure that the current texture binding will be preserved priv::TextureSaver save; @@ -436,6 +414,10 @@ void Texture::update(const Uint8* pixels, unsigned int width, unsigned int heigh m_hasMipmap = false; m_pixelsFlipped = false; m_cacheId = getUniqueId(); + + // Force an OpenGL flush, so that the texture data will appear updated + // in all contexts immediately (solves problems in multi-threaded apps) + glCheck(glFlush()); } } @@ -470,6 +452,8 @@ void Texture::update(const Window& window, unsigned int x, unsigned int y) if (m_texture && window.setActive(true)) { + TransientContextLock lock; + // Make sure that the current texture binding will be preserved priv::TextureSaver save; @@ -480,6 +464,10 @@ void Texture::update(const Window& window, unsigned int x, unsigned int y) m_hasMipmap = false; m_pixelsFlipped = true; m_cacheId = getUniqueId(); + + // Force an OpenGL flush, so that the texture will appear updated + // in all contexts immediately (solves problems in multi-threaded apps) + glCheck(glFlush()); } } @@ -493,7 +481,7 @@ void Texture::setSmooth(bool smooth) if (m_texture) { - ensureGlContext(); + TransientContextLock lock; // Make sure that the current texture binding will be preserved priv::TextureSaver save; @@ -544,7 +532,7 @@ void Texture::setRepeated(bool repeated) if (m_texture) { - ensureGlContext(); + TransientContextLock lock; // Make sure that the current texture binding will be preserved priv::TextureSaver save; @@ -586,7 +574,7 @@ bool Texture::generateMipmap() if (!m_texture) return false; - ensureGlContext(); + TransientContextLock lock; // Make sure that extensions are initialized priv::ensureExtensionsInit(); @@ -613,7 +601,7 @@ void Texture::invalidateMipmap() if (!m_hasMipmap) return; - ensureGlContext(); + TransientContextLock lock; // Make sure that the current texture binding will be preserved priv::TextureSaver save; @@ -628,7 +616,7 @@ void Texture::invalidateMipmap() //////////////////////////////////////////////////////////// void Texture::bind(const Texture* texture, CoordinateType coordinateType) { - ensureGlContext(); + TransientContextLock lock; if (texture && texture->m_texture) { @@ -684,12 +672,21 @@ void Texture::bind(const Texture* texture, CoordinateType coordinateType) //////////////////////////////////////////////////////////// unsigned int Texture::getMaximumSize() { - // TODO: Remove this lock when it becomes unnecessary in C++11 - Lock lock(mutex); + Lock lock(maximumSizeMutex); - static unsigned int size = checkMaximumTextureSize(); + static bool checked = false; + static GLint size = 0; - return size; + if (!checked) + { + checked = true; + + TransientContextLock lock; + + glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size)); + } + + return static_cast(size); } @@ -722,7 +719,7 @@ unsigned int Texture::getNativeHandle() const //////////////////////////////////////////////////////////// unsigned int Texture::getValidSize(unsigned int size) { - ensureGlContext(); + TransientContextLock lock; // Make sure that extensions are initialized priv::ensureExtensionsInit(); diff --git a/src/SFML/Window/Context.cpp b/src/SFML/Window/Context.cpp index 2d51bbc2..7617e1af 100644 --- a/src/SFML/Window/Context.cpp +++ b/src/SFML/Window/Context.cpp @@ -28,24 +28,6 @@ #include #include #include -#include -#include -#include -#include - -#if defined(SFML_SYSTEM_WINDOWS) - - typedef const GLubyte* (APIENTRY *glGetStringiFuncType)(GLenum, GLuint); - -#else - - typedef const GLubyte* (*glGetStringiFuncType)(GLenum, GLuint); - -#endif - -#if !defined(GL_NUM_EXTENSIONS) - #define GL_NUM_EXTENSIONS 0x821D -#endif namespace @@ -99,70 +81,16 @@ const Context* Context::getActiveContext() //////////////////////////////////////////////////////////// -GlFunctionPointer Context::getFunction(const char* name) +bool Context::isExtensionAvailable(const char* name) { - return priv::GlContext::getFunction(name); + return priv::GlContext::isExtensionAvailable(name); } //////////////////////////////////////////////////////////// -bool Context::isExtensionAvailable(const char* name) +GlFunctionPointer Context::getFunction(const char* name) { - static std::vector extensions; - static bool loaded = false; - - if (!loaded) - { - const Context* context = getActiveContext(); - - if (!context) - return false; - - const char* extensionString = NULL; - - if(context->getSettings().majorVersion < 3) - { - // Try to load the < 3.0 way - extensionString = reinterpret_cast(glGetString(GL_EXTENSIONS)); - - do - { - const char* extension = extensionString; - - while(*extensionString && (*extensionString != ' ')) - extensionString++; - - extensions.push_back(std::string(extension, extensionString)); - } - while (*extensionString++); - } - else - { - // Try to load the >= 3.0 way - glGetStringiFuncType glGetStringiFunc = NULL; - glGetStringiFunc = reinterpret_cast(getFunction("glGetStringi")); - - if (glGetStringiFunc) - { - int numExtensions = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); - - if (numExtensions) - { - for (unsigned int i = 0; i < static_cast(numExtensions); ++i) - { - extensionString = reinterpret_cast(glGetStringiFunc(GL_EXTENSIONS, i)); - - extensions.push_back(extensionString); - } - } - } - } - - loaded = true; - } - - return std::find(extensions.begin(), extensions.end(), name) != extensions.end(); + return priv::GlContext::getFunction(name); } diff --git a/src/SFML/Window/EglContext.cpp b/src/SFML/Window/EglContext.cpp index f6686f17..03c41979 100644 --- a/src/SFML/Window/EglContext.cpp +++ b/src/SFML/Window/EglContext.cpp @@ -173,9 +173,12 @@ EglContext::~EglContext() //////////////////////////////////////////////////////////// -bool EglContext::makeCurrent() +bool EglContext::makeCurrent(bool current) { - return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context)); + if (current) + return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context)); + + return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); } @@ -209,6 +212,9 @@ void EglContext::createContext(EglContext* shared) else toShared = EGL_NO_CONTEXT; + if (toShared != EGL_NO_CONTEXT) + eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + // Create EGL context m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion)); } diff --git a/src/SFML/Window/EglContext.hpp b/src/SFML/Window/EglContext.hpp index 6df6a536..a889c3ac 100644 --- a/src/SFML/Window/EglContext.hpp +++ b/src/SFML/Window/EglContext.hpp @@ -83,10 +83,12 @@ public: /// \brief Activate the context as the current target /// for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); //////////////////////////////////////////////////////////// /// \brief Display what has been rendered to the context so far diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index b74725e7..8ae4b3ab 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -31,9 +31,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include #if !defined(SFML_OPENGL_ES) @@ -126,6 +130,8 @@ namespace // AMD drivers have issues with internal synchronization // We need to make sure that no operating system context // or pixel format operations are performed simultaneously + // This mutex is also used to protect the shared context + // from being locked on multiple threads sf::Mutex mutex; // This per-thread variable holds the current context for each thread @@ -134,35 +140,12 @@ namespace // The hidden, inactive context that will be shared with all other contexts ContextType* sharedContext = NULL; - // Internal contexts - sf::ThreadLocalPtr internalContext(NULL); - std::set internalContexts; - sf::Mutex internalContextsMutex; + // This per-thread variable is set to point to the shared context + // if we had to acquire it when a TransientContextLock was required + sf::ThreadLocalPtr currentSharedContext(NULL); - // Check if the internal context of the current thread is valid - bool hasInternalContext() - { - // The internal context can be null... - if (!internalContext) - return false; - - // ... or non-null but deleted from the list of internal contexts - sf::Lock lock(internalContextsMutex); - return internalContexts.find(internalContext) != internalContexts.end(); - } - - // Retrieve the internal context for the current thread - sf::Context* getInternalContext() - { - if (!hasInternalContext()) - { - internalContext = new sf::Context; - sf::Lock lock(internalContextsMutex); - internalContexts.insert(internalContext); - } - - return internalContext; - } + // Supported OpenGL extensions + std::vector extensions; } @@ -182,9 +165,53 @@ void GlContext::globalInit() sharedContext = new ContextType(NULL); sharedContext->initialize(ContextSettings()); - // This call makes sure that: - // - the shared context is inactive (it must never be) - // - another valid context is activated in the current thread + // Load our extensions vector + extensions.clear(); + + // Check whether a >= 3.0 context is available + int majorVersion = 0; + glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); + + if (glGetError() == GL_INVALID_ENUM) + { + // Try to load the < 3.0 way + const char* extensionString = reinterpret_cast(glGetString(GL_EXTENSIONS)); + + do + { + const char* extension = extensionString; + + while(*extensionString && (*extensionString != ' ')) + extensionString++; + + extensions.push_back(std::string(extension, extensionString)); + } + while (*extensionString++); + } + else + { + // Try to load the >= 3.0 way + glGetStringiFuncType glGetStringiFunc = NULL; + glGetStringiFunc = reinterpret_cast(getFunction("glGetStringi")); + + if (glGetStringiFunc) + { + int numExtensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + + if (numExtensions) + { + for (unsigned int i = 0; i < static_cast(numExtensions); ++i) + { + const char* extensionString = reinterpret_cast(glGetStringiFunc(GL_EXTENSIONS, i)); + + extensions.push_back(extensionString); + } + } + } + } + + // Deactivate the shared context so that others can activate it when necessary sharedContext->setActive(false); } @@ -200,31 +227,59 @@ void GlContext::globalCleanup() // Destroy the shared context delete sharedContext; sharedContext = NULL; - - // Destroy the internal contexts - Lock internalContextsLock(internalContextsMutex); - for (std::set::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it) - delete *it; - internalContexts.clear(); } //////////////////////////////////////////////////////////// -void GlContext::ensureContext() +void GlContext::acquireTransientContext() { - // If there's no active context on the current thread, activate an internal one - if (!currentContext) - getInternalContext()->setActive(true); + // If a capable context is already active on this thread + // there is no need to use the shared context for the operation + if (currentContext) + { + currentSharedContext = NULL; + return; + } + + mutex.lock(); + currentSharedContext = sharedContext; + sharedContext->setActive(true); +} + + +//////////////////////////////////////////////////////////// +void GlContext::releaseTransientContext() +{ + if (!currentSharedContext) + return; + + sharedContext->setActive(false); + mutex.unlock(); } //////////////////////////////////////////////////////////// GlContext* GlContext::create() { + // Make sure that there's an active context (context creation may need extensions, and thus a valid context) + assert(sharedContext != NULL); + Lock lock(mutex); - // Create the context - GlContext* context = new ContextType(sharedContext); + GlContext* context = NULL; + + // We don't use acquireTransientContext here since we have + // to ensure we have exclusive access to the shared context + // in order to make sure it is not active during context creation + { + sharedContext->setActive(true); + + // Create the context + context = new ContextType(sharedContext); + + sharedContext->setActive(false); + } + context->initialize(ContextSettings()); return context; @@ -235,12 +290,24 @@ GlContext* GlContext::create() GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) { // Make sure that there's an active context (context creation may need extensions, and thus a valid context) - ensureContext(); + assert(sharedContext != NULL); Lock lock(mutex); - // Create the context - GlContext* context = new ContextType(sharedContext, settings, owner, bitsPerPixel); + GlContext* context = NULL; + + // We don't use acquireTransientContext here since we have + // to ensure we have exclusive access to the shared context + // in order to make sure it is not active during context creation + { + sharedContext->setActive(true); + + // Create the context + context = new ContextType(sharedContext, settings, owner, bitsPerPixel); + + sharedContext->setActive(false); + } + context->initialize(settings); context->checkSettings(settings); @@ -252,12 +319,24 @@ GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* GlContext* GlContext::create(const ContextSettings& settings, unsigned int width, unsigned int height) { // Make sure that there's an active context (context creation may need extensions, and thus a valid context) - ensureContext(); + assert(sharedContext != NULL); Lock lock(mutex); - // Create the context - GlContext* context = new ContextType(sharedContext, settings, width, height); + GlContext* context = NULL; + + // We don't use acquireTransientContext here since we have + // to ensure we have exclusive access to the shared context + // in order to make sure it is not active during context creation + { + sharedContext->setActive(true); + + // Create the context + context = new ContextType(sharedContext, settings, width, height); + + sharedContext->setActive(false); + } + context->initialize(settings); context->checkSettings(settings); @@ -265,6 +344,13 @@ GlContext* GlContext::create(const ContextSettings& settings, unsigned int width } +//////////////////////////////////////////////////////////// +bool GlContext::isExtensionAvailable(const char* name) +{ + return std::find(extensions.begin(), extensions.end(), name) != extensions.end(); +} + + //////////////////////////////////////////////////////////// GlFunctionPointer GlContext::getFunction(const char* name) { @@ -287,7 +373,10 @@ GlContext::~GlContext() { // Deactivate the context before killing it, unless we're inside Cleanup() if (sharedContext) - setActive(false); + { + if (this == currentContext) + currentContext = NULL; + } } @@ -308,7 +397,7 @@ bool GlContext::setActive(bool active) Lock lock(mutex); // Activate the context - if (makeCurrent()) + if (makeCurrent(true)) { // Set it as the new current context for this thread currentContext = this; @@ -329,9 +418,18 @@ bool GlContext::setActive(bool active) { if (this == currentContext) { - // To deactivate the context, we actually activate another one so that we make - // sure that there is always an active context for subsequent graphics operations - return getInternalContext()->setActive(true); + Lock lock(mutex); + + // Deactivate the context + if (makeCurrent(false)) + { + currentContext = NULL; + return true; + } + else + { + return false; + } } else { diff --git a/src/SFML/Window/GlContext.hpp b/src/SFML/Window/GlContext.hpp index 8c4ce019..55b6c1f1 100644 --- a/src/SFML/Window/GlContext.hpp +++ b/src/SFML/Window/GlContext.hpp @@ -73,10 +73,16 @@ public: static void globalCleanup(); //////////////////////////////////////////////////////////// - /// \brief Ensures that an OpenGL context is active in the current thread + /// \brief Acquires a context for short-term use on the current thread /// //////////////////////////////////////////////////////////// - static void ensureContext(); + static void acquireTransientContext(); + + //////////////////////////////////////////////////////////// + /// \brief Releases a context after short-term use on the current thread + /// + //////////////////////////////////////////////////////////// + static void releaseTransientContext(); //////////////////////////////////////////////////////////// /// \brief Create a new context, not associated to a window @@ -120,6 +126,16 @@ public: static GlContext* create(const ContextSettings& settings, unsigned int width, unsigned int height); public: + //////////////////////////////////////////////////////////// + /// \brief Check whether a given OpenGL extension is available + /// + /// \param name Name of the extension to check for + /// + /// \return True if available, false if unavailable + /// + //////////////////////////////////////////////////////////// + static bool isExtensionAvailable(const char* name); + //////////////////////////////////////////////////////////// /// \brief Get the address of an OpenGL function /// @@ -197,10 +213,12 @@ protected: /// \brief Activate the context as the current target /// for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent() = 0; + virtual bool makeCurrent(bool current) = 0; //////////////////////////////////////////////////////////// /// \brief Evaluate a pixel format configuration diff --git a/src/SFML/Window/GlResource.cpp b/src/SFML/Window/GlResource.cpp index dfcbe7a9..a3cdddf6 100644 --- a/src/SFML/Window/GlResource.cpp +++ b/src/SFML/Window/GlResource.cpp @@ -27,6 +27,7 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include @@ -44,20 +45,15 @@ namespace sf //////////////////////////////////////////////////////////// GlResource::GlResource() { - { - // Protect from concurrent access - Lock lock(mutex); + // Protect from concurrent access + Lock lock(mutex); - // If this is the very first resource, trigger the global context initialization - if (count == 0) - priv::GlContext::globalInit(); + // If this is the very first resource, trigger the global context initialization + if (count == 0) + priv::GlContext::globalInit(); - // Increment the resources counter - count++; - } - - // Now make sure that there is an active OpenGL context in the current thread - priv::GlContext::ensureContext(); + // Increment the resources counter + count++; } @@ -77,9 +73,31 @@ GlResource::~GlResource() //////////////////////////////////////////////////////////// -void GlResource::ensureGlContext() +GlResource::TransientContextLock::TransientContextLock() : +m_context(0) { - priv::GlContext::ensureContext(); + Lock lock(mutex); + + if (count == 0) + { + m_context = new Context; + return; + } + + priv::GlContext::acquireTransientContext(); +} + + +//////////////////////////////////////////////////////////// +GlResource::TransientContextLock::~TransientContextLock() +{ + if (m_context) + { + delete m_context; + return; + } + + priv::GlContext::releaseTransientContext(); } } // namespace sf diff --git a/src/SFML/Window/OSX/SFContext.hpp b/src/SFML/Window/OSX/SFContext.hpp index 3e2a979d..75e67942 100644 --- a/src/SFML/Window/OSX/SFContext.hpp +++ b/src/SFML/Window/OSX/SFContext.hpp @@ -137,10 +137,12 @@ protected: /// \brief Activate the context as the current target /// for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); private: //////////////////////////////////////////////////////////// diff --git a/src/SFML/Window/OSX/SFContext.mm b/src/SFML/Window/OSX/SFContext.mm index 09700077..d458a6e1 100644 --- a/src/SFML/Window/OSX/SFContext.mm +++ b/src/SFML/Window/OSX/SFContext.mm @@ -104,6 +104,10 @@ m_window(0) SFContext::~SFContext() { [m_context clearDrawable]; + + if (m_context == [NSOpenGLContext currentContext]) + [NSOpenGLContext clearCurrentContext]; + [m_context release]; [m_view release]; // Might be nil but we don't care. @@ -124,10 +128,18 @@ GlFunctionPointer SFContext::getFunction(const char* name) //////////////////////////////////////////////////////////// -bool SFContext::makeCurrent() +bool SFContext::makeCurrent(bool current) { - [m_context makeCurrentContext]; - return m_context == [NSOpenGLContext currentContext]; // Should be true. + if (current) + { + [m_context makeCurrentContext]; + return m_context == [NSOpenGLContext currentContext]; // Should be true. + } + else + { + [NSOpenGLContext clearCurrentContext]; + return m_context != [NSOpenGLContext currentContext]; // Should be true. + } } @@ -257,6 +269,17 @@ void SFContext::createContext(SFContext* shared, // Use the shared context if one is given. NSOpenGLContext* sharedContext = shared != NULL ? shared->m_context : nil; + if (sharedContext != nil) + { + [NSOpenGLContext clearCurrentContext]; + + if (sharedContext == [NSOpenGLContext currentContext]) + { + sf::err() << "Failed to deactivate shared context before sharing" << std::endl; + return; + } + } + // Create the context. m_context = [[NSOpenGLContext alloc] initWithFormat:pixFmt shareContext:sharedContext]; diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp index fce86015..7445508f 100644 --- a/src/SFML/Window/Unix/Display.cpp +++ b/src/SFML/Window/Unix/Display.cpp @@ -26,6 +26,8 @@ // Headers //////////////////////////////////////////////////////////// #include +#include +#include #include #include #include @@ -38,6 +40,7 @@ namespace // The shared display and its reference counter Display* sharedDisplay = NULL; unsigned int referenceCount = 0; + sf::Mutex mutex; typedef std::map AtomMap; AtomMap atoms; @@ -50,6 +53,8 @@ namespace priv //////////////////////////////////////////////////////////// Display* OpenDisplay() { + Lock lock(mutex); + if (referenceCount == 0) { sharedDisplay = XOpenDisplay(NULL); @@ -71,6 +76,8 @@ Display* OpenDisplay() //////////////////////////////////////////////////////////// void CloseDisplay(Display* display) { + Lock lock(mutex); + assert(display == sharedDisplay); referenceCount--; diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index 8b4711d4..4efee9f0 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -211,7 +211,7 @@ GlFunctionPointer GlxContext::getFunction(const char* name) //////////////////////////////////////////////////////////// -bool GlxContext::makeCurrent() +bool GlxContext::makeCurrent(bool current) { if (!m_context) return false; @@ -222,13 +222,20 @@ bool GlxContext::makeCurrent() bool result = false; - if (m_pbuffer) + if (current) { - result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context); + if (m_pbuffer) + { + result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context); + } + else if (m_window) + { + result = glXMakeCurrent(m_display, m_window, m_context); + } } - else if (m_window) + else { - result = glXMakeCurrent(m_display, m_window, m_context); + result = glXMakeCurrent(m_display, None, NULL); } #if defined(GLX_DEBUGGING) @@ -686,6 +693,15 @@ void GlxContext::createContext(GlxContext* shared) // On an error, glXCreateContextAttribsARB will return 0 anyway GlxErrorHandler handler(m_display); + if (toShare) + { + if (!glXMakeCurrent(m_display, None, NULL)) + { + err() << "Failed to deactivate shared context before sharing" << std::endl; + return; + } + } + // Create the context m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, &attributes[0]); @@ -732,6 +748,15 @@ void GlxContext::createContext(GlxContext* shared) GlxErrorHandler handler(m_display); #endif + if (toShare) + { + if (!glXMakeCurrent(m_display, None, NULL)) + { + err() << "Failed to deactivate shared context before sharing" << std::endl; + return; + } + } + // Create the context, using the target window's visual m_context = glXCreateContext(m_display, visualInfo, toShare, true); diff --git a/src/SFML/Window/Unix/GlxContext.hpp b/src/SFML/Window/Unix/GlxContext.hpp index 959c3299..360906b6 100644 --- a/src/SFML/Window/Unix/GlxContext.hpp +++ b/src/SFML/Window/Unix/GlxContext.hpp @@ -94,10 +94,12 @@ public: //////////////////////////////////////////////////////////// /// \brief Activate the context as the current target for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); //////////////////////////////////////////////////////////// /// \brief Display what has been rendered to the context so far diff --git a/src/SFML/Window/Win32/WglContext.cpp b/src/SFML/Window/Win32/WglContext.cpp index 486946fe..a44c0c5e 100644 --- a/src/SFML/Window/Win32/WglContext.cpp +++ b/src/SFML/Window/Win32/WglContext.cpp @@ -200,9 +200,9 @@ GlFunctionPointer WglContext::getFunction(const char* name) //////////////////////////////////////////////////////////// -bool WglContext::makeCurrent() +bool WglContext::makeCurrent(bool current) { - return m_deviceContext && m_context && wglMakeCurrent(m_deviceContext, m_context); + return m_deviceContext && m_context && wglMakeCurrent(current ? m_deviceContext : NULL, current ? m_context : NULL); } @@ -599,6 +599,18 @@ void WglContext::createContext(WglContext* shared) attributes.push_back(0); attributes.push_back(0); + if (sharedContext) + { + static Mutex mutex; + Lock lock(mutex); + + if (!wglMakeCurrent(NULL, NULL)) + { + err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + return; + } + } + // Create the context m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]); } @@ -657,6 +669,12 @@ void WglContext::createContext(WglContext* shared) static Mutex mutex; Lock lock(mutex); + if (!wglMakeCurrent(NULL, NULL)) + { + err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + return; + } + if (!wglShareLists(sharedContext, m_context)) err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl; } diff --git a/src/SFML/Window/Win32/WglContext.hpp b/src/SFML/Window/Win32/WglContext.hpp index ceecc2df..9017c938 100644 --- a/src/SFML/Window/Win32/WglContext.hpp +++ b/src/SFML/Window/Win32/WglContext.hpp @@ -93,10 +93,12 @@ public: //////////////////////////////////////////////////////////// /// \brief Activate the context as the current target for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); //////////////////////////////////////////////////////////// /// \brief Display what has been rendered to the context so far diff --git a/src/SFML/Window/iOS/EaglContext.hpp b/src/SFML/Window/iOS/EaglContext.hpp index a3c48eac..2bcdc36e 100644 --- a/src/SFML/Window/iOS/EaglContext.hpp +++ b/src/SFML/Window/iOS/EaglContext.hpp @@ -126,10 +126,12 @@ protected: /// \brief Activate the context as the current target /// for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); private: diff --git a/src/SFML/Window/iOS/EaglContext.mm b/src/SFML/Window/iOS/EaglContext.mm index e0337188..37ab4c3c 100644 --- a/src/SFML/Window/iOS/EaglContext.mm +++ b/src/SFML/Window/iOS/EaglContext.mm @@ -107,6 +107,9 @@ EaglContext::~EaglContext() // Restore the previous context [EAGLContext setCurrentContext:previousContext]; + + if (m_context == [EAGLContext currentContext]) + [EAGLContext setCurrentContext:nil]; } } @@ -167,9 +170,12 @@ void EaglContext::recreateRenderBuffers(SFView* glView) //////////////////////////////////////////////////////////// -bool EaglContext::makeCurrent() +bool EaglContext::makeCurrent(bool current) { - return [EAGLContext setCurrentContext:m_context]; + if (current) + return [EAGLContext setCurrentContext:m_context]; + + return [EAGLContext setCurrentContext:nil]; } @@ -215,12 +221,18 @@ void EaglContext::createContext(EaglContext* shared, // Create the context if (shared) + { + [EAGLContext setCurrentContext:nil]; + m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]]; + } else + { m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; + } // Activate it - makeCurrent(); + makeCurrent(true); // Create the framebuffer (this is the only allowed drawable on iOS) glGenFramebuffersOES(1, &m_framebuffer); @@ -230,6 +242,9 @@ void EaglContext::createContext(EaglContext* shared, // Attach the context to the GL view for future updates window->getGlView().context = this; + + // Deactivate it + makeCurrent(false); } } // namespace priv From 303d07976c5e2b32f0c1d5dc22278c6f92ea6f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20D=C3=BCrrenberger?= Date: Mon, 24 Oct 2016 14:09:14 +0200 Subject: [PATCH 15/16] Added back GlResource::ensureGlContext() for ABI compatibility. --- include/SFML/Window/GlResource.hpp | 6 ++++++ src/SFML/Window/GlResource.cpp | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/include/SFML/Window/GlResource.hpp b/include/SFML/Window/GlResource.hpp index 876f177c..627ec30a 100644 --- a/include/SFML/Window/GlResource.hpp +++ b/include/SFML/Window/GlResource.hpp @@ -57,6 +57,12 @@ protected: //////////////////////////////////////////////////////////// ~GlResource(); + //////////////////////////////////////////////////////////// + /// \brief Empty function for ABI compatibility, use acquireTransientContext instead + /// + //////////////////////////////////////////////////////////// + static void ensureGlContext(); + //////////////////////////////////////////////////////////// /// \brief RAII helper class to temporarily lock an available context for use /// diff --git a/src/SFML/Window/GlResource.cpp b/src/SFML/Window/GlResource.cpp index a3cdddf6..e9a9ecc9 100644 --- a/src/SFML/Window/GlResource.cpp +++ b/src/SFML/Window/GlResource.cpp @@ -72,6 +72,13 @@ GlResource::~GlResource() } +//////////////////////////////////////////////////////////// +void GlResource::ensureGlContext() +{ + // Empty function for ABI compatibility, use acquireTransientContext instead +} + + //////////////////////////////////////////////////////////// GlResource::TransientContextLock::TransientContextLock() : m_context(0) From b3e44568dfbd76bd81dca3ef11d6f2763446bbb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20D=C3=BCrrenberger?= Date: Fri, 21 Oct 2016 17:07:22 +0200 Subject: [PATCH 16/16] Incremented SFML version number and added changes to the changelog. --- CMakeLists.txt | 2 +- changelog.txt | 51 +++++++++++++++++++++++++++++++++++++++-- include/SFML/Config.hpp | 2 +- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe33ac29..77589da7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake) # setup version numbers set(VERSION_MAJOR 2) set(VERSION_MINOR 4) -set(VERSION_PATCH 0) +set(VERSION_PATCH 1) # add the SFML header path include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/changelog.txt b/changelog.txt index ff61a532..666e2542 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,51 @@ +SFML 2.4.1 +========== + +Also available on the website: http://www.sfml-dev.org/changelog.php#sfml-2.4.1 + +General +======= + +* [kFreeBSD] Define SFML_OS_FREEBSD when compiling for kFreeBSD (#1129) +* [Window] Added some simple messaging when trying to build under Cygwin (#1153) + + +Window +====== + +Bugfixes +-------- +* Fixed stack overflow on GlContext creation with multiple threads (#989, #1002) +* Adjusted mouse cursor grab documentation (#1133) +* [iOS] Fixed orientation change not rescaling window size properly (#1049, #1050) +* [Linux] Fixed fullscreen issue (#921, #1138) +* [Linux] Switched from XCB back to Xlib for windowing (#1138) +* [Linux] Fixed window icon not showing up on some distros (#1087, #1088) +* [Linux] Fixed an issue where GNOME flags window unresponsive (#1089, #1138) +* [Linux] Fixed leak of XVisualInfo objects during GlxContext creation (#1135) +* [Linux] Fixed possible hang when setting visibility if external window sources (#1136) +* [OS X] Fixed inconsistency between doc and impl on OS X for the grab feature (#1133, #1148, #1150) +* [Windows] Fixed context memory leaks (#1143, #1002) + + +Graphics +======== + +Bugfixes +-------- +* Adjusted uniform error message (#1131) +* Clarify documentation on Rect::contains function bounds (#1151) + + +Network +======= + +Bugfixes +-------- +* Fixed a typo in comment for void unbind() (#1121) + + + SFML 2.4.0 ========== @@ -115,8 +163,6 @@ Bugfixes - - SFML 2.3.2 ========== @@ -152,6 +198,7 @@ Bugfixes * Secure function against random data return (#935, #942) + SFML 2.3.1 ========== diff --git a/include/SFML/Config.hpp b/include/SFML/Config.hpp index 497ef67f..9c68d84a 100644 --- a/include/SFML/Config.hpp +++ b/include/SFML/Config.hpp @@ -31,7 +31,7 @@ //////////////////////////////////////////////////////////// #define SFML_VERSION_MAJOR 2 #define SFML_VERSION_MINOR 4 -#define SFML_VERSION_PATCH 0 +#define SFML_VERSION_PATCH 1 ////////////////////////////////////////////////////////////