From 135c1716e877464db720265f37316cbb54ef13f2 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sun, 25 Nov 2012 11:54:45 +0100 Subject: [PATCH 1/8] Replaced Xlib by XCB implementation. * Added FindXCB.cmake script * Added AutoPointer wrapper for automatically free'ing pointers * Huge commit: Ported linux implementation of sfml-window to xcb * Xcb is now used for window creation, event loop etc * As GLX is linked to Xlib, that part of the implementation still uses Xlib. * Also, some keyboard related (such as XLookupString) stuff is still Xlib, as xcb does not have it (yet?). * Replaced some enums with the xcb equivalents --- cmake/Modules/FindXCB.cmake | 97 +++++ src/SFML/Window/CMakeLists.txt | 19 +- src/SFML/Window/Linux/AutoPointer.cpp | 44 +++ src/SFML/Window/Linux/AutoPointer.hpp | 132 +++++++ src/SFML/Window/Unix/Display.cpp | 28 ++ src/SFML/Window/Unix/Display.hpp | 35 +- src/SFML/Window/Unix/GlxContext.cpp | 219 +++++++---- src/SFML/Window/Unix/GlxContext.hpp | 11 +- src/SFML/Window/Unix/InputImpl.cpp | 75 ++-- src/SFML/Window/Unix/VideoModeImpl.cpp | 95 ++--- src/SFML/Window/Unix/WindowImplX11.cpp | 511 ++++++++++++++----------- src/SFML/Window/Unix/WindowImplX11.hpp | 31 +- 12 files changed, 862 insertions(+), 435 deletions(-) create mode 100644 cmake/Modules/FindXCB.cmake create mode 100644 src/SFML/Window/Linux/AutoPointer.cpp create mode 100644 src/SFML/Window/Linux/AutoPointer.hpp diff --git a/cmake/Modules/FindXCB.cmake b/cmake/Modules/FindXCB.cmake new file mode 100644 index 000000000..d69146104 --- /dev/null +++ b/cmake/Modules/FindXCB.cmake @@ -0,0 +1,97 @@ +# 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/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index 3046fec67..20fb2b313 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -69,6 +69,8 @@ if(SFML_OS_WINDOWS) add_definitions(-DUNICODE -D_UNICODE) elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD) set(PLATFORM_SRC + ${SRCROOT}/Linux/AutoPointer.cpp + ${SRCROOT}/Linux/AutoPointer.hpp ${SRCROOT}/Unix/Display.cpp ${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/InputImpl.cpp @@ -193,11 +195,11 @@ if(NOT SFML_OPENGL_ES) find_package(OpenGL REQUIRED) include_directories(${OPENGL_INCLUDE_DIR}) if(SFML_OS_LINUX OR SFML_OS_FREEBSD) - find_package(X11 REQUIRED) - if(NOT X11_Xrandr_FOUND) - message(FATAL_ERROR "Xrandr library not found") + find_package(XCB COMPONENTS xlib_xcb atom icccm image randr REQUIRED) + if(NOT LIBXCB_FOUND) + message(FATAL_ERROR "Xcb library not found") endif() - include_directories(${X11_INCLUDE_DIR}) + include_directories(${LIBXCB_INCLUDE_DIRS}) endif() endif() if(SFML_OPENGL_ES AND SFML_OS_LINUX) @@ -217,10 +219,11 @@ endif() # build the list of external libraries to link if(SFML_OS_WINDOWS) list(APPEND WINDOW_EXT_LIBS winmm gdi32) -elseif(SFML_OS_LINUX) - 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} ${X11_Xrandr_LIB} usbhid) +elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD) + list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) + if(SFML_OS_FREEBSD) + list(APPEND WINDOW_EXT_LIBS usbhid) + endif() 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/Linux/AutoPointer.cpp b/src/SFML/Window/Linux/AutoPointer.cpp new file mode 100644 index 000000000..e20d01d6b --- /dev/null +++ b/src/SFML/Window/Linux/AutoPointer.cpp @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2012 Laurent Gomila (laurent.gom@gmail.com) +// +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + +#include +#include + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +ErrorPointer::ErrorPointer(xcb_connection_t *&connection, xcb_void_cookie_t &cookie) + : AutoPointer(xcb_request_check(connection, cookie)) +{ +} + +} // namespace priv + +} // namespace sf diff --git a/src/SFML/Window/Linux/AutoPointer.hpp b/src/SFML/Window/Linux/AutoPointer.hpp new file mode 100644 index 000000000..0d9296823 --- /dev/null +++ b/src/SFML/Window/Linux/AutoPointer.hpp @@ -0,0 +1,132 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2012 Laurent Gomila (laurent.gom@gmail.com) +// +// 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 AUTOPOINTER_HPP +#define AUTOPOINTER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief Pointer Wrapper. Memory is automatically free'd +/// on deletion of the object. +/// +//////////////////////////////////////////////////////////// +template +class AutoPointer +{ +public: + //////////////////////////////////////////////////////////// + /// \brief Constructor + /// + //////////////////////////////////////////////////////////// + AutoPointer(T* ptr) + { + pointer = ptr; + } + + //////////////////////////////////////////////////////////// + /// \brief Constructor + /// + //////////////////////////////////////////////////////////// + AutoPointer() + : pointer(NULL) + { + } + + //////////////////////////////////////////////////////////// + /// \brief Destructor, frees the error pointer + /// + //////////////////////////////////////////////////////////// + ~AutoPointer() + { + free(pointer); + } + + //////////////////////////////////////////////////////////// + /// \brief Operator for error member access + /// + //////////////////////////////////////////////////////////// + T* operator->() const + { + return pointer; + } + + //////////////////////////////////////////////////////////// + /// \brief Assignment operator. Frees the previous pointer + /// + //////////////////////////////////////////////////////////// + T* operator=(T*& new_pointer) const + { + free(pointer); + pointer = new_pointer; + } + + T** operator&() + { + return &pointer; + } + + //////////////////////////////////////////////////////////// + /// \brief Check if reqeust succeeded + /// + /// \return true if reqeust succeeded + /// + //////////////////////////////////////////////////////////// + bool isNull() const + { + return pointer == NULL; + } + +private: + T* pointer; +}; + + +//////////////////////////////////////////////////////////// +/// \brief Wrapper for automatically creating and freeing +/// an error struct out of a cookie +/// +//////////////////////////////////////////////////////////// +class ErrorPointer : public AutoPointer +{ +public: + //////////////////////////////////////////////////////////// + /// \brief Construct the error pointer from a cookie + /// + //////////////////////////////////////////////////////////// + ErrorPointer(xcb_connection_t*& connection, xcb_void_cookie_t& cookie); +}; + +} // namespace priv + +} // namespace sf + +#endif // AUTOPOINTER_HPP diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp index aad1b2672..fddba3073 100644 --- a/src/SFML/Window/Unix/Display.cpp +++ b/src/SFML/Window/Unix/Display.cpp @@ -63,6 +63,13 @@ Display* OpenDisplay() } +//////////////////////////////////////////////////////////// +xcb_connection_t* OpenConnection() +{ + return XGetXCBConnection(OpenDisplay()); +} + + //////////////////////////////////////////////////////////// void CloseDisplay(Display* display) { @@ -73,6 +80,27 @@ void CloseDisplay(Display* display) XCloseDisplay(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; +} + } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp index df018b391..6d213f0bf 100644 --- a/src/SFML/Window/Unix/Display.hpp +++ b/src/SFML/Window/Unix/Display.hpp @@ -28,7 +28,7 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include +#include namespace sf @@ -47,13 +47,42 @@ namespace priv Display* OpenDisplay(); //////////////////////////////////////////////////////////// -/// \brief Release a reference to the shared +/// \brief Get the xcb connection of the shared Display /// -/// \param display Display to release +/// This function increments the reference count of the display, +/// it must be matched with a call to CloseDisplay. +/// +/// \return Pointer to the shared connection +/// +//////////////////////////////////////////////////////////// +xcb_connection_t* OpenConnection(); + +//////////////////////////////////////////////////////////// +/// \brief Release a reference to the shared display +/// +/// \param Display to release /// //////////////////////////////////////////////////////////// void CloseDisplay(Display* display); +//////////////////////////////////////////////////////////// +/// \brief Release a reference to the shared display +/// +/// \param Connection of display to release +/// +//////////////////////////////////////////////////////////// +void CloseConnection(xcb_connection_t* connection); + +//////////////////////////////////////////////////////////// +/// \brief Get screen of a display by index (equivalent to XScreenOfDisplay) +/// +/// \param The index of the screen +/// +/// \return Pointer to the screen +/// +//////////////////////////////////////////////////////////// +xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr); + } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index eac6099e2..b346753bc 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -44,18 +44,22 @@ m_ownsWindow(true) { // Open a connection with the X server m_display = OpenDisplay(); + m_connection = XGetXCBConnection(m_display); // Create a dummy window (disabled and hidden) - int screen = DefaultScreen(m_display); - m_window = XCreateWindow(m_display, - RootWindow(m_display, screen), - 0, 0, - 1, 1, - 0, - DefaultDepth(m_display, screen), - InputOutput, - DefaultVisual(m_display, screen), - 0, NULL); + xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display)); + m_window = xcb_generate_id(m_connection); + xcb_create_window( + m_connection, + screen->root_depth, + m_window, screen->root, + 0, 0, + 1, 1, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + screen->root_visual, + 0, NULL + ); // Create the context createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings()); @@ -71,6 +75,7 @@ m_ownsWindow(false) // Open a connection with the X server // (important: must be the same display as the owner window) m_display = OpenDisplay(); + m_connection = XGetXCBConnection(m_display); // Get the owner window and its device context m_window = static_cast< ::Window>(owner->getSystemHandle()); @@ -89,18 +94,22 @@ m_ownsWindow(true) { // Open a connection with the X server m_display = OpenDisplay(); + m_connection = XGetXCBConnection(m_display); // Create the hidden window - int screen = DefaultScreen(m_display); - m_window = XCreateWindow(m_display, - RootWindow(m_display, screen), - 0, 0, - width, height, - 0, - DefaultDepth(m_display, screen), - InputOutput, - DefaultVisual(m_display, screen), - 0, NULL); + xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display)); + m_window = xcb_generate_id(m_connection); + xcb_create_window( + m_connection, + screen->root_depth, + m_window, screen->root, + 0, 0, + width, height, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + screen->root_visual, + 0, NULL + ); // Create the context createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings); @@ -121,8 +130,8 @@ GlxContext::~GlxContext() // Destroy the window if we own it if (m_window && m_ownsWindow) { - XDestroyWindow(m_display, m_window); - XFlush(m_display); + xcb_destroy_window(m_connection, m_window); + xcb_flush(m_connection); } // Close the connection with the X server @@ -211,26 +220,88 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe } } - //////////////////////////////////////////////////////////// void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) { - XVisualInfo* visualInfo = NULL; - // Save the creation settings m_settings = settings; + // Get the attributes of the target window + XWindowAttributes windowAttributes; + if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0) + { + err() << "Failed to get the window attributes" << std::endl; + return; + } + + // Setup the visual infos to match + XVisualInfo tpl; + tpl.depth = windowAttributes.depth; + tpl.visualid = XVisualIDFromVisual(windowAttributes.visual); + tpl.screen = DefaultScreen(m_display); + + // Get all the visuals matching the template + int nbVisuals = 0; + XVisualInfo* visuals = XGetVisualInfo(m_display, VisualDepthMask | VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); + if (!visuals || (nbVisuals == 0)) + { + if (visuals) + XFree(visuals); + err() << "There is no valid visual for the selected screen" << std::endl; + return; + } + + // Find the best visual + int bestScore = 0xFFFF; + XVisualInfo* bestVisual = NULL; + for (int i = 0; i < nbVisuals; ++i) + { + // Get the current visual attributes + int RGBA, doubleBuffer, red, green, blue, alpha, depth, stencil, multiSampling, samples; + glXGetConfig(m_display, &visuals[i], GLX_RGBA, &RGBA); + glXGetConfig(m_display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer); + glXGetConfig(m_display, &visuals[i], GLX_RED_SIZE, &red); + glXGetConfig(m_display, &visuals[i], GLX_GREEN_SIZE, &green); + glXGetConfig(m_display, &visuals[i], GLX_BLUE_SIZE, &blue); + glXGetConfig(m_display, &visuals[i], GLX_ALPHA_SIZE, &alpha); + glXGetConfig(m_display, &visuals[i], GLX_DEPTH_SIZE, &depth); + glXGetConfig(m_display, &visuals[i], GLX_STENCIL_SIZE, &stencil); + glXGetConfig(m_display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling); + glXGetConfig(m_display, &visuals[i], GLX_SAMPLES_ARB, &samples); + + // First check the mandatory parameters + if ((RGBA == 0) || (doubleBuffer == 0)) + continue; + + // Evaluate the current configuration + int color = red + green + blue + alpha; + int score = evaluateFormat(bitsPerPixel, m_settings, color, depth, stencil, multiSampling ? samples : 0); + + // Keep it if it's better than the current best + if (score < bestScore) + { + bestScore = score; + bestVisual = &visuals[i]; + } + } + + // Make sure that we have found a visual + if (!bestVisual) + { + err() << "Failed to find a suitable pixel format for the window -- cannot create OpenGL context" << std::endl; + return; + } + // Get the context to share display lists with GLXContext toShare = shared ? shared->m_context : NULL; // Create the OpenGL context -- first try context versions >= 3.0 if it is requested (they require special code) - if (m_settings.majorVersion >= 3) + while (!m_context && (m_settings.majorVersion >= 3)) { const GLubyte* name = reinterpret_cast("glXCreateContextAttribsARB"); PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = reinterpret_cast(glXGetProcAddress(name)); if (glXCreateContextAttribsARB) { - // Select a GLXFB config that matches the requested context settings int nbConfigs = 0; int fbAttributes[] = { @@ -250,43 +321,38 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co None }; GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), fbAttributes, &nbConfigs); + if (configs && nbConfigs) { - while (!m_context && (m_settings.majorVersion >= 3)) + // Create the context + int attributes[] = { - // Create the context - int attributes[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, static_cast(m_settings.majorVersion), - GLX_CONTEXT_MINOR_VERSION_ARB, static_cast(m_settings.minorVersion), - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - 0, 0 - }; - m_context = glXCreateContextAttribsARB(m_display, configs[0], toShare, true, attributes); + GLX_CONTEXT_MAJOR_VERSION_ARB, static_cast(m_settings.majorVersion), + GLX_CONTEXT_MINOR_VERSION_ARB, static_cast(m_settings.minorVersion), + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + 0, 0 + }; + m_context = glXCreateContextAttribsARB(m_display, configs[0], toShare, true, attributes); + } - if (m_context) - { - // Ok: retrieve the config's visual - visualInfo = glXGetVisualFromFBConfig(m_display, configs[0]); - } - else - { - // If we couldn't create the context, lower the version number and try again -- stop at 3.0 - // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care - if (m_settings.minorVersion > 0) - { - // If the minor version is not 0, we decrease it and try again - m_settings.minorVersion--; - } - else - { - // If the minor version is 0, we decrease the major version - m_settings.majorVersion--; - m_settings.minorVersion = 9; - } - } - } + if (configs) XFree(configs); + } + + // If we couldn't create the context, lower the version number and try again -- stop at 3.0 + // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care + if (!m_context) + { + if (m_settings.minorVersion > 0) + { + // If the minor version is not 0, we decrease it and try again + m_settings.minorVersion--; + } + else + { + // If the minor version is 0, we decrease the major version + m_settings.majorVersion--; + m_settings.minorVersion = 9; } } } @@ -298,23 +364,7 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co m_settings.majorVersion = 2; m_settings.minorVersion = 0; - // Retrieve the attributes of the target window - XWindowAttributes windowAttributes; - if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0) - { - err() << "Failed to get the window attributes" << std::endl; - return; - } - - // Get its visual - XVisualInfo tpl; - tpl.screen = DefaultScreen(m_display); - tpl.visualid = XVisualIDFromVisual(windowAttributes.visual); - int nbVisuals = 0; - visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); - - // Create the context, using the target window's visual - m_context = glXCreateContext(m_display, visualInfo, toShare, true); + m_context = glXCreateContext(m_display, bestVisual, toShare, true); if (!m_context) { err() << "Failed to create an OpenGL context for this window" << std::endl; @@ -324,16 +374,21 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co // Update the creation settings from the chosen format int depth, stencil, multiSampling, samples; - glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth); - glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil); - glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); - glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples); + glXGetConfig(m_display, bestVisual, GLX_DEPTH_SIZE, &depth); + glXGetConfig(m_display, bestVisual, GLX_STENCIL_SIZE, &stencil); + glXGetConfig(m_display, bestVisual, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); + glXGetConfig(m_display, bestVisual, GLX_SAMPLES_ARB, &samples); m_settings.depthBits = static_cast(depth); m_settings.stencilBits = static_cast(stencil); m_settings.antialiasingLevel = multiSampling ? samples : 0; - // Free the visual info - XFree(visualInfo); + // Change the target window's colormap so that it matches the context's one + ::Window root = RootWindow(m_display, DefaultScreen(m_display)); + Colormap colorMap = XCreateColormap(m_display, root, bestVisual->visual, AllocNone); + XSetWindowColormap(m_display, m_window, colorMap); + + // Free the temporary visuals array + XFree(visuals); } } // namespace priv diff --git a/src/SFML/Window/Unix/GlxContext.hpp b/src/SFML/Window/Unix/GlxContext.hpp index 0b5982fb6..0e8bc402d 100644 --- a/src/SFML/Window/Unix/GlxContext.hpp +++ b/src/SFML/Window/Unix/GlxContext.hpp @@ -29,7 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include -#include +#include #include @@ -135,10 +135,11 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - ::Display* m_display; ///< Connection to the X server - ::Window m_window; ///< Window to which the context is attached - GLXContext m_context; ///< OpenGL context - bool m_ownsWindow; ///< Do we own the window associated to the context? + ::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 + bool m_ownsWindow; ///< Do we own the window associated to the context? }; } // namespace priv diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp index 8ff76976f..68e396b64 100644 --- a/src/SFML/Window/Unix/InputImpl.cpp +++ b/src/SFML/Window/Unix/InputImpl.cpp @@ -28,8 +28,10 @@ #include #include #include -#include +#include +#include #include +#include namespace sf @@ -149,20 +151,20 @@ bool InputImpl::isKeyPressed(Keyboard::Key key) // Open a connection with the X server Display* display = OpenDisplay(); + xcb_connection_t* connection = XGetXCBConnection(display); // Convert to keycode KeyCode keycode = XKeysymToKeycode(display, keysym); if (keycode != 0) { // Get the whole keyboard state - char keys[32]; - XQueryKeymap(display, keys); + AutoPointer keymap = xcb_query_keymap_reply(connection, xcb_query_keymap(connection), NULL); // Close the connection with the X server CloseDisplay(display); // Check our keycode - return (keys[keycode / 8] & (1 << (keycode % 8))) != 0; + return (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0; } else { @@ -186,29 +188,24 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button) { // Open a connection with the X server Display* display = OpenDisplay(); + xcb_connection_t* connection = XGetXCBConnection(display); - // we don't care about these but they are required - ::Window root, child; - int wx, wy; - int gx, gy; - - unsigned int buttons = 0; - XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &wx, &wy, &buttons); + // Get pointer mask + AutoPointer pointer = + xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL); // Close the connection with the X server CloseDisplay(display); switch (button) { - 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 + case Mouse::Left: return pointer->mask & XCB_BUTTON_MASK_1; + case Mouse::Right: return pointer->mask & XCB_BUTTON_MASK_3; + case Mouse::Middle: return pointer->mask & XCB_BUTTON_MASK_2; + case Mouse::XButton1: // not supported by X + case Mouse::XButton2: // not supported by X default: return false; } - - return false; } @@ -217,20 +214,15 @@ Vector2i InputImpl::getMousePosition() { // Open a connection with the X server Display* display = OpenDisplay(); + xcb_connection_t* connection = XGetXCBConnection(display); - // we don't care about these but they are required - ::Window root, child; - int x, y; - unsigned int buttons; - - int gx = 0; - int gy = 0; - XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &x, &y, &buttons); + AutoPointer pointer = + xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL); // Close the connection with the X server CloseDisplay(display); - return Vector2i(gx, gy); + return Vector2i(pointer->root_x, pointer->root_y); } @@ -241,21 +233,15 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo) if (handle) { // Open a connection with the X server - Display* display = OpenDisplay(); + xcb_connection_t* connection = OpenConnection(); - // we don't care about these but they are required - ::Window root, child; - int gx, gy; - unsigned int buttons; - - int x = 0; - int y = 0; - XQueryPointer(display, handle, &root, &child, &gx, &gy, &x, &y, &buttons); + AutoPointer pointer = + xcb_query_pointer_reply(connection, xcb_query_pointer(connection, handle), NULL); // Close the connection with the X server - CloseDisplay(display); + CloseConnection(connection); - return Vector2i(x, y); + return Vector2i(pointer->win_x, pointer->win_y); } else { @@ -269,9 +255,10 @@ void InputImpl::setMousePosition(const Vector2i& position) { // Open a connection with the X server Display* display = OpenDisplay(); + xcb_connection_t* connection = XGetXCBConnection(display); - XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y); - XFlush(display); + xcb_warp_pointer(connection, None, XDefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y); + xcb_flush(connection); // Close the connection with the X server CloseDisplay(display); @@ -282,17 +269,17 @@ void InputImpl::setMousePosition(const Vector2i& position) void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo) { // Open a connection with the X server - Display* display = OpenDisplay(); + xcb_connection_t* connection = OpenConnection(); WindowHandle handle = relativeTo.getSystemHandle(); if (handle) { - XWarpPointer(display, None, handle, 0, 0, 0, 0, position.x, position.y); - XFlush(display); + xcb_warp_pointer(connection, None, handle, 0, 0, 0, 0, position.x, position.y); + xcb_flush(connection); } // Close the connection with the X server - CloseDisplay(display); + CloseConnection(connection); } diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp index c7e620409..01ddf0363 100644 --- a/src/SFML/Window/Unix/VideoModeImpl.cpp +++ b/src/SFML/Window/Unix/VideoModeImpl.cpp @@ -28,8 +28,8 @@ #include #include #include -#include -#include +#include +#include #include @@ -44,63 +44,62 @@ std::vector VideoModeImpl::getFullscreenModes() // Open a connection with the X server Display* display = OpenDisplay(); + xcb_connection_t* connection = XGetXCBConnection(display); + if (display) { - // Retrieve the default screen number - int screen = DefaultScreen(display); + // Check if the XRandR extension is present + xcb_query_extension_cookie_t cookie = xcb_query_extension(connection, 5, "RANDR"); + + // Retrieve the default screen + xcb_screen_t* screen = XCBScreenOfDisplay(connection, DefaultScreen(display)); // Check if the XRandR extension is present - int version; - if (XQueryExtension(display, "RANDR", &version, &version, &version)) + xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(connection, cookie, NULL); + if (randr_ext->present) { // Get the current configuration - XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); - if (config) + xcb_generic_error_t* errors; + xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply( + connection, xcb_randr_get_screen_info(connection, screen->root), &errors); + if (! errors) { // Get the available screen sizes - int nbSizes; - XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); - if (sizes && (nbSizes > 0)) + xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config); + if (sizes && (config->nSizes > 0)) { // Get the list of supported depths - int nbDepths = 0; - int* depths = XListDepths(display, screen, &nbDepths); - if (depths && (nbDepths > 0)) + 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)) { - // Combine depths and sizes to fill the array of supported modes - for (int i = 0; i < nbDepths; ++i) + for (int j = 0; j < config->nSizes; ++j) { - for (int j = 0; j < nbSizes; ++j) - { - // Convert to VideoMode - VideoMode mode(sizes[j].width, sizes[j].height, depths[i]); + // Convert to VideoMode + VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth); - // 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); - } + // 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; } + // Free the configuration instance + free(errors); + free(config); } 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; } - + free(randr_ext); // Close the connection with the X server CloseDisplay(display); } @@ -121,37 +120,42 @@ VideoMode VideoModeImpl::getDesktopMode() // Open a connection with the X server Display* display = OpenDisplay(); + xcb_connection_t* connection = XGetXCBConnection(display); if (display) { - // Retrieve the default screen number - int screen = DefaultScreen(display); + xcb_query_extension_cookie_t cookie = xcb_query_extension(connection, 5, "RANDR"); + // Retrieve the default screen + xcb_screen_t* screen = XCBScreenOfDisplay(connection, DefaultScreen(display)); // Check if the XRandR extension is present - int version; - if (XQueryExtension(display, "RANDR", &version, &version, &version)) + xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(connection, cookie, NULL); + if (randr_ext->present) { // Get the current configuration - XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); - if (config) + xcb_generic_error_t* errors; + xcb_randr_get_screen_info_reply_t* config = + xcb_randr_get_screen_info_reply( + connection, xcb_randr_get_screen_info(connection, screen->root), &errors); + if (! errors) { // Get the current video mode - Rotation currentRotation; - int currentMode = XRRConfigCurrentConfiguration(config, ¤tRotation); + xcb_randr_rotation_t Rotation = (xcb_randr_rotation_t)config->rotation; + xcb_randr_mode_t currentMode = config->sizeID; // Get the available screen sizes - int nbSizes; - XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); + int nbSizes = xcb_randr_get_screen_info_sizes_length(config); + xcb_randr_screen_size_t* sizes= xcb_randr_get_screen_info_sizes(config); if (sizes && (nbSizes > 0)) - desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, DefaultDepth(display, screen)); - - // Free the configuration instance - XRRFreeScreenConfigInfo(config); + desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth); } else { // Failed to get the screen configuration err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl; } + // Free the configuration instance + free(errors); + free(config); } else { @@ -159,6 +163,7 @@ VideoMode VideoModeImpl::getDesktopMode() err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl; } + free(randr_ext); // Close the connection with the X server CloseDisplay(display); } diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 9e297576d..22ad33034 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -28,14 +28,15 @@ #include // important to be included first (conflict with None) #include #include +#include #include #include -#include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include @@ -104,6 +105,7 @@ m_useSizeHints(false) { // Open a connection with the X server m_display = OpenDisplay(); + XSetEventQueueOwner(m_display, XCBOwnsEventQueue); m_screen = DefaultScreen(m_display); // Save the window handle @@ -135,8 +137,14 @@ m_useSizeHints(false) { // Open a connection with the X server m_display = OpenDisplay(); - m_screen = DefaultScreen(m_display); - ::Window root = RootWindow(m_display, m_screen); + XSetEventQueueOwner(m_display, XCBOwnsEventQueue); + m_connection = XGetXCBConnection(m_display); + if (! m_connection) + { + err() << "Failed cast Display object to an XCB connection object" << std::endl; + return; + } + m_screen = DefaultScreen(m_display); // Compute position and size int left, top; @@ -162,22 +170,26 @@ m_useSizeHints(false) XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings); // Define the window attributes - XSetWindowAttributes attributes; - attributes.override_redirect = fullscreen; - attributes.event_mask = eventMask; - attributes.colormap = XCreateColormap(m_display, root, visualInfo.visual, AllocNone); + const uint32_t value_list[] = {fullscreen, eventMask}; // Create the window - m_window = XCreateWindow(m_display, - root, - left, top, - width, height, - 0, - visualInfo.depth, - InputOutput, - visualInfo.visual, - CWEventMask | CWOverrideRedirect | CWColormap, &attributes); - if (!m_window) + m_window = xcb_generate_id(m_connection); + + xcb_void_cookie_t cookie = xcb_create_window_checked( + m_connection, + XCB_COPY_FROM_PARENT, + m_window, + RootWindow(m_display, m_screen), + left, top, + width, height, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + XCB_COPY_FROM_PARENT, + XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT, + value_list); + + ErrorPointer errptr(m_connection, cookie); + if(! errptr.isNull()) { err() << "Failed to create window" << std::endl; return; @@ -189,7 +201,7 @@ m_useSizeHints(false) // Set the window's style (tell the windows manager to change our window's decorations and functions according to the requested style) if (!fullscreen) { - Atom WMHintsAtom = XInternAtom(m_display, "_MOTIF_WM_HINTS", false); + xcb_atom_t WMHintsAtom = xcb_atom_get(m_connection, "_MOTIF_WM_HINTS"); if (WMHintsAtom) { static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; @@ -212,11 +224,11 @@ m_useSizeHints(false) struct WMHints { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long inputMode; - unsigned long state; + uint32_t flags; + uint32_t functions; + uint32_t decorations; + int32_t inputMode; + uint32_t state; }; WMHints hints; @@ -241,19 +253,18 @@ m_useSizeHints(false) } const unsigned char* ptr = reinterpret_cast(&hints); - XChangeProperty(m_display, m_window, WMHintsAtom, WMHintsAtom, 32, PropModeReplace, ptr, 5); + xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, + WMHintsAtom, WM_HINTS, 32, 5, ptr); } // 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); + xcb_size_hints_t sizeHints; + sizeHints.flags = XCB_SIZE_HINT_P_MIN_SIZE | XCB_SIZE_HINT_P_MAX_SIZE; + sizeHints.min_width = sizeHints.max_width = width; + sizeHints.min_height = sizeHints.max_height = height; + xcb_set_wm_normal_hints(m_connection, m_window, &sizeHints); } } @@ -272,8 +283,8 @@ m_useSizeHints(false) // In fullscreen mode, we must grab keyboard and mouse inputs if (fullscreen) { - XGrabPointer(m_display, m_window, true, 0, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); - XGrabKeyboard(m_display, m_window, true, GrabModeAsync, GrabModeAsync, CurrentTime); + xcb_grab_pointer(m_connection, True, m_window, 0, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, m_window, XCB_NONE, XCB_CURRENT_TIME); + xcb_grab_keyboard(m_connection, True, m_window, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); } } @@ -286,7 +297,7 @@ WindowImplX11::~WindowImplX11() // Destroy the cursor if (m_hiddenCursor) - XFreeCursor(m_display, m_hiddenCursor); + xcb_free_cursor(m_connection, m_hiddenCursor); // Destroy the input context if (m_inputContext) @@ -295,8 +306,8 @@ WindowImplX11::~WindowImplX11() // Destroy the window if (m_window && !m_isExternal) { - XDestroyWindow(m_display, m_window); - XFlush(m_display); + xcb_destroy_window(m_connection, m_window); + xcb_flush(m_connection); } // Close the input method @@ -321,10 +332,10 @@ WindowHandle WindowImplX11::getSystemHandle() const //////////////////////////////////////////////////////////// void WindowImplX11::processEvents() { - XEvent event; - while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast(m_window))) + while(xcb_generic_event_t* event = xcb_poll_for_event(m_connection)) { processEvent(event); + free(event); } } @@ -332,80 +343,59 @@ void WindowImplX11::processEvents() //////////////////////////////////////////////////////////// Vector2i WindowImplX11::getPosition() const { - ::Window root, child; - int localX, localY, x, y; - unsigned int width, height, border, depth; - - XGetGeometry(m_display, m_window, &root, &localX, &localY, &width, &height, &border, &depth); - XTranslateCoordinates(m_display, m_window, root, localX, localY, &x, &y, &child); - - return Vector2i(x, y); + AutoPointer reply = + xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL); + return Vector2i(reply->x, reply->y); } //////////////////////////////////////////////////////////// void WindowImplX11::setPosition(const Vector2i& position) { - XMoveWindow(m_display, m_window, position.x, position.y); - XFlush(m_display); + uint32_t values[] = {position.x, position.y}; + xcb_configure_window(m_connection, m_window, + XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, + values); + xcb_flush(m_connection); } //////////////////////////////////////////////////////////// Vector2u WindowImplX11::getSize() const { - XWindowAttributes attributes; - XGetWindowAttributes(m_display, m_window, &attributes); - return Vector2u(attributes.width, attributes.height); + AutoPointer reply = + xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL); + return Vector2u(reply->width, reply->height); } //////////////////////////////////////////////////////////// void WindowImplX11::setSize(const Vector2u& size) { - // If we used size hint to fix the size of the window, we must update them - 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); - } - - XResizeWindow(m_display, m_window, size.x, size.y); - XFlush(m_display); + uint32_t values[] = {size.x, size.y}; + xcb_configure_window(m_connection, m_window, + XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, + values); + xcb_flush(m_connection); } //////////////////////////////////////////////////////////// void WindowImplX11::setTitle(const String& title) { - // Bare X11 has no Unicode window title support. - // There is however an option to tell the window manager your Unicode title via hints. - - // Convert to UTF-8 encoding. - std::basic_string utf8Title; - Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title)); - - // Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title. - Atom wmName = XInternAtom(m_display, "_NET_WM_NAME", False); - Atom useUtf8 = XInternAtom(m_display, "UTF8_STRING", False); - XChangeProperty(m_display, m_window, wmName, useUtf8, 8, - PropModeReplace, utf8Title.c_str(), utf8Title.size()); - - // Set the non-Unicode title as a fallback for window managers who don't support _NET_WM_NAME. - XStoreName(m_display, m_window, title.toAnsiString().c_str()); + const char* c_title = title.c_str(); + xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, + WM_NAME, STRING, + 8, title.length(), c_title); + xcb_flush(m_connection); } //////////////////////////////////////////////////////////// void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels) { - // 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)); + // X11 wants BGRA pixels : swap red and blue channels + Uint8 iconPixels[width * height * 4]; for (std::size_t i = 0; i < width * height; ++i) { iconPixels[i * 4 + 0] = pixels[i * 4 + 2]; @@ -415,20 +405,25 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 } // Create the icon pixmap - 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) + uint8_t defDepth = DefaultDepth(m_display, m_screen); + + xcb_pixmap_t iconPixmap = xcb_generate_id(m_connection); + xcb_create_pixmap(m_connection, defDepth, iconPixmap, RootWindow(m_display, m_screen), + width, height); + + xcb_gcontext_t iconGC = xcb_generate_id(m_connection); + xcb_create_gc(m_connection, iconGC, iconPixmap, 0, NULL); + xcb_void_cookie_t cookie = xcb_put_image_checked( + m_connection, XCB_IMAGE_FORMAT_Z_PIXMAP, iconPixmap, iconGC, + width, height, 0, 0, 0, defDepth, sizeof(iconPixels), iconPixels); + xcb_free_gc(m_connection, iconGC); + + ErrorPointer errptr(m_connection, cookie); + if (! errptr.isNull()) { - err() << "Failed to set the window's icon" << std::endl; + err() << "Failed to set the window's icon: Error code " << (int)errptr->error_code << std::endl; return; } - Pixmap iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth); - XGCValues values; - GC iconGC = XCreateGC(m_display, iconPixmap, 0, &values); - XPutImage(m_display, 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; @@ -447,17 +442,16 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 } } } - Pixmap maskPixmap = XCreatePixmapFromBitmapData(m_display, m_window, (char*)&maskPixels[0], width, height, 1, 0, 1); + xcb_pixmap_t maskPixmap = xcb_create_pixmap_from_bitmap_data(m_connection, m_window, (Uint8*)&maskPixels[0], width, height, 1, 0, 1, NULL); // Send our new icon to the window through the WMHints - XWMHints* hints = XAllocWMHints(); - hints->flags = IconPixmapHint | IconMaskHint; - hints->icon_pixmap = iconPixmap; - hints->icon_mask = maskPixmap; - XSetWMHints(m_display, m_window, hints); - XFree(hints); + xcb_wm_hints_t hints; + hints.flags = XCB_WM_HINT_ICON_PIXMAP | XCB_WM_HINT_ICON_MASK; + hints.icon_pixmap = iconPixmap; + hints.icon_mask = maskPixmap; + xcb_set_wm_hints(m_connection, m_window, &hints); - XFlush(m_display); + xcb_flush(m_connection); } @@ -465,19 +459,20 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 void WindowImplX11::setVisible(bool visible) { if (visible) - XMapWindow(m_display, m_window); + xcb_map_window(m_connection, m_window); else - XUnmapWindow(m_display, m_window); + xcb_unmap_window(m_connection, m_window); - XFlush(m_display); + xcb_flush(m_connection); } //////////////////////////////////////////////////////////// void WindowImplX11::setMouseCursorVisible(bool visible) { - XDefineCursor(m_display, m_window, visible ? None : m_hiddenCursor); - XFlush(m_display); + const uint32_t values = visible ? XCB_NONE : m_hiddenCursor; + xcb_change_window_attributes(m_connection, m_window, XCB_CW_CURSOR, &values); + xcb_flush(m_connection); } @@ -553,29 +548,37 @@ bool WindowImplX11::hasFocus() const void WindowImplX11::switchToFullscreen(const VideoMode& mode) { // Check if the XRandR extension is present - int version; - if (XQueryExtension(m_display, "RANDR", &version, &version, &version)) + xcb_query_extension_reply_t* randr_ext = + xcb_query_extension_reply(m_connection, xcb_query_extension(m_connection, 5, "RANDR"), NULL); + if (randr_ext->present) { + xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, m_screen); // Get the current configuration - XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); - if (config) + xcb_generic_error_t* errors; + xcb_randr_get_screen_info_reply_t* config = + xcb_randr_get_screen_info_reply(m_connection, + xcb_randr_get_screen_info(m_connection, screen->root), + &errors); + if (! errors) { - // Get the current rotation - Rotation currentRotation; - m_oldVideoMode = XRRConfigCurrentConfiguration(config, ¤tRotation); + // Save the current video mode before we switch to fullscreen + m_oldVideoMode = config->sizeID; // Get the available screen sizes - int nbSizes; - XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); - if (sizes && (nbSizes > 0)) + xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config); + if (sizes && (config->nSizes > 0)) { // Search a matching size - for (int i = 0; i < nbSizes; ++i) + for (int i = 0; i < config->nSizes; ++i) { if ((sizes[i].width == static_cast(mode.width)) && (sizes[i].height == static_cast(mode.height))) { // Switch to fullscreen mode - XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime); + xcb_randr_set_screen_config(m_connection, + screen->root, + config->timestamp, + config->config_timestamp, + i, config->rotation, config->rate); // Set "this" as the current fullscreen window fullscreenWindow = this; @@ -583,30 +586,36 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode) } } } - - // Free the configuration instance - XRRFreeScreenConfigInfo(config); } else { // Failed to get the screen configuration err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl; } + free(errors); + free(config); } else { // XRandr extension is not supported: we cannot use fullscreen mode err() << "Fullscreen is not supported, switching to window mode" << std::endl; } + free(randr_ext); } //////////////////////////////////////////////////////////// void WindowImplX11::initialize() { + // Make sure the "last key release" is initialized with invalid values + m_lastKeyReleaseEvent.response_type = -1; + m_lastKeyReleaseEvent.detail = 0; + m_lastKeyReleaseEvent.time = 0; + // Get the atom defining the close event - m_atomClose = XInternAtom(m_display, "WM_DELETE_WINDOW", false); - XSetWMProtocols(m_display, m_window, &m_atomClose, 1); + m_atomClose = xcb_atom_get(m_connection, "WM_DELETE_WINDOW"); + xcb_atom_t wmprotocolsAtom = xcb_atom_get(m_connection, "WM_PROTOCOLS"); + xcb_set_wm_protocols(m_connection, wmprotocolsAtom, m_window, 1, &m_atomClose); // Create the input context m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL); @@ -626,15 +635,15 @@ void WindowImplX11::initialize() err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl; // Show the window - XMapWindow(m_display, m_window); - XFlush(m_display); + xcb_map_window(m_connection, m_window); + xcb_flush(m_connection); // Create the hidden cursor createHiddenCursor(); // Flush the commands queue - XFlush(m_display); - + xcb_flush(m_connection); + // Add this window to the global list of windows (required for focus request) allWindows.push_back(this); } @@ -643,20 +652,19 @@ void WindowImplX11::initialize() //////////////////////////////////////////////////////////// void WindowImplX11::createHiddenCursor() { + xcb_pixmap_t cursorPixmap = xcb_generate_id(m_connection); + m_hiddenCursor = xcb_generate_id(m_connection); // Create the cursor's pixmap (1x1 pixels) - 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); + xcb_create_pixmap(m_connection, 1, cursorPixmap, m_window, 1, 1); // Create the cursor, using the pixmap as both the shape and the mask of the cursor - 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); + xcb_create_cursor(m_connection, m_hiddenCursor, cursorPixmap, cursorPixmap, + 0, 0, 0, // Fore color + 0, 0, 0, // Back color + 0, 0); // We don't need the pixmap any longer, free it - XFreePixmap(m_display, cursorPixmap); + xcb_free_pixmap(m_connection, cursorPixmap); } @@ -666,20 +674,27 @@ void WindowImplX11::cleanup() // Restore the previous video mode (in case we were running in fullscreen) if (fullscreenWindow == this) { - // Get current screen info - XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); - if (config) - { - // Get the current rotation - Rotation currentRotation; - XRRConfigCurrentConfiguration(config, ¤tRotation); + // Retrieve the default screen + xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, m_screen); + // Get current screen info + xcb_generic_error_t* errors; + xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply( + m_connection, xcb_randr_get_screen_info(m_connection, screen->root), &errors); + if (! errors) + { // Reset the video mode - XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime); + xcb_randr_set_screen_config(m_connection, + screen->root, + CurrentTime, + config->config_timestamp, + m_oldVideoMode, + config->rotation, config->rate); // Free the configuration instance - XRRFreeScreenConfigInfo(config); + free(config); } + free(errors); // Reset the fullscreen window fullscreenWindow = NULL; @@ -691,7 +706,7 @@ void WindowImplX11::cleanup() //////////////////////////////////////////////////////////// -bool WindowImplX11::processEvent(XEvent windowEvent) +bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) { // This function implements a workaround to properly discard // repeated key events when necessary. The problem is that the @@ -702,26 +717,34 @@ bool WindowImplX11::processEvent(XEvent windowEvent) // - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false // Detect repeated key events - // (code shamelessly taken from SDL) - if (windowEvent.type == KeyRelease) + if ((windowEvent->response_type == XCB_KEY_PRESS) || + (windowEvent->response_type == XCB_KEY_RELEASE)) { - // Check if there's a matching KeyPress event in the queue - XEvent nextEvent; - if (XPending(m_display)) + xcb_key_press_event_t* press = reinterpret_cast(windowEvent); + if (press->detail < 256) { - // Grab it but don't remove it from the queue, it still needs to be processed :) - XPeekEvent(m_display, &nextEvent); - if (nextEvent.type == KeyPress) - { - // Check if it is a duplicated event (same timestamp as the KeyRelease event) - if ((nextEvent.xkey.keycode == windowEvent.xkey.keycode) && - (nextEvent.xkey.time - windowEvent.xkey.time < 2)) - { - // If we don't want repeated events, remove the next KeyPress from the queue - if (!m_keyRepeat) - XNextEvent(m_display, &nextEvent); + // To detect if it is a repeated key event, we check the current state of the key. + // - If the state is "down", KeyReleased events must obviously be discarded. + // - KeyPress events are a little bit harder to handle: they depend on the EnableKeyRepeat state, + // and we need to properly forward the first one. + xcb_query_keymap_cookie_t cookie = xcb_query_keymap(m_connection); + AutoPointer keymap = xcb_query_keymap_reply(m_connection, + cookie, NULL); - // This KeyRelease is a repeated event and we don't want it + if (keymap->keys[press->detail / 8] & (1 << (press->detail % 8))) + { + // KeyRelease event + key down = repeated event --> discard + if (windowEvent->response_type == XCB_KEY_RELEASE) + { + m_lastKeyReleaseEvent = *press; + return false; + } + + // KeyPress event + key repeat disabled + matching KeyRelease event = repeated event --> discard + if ((windowEvent->response_type == XCB_KEY_PRESS) && !m_keyRepeat && + (m_lastKeyReleaseEvent.detail == press->detail) && + (m_lastKeyReleaseEvent.time == press->time)) + { return false; } } @@ -729,10 +752,10 @@ bool WindowImplX11::processEvent(XEvent windowEvent) } // Convert the X11 event to a sf::Event - switch (windowEvent.type) + switch (windowEvent->response_type & ~0x80) { // Destroy event - case DestroyNotify: + case XCB_DESTROY_NOTIFY: { // The window is about to be destroyed: we must cleanup resources cleanup(); @@ -740,7 +763,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent) } // Gain focus event - case FocusIn: + case XCB_FOCUS_IN: { // Update the input context if (m_inputContext) @@ -763,7 +786,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent) } // Lost focus event - case FocusOut: + case XCB_FOCUS_OUT: { // Update the input context if (m_inputContext) @@ -776,27 +799,22 @@ bool WindowImplX11::processEvent(XEvent windowEvent) } // Resize event - case ConfigureNotify: + case XCB_CONFIGURE_NOTIFY: { - // ConfigureNotify can be triggered for other reasons, check if the size has actually changed - if ((windowEvent.xconfigure.width != m_previousSize.x) || (windowEvent.xconfigure.height != m_previousSize.y)) - { - Event event; - event.type = Event::Resized; - event.size.width = windowEvent.xconfigure.width; - event.size.height = windowEvent.xconfigure.height; - pushEvent(event); - - m_previousSize.x = windowEvent.xconfigure.width; - m_previousSize.y = windowEvent.xconfigure.height; - } + xcb_configure_notify_event_t* e = reinterpret_cast(windowEvent); + Event event; + event.type = Event::Resized; + event.size.width = e->width; + event.size.height = e->height; + pushEvent(event); break; } // Close event - case ClientMessage: + case XCB_CLIENT_MESSAGE: { - if ((windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast(m_atomClose)) + xcb_client_message_event_t* e = reinterpret_cast(windowEvent); + if ((e->format == 32) && (e->data.data32[0]) == static_cast(m_atomClose)) { Event event; event.type = Event::Closed; @@ -806,34 +824,45 @@ bool WindowImplX11::processEvent(XEvent windowEvent) } // Key down event - case KeyPress: + case XCB_KEY_PRESS: { + xcb_key_press_event_t* e = reinterpret_cast(windowEvent); // Get the keysym of the key that has been pressed static XComposeStatus keyboard; char buffer[32]; KeySym symbol; - XLookupString(&windowEvent.xkey, buffer, sizeof(buffer), &symbol, &keyboard); + + // There is no xcb equivalent of XLookupString, so the xcb event + // has to be converted to an XEvent + XEvent fake_event; + fake_event.type = KeyPress; + fake_event.xany.display = m_display; + fake_event.xany.window = e->event; + fake_event.xkey.state = e->state; + fake_event.xkey.keycode = e->detail; + + XLookupString(&fake_event.xkey, buffer, sizeof(buffer), &symbol, &keyboard); // Fill the event parameters // TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping Event event; event.type = Event::KeyPressed; event.key.code = keysymToSF(symbol); - event.key.alt = windowEvent.xkey.state & Mod1Mask; - event.key.control = windowEvent.xkey.state & ControlMask; - event.key.shift = windowEvent.xkey.state & ShiftMask; - event.key.system = windowEvent.xkey.state & Mod4Mask; + event.key.alt = e->state & XCB_MOD_MASK_1; + event.key.control = e->state & XCB_MOD_MASK_CONTROL; + event.key.shift = e->state & XCB_MOD_MASK_SHIFT; + event.key.system = e->state & XCB_MOD_MASK_4; pushEvent(event); // Generate a TextEntered event - if (!XFilterEvent(&windowEvent, None)) + if (!XFilterEvent(&fake_event, None)) { #ifdef X_HAVE_UTF8_STRING if (m_inputContext) { Status status; Uint8 keyBuffer[16]; - int length = Xutf8LookupString(m_inputContext, &windowEvent.xkey, reinterpret_cast(keyBuffer), sizeof(keyBuffer), NULL, &status); + int length = Xutf8LookupString(m_inputContext, &fake_event.xkey, reinterpret_cast(keyBuffer), sizeof(keyBuffer), NULL, &status); if (length > 0) { Uint32 unicode = 0; @@ -852,7 +881,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent) { static XComposeStatus status; char keyBuffer[16]; - if (XLookupString(&windowEvent.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status)) + if (XLookupString(&fake_event.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status)) { Event textEvent; textEvent.type = Event::TextEntered; @@ -868,41 +897,53 @@ bool WindowImplX11::processEvent(XEvent windowEvent) // Key up event case KeyRelease: { + xcb_key_release_event_t* e = reinterpret_cast(windowEvent); // Get the keysym of the key that has been pressed char buffer[32]; KeySym symbol; - XLookupString(&windowEvent.xkey, buffer, 32, &symbol, NULL); + + // There is no xcb equivalent of XLookupString, so the xcb event + // has to be converted to an XEvent + XKeyEvent fake_event; + fake_event.display = m_display; + fake_event.state = e->state; + fake_event.keycode = e->detail; + XLookupString(&fake_event, buffer, 32, &symbol, NULL); // Fill the event parameters Event event; event.type = Event::KeyReleased; event.key.code = keysymToSF(symbol); - event.key.alt = windowEvent.xkey.state & Mod1Mask; - event.key.control = windowEvent.xkey.state & ControlMask; - event.key.shift = windowEvent.xkey.state & ShiftMask; - event.key.system = windowEvent.xkey.state & Mod4Mask; + event.key.alt = e->state & XCB_MOD_MASK_1; + event.key.control = e->state & XCB_MOD_MASK_CONTROL; + event.key.shift = e->state & XCB_MOD_MASK_SHIFT; + event.key.system = e->state & XCB_MOD_MASK_4; pushEvent(event); break; } // Mouse button pressed - case ButtonPress: + case XCB_BUTTON_PRESS: { - unsigned int button = windowEvent.xbutton.button; - if ((button == Button1) || (button == Button2) || (button == Button3) || (button == 8) || (button == 9)) + xcb_button_press_event_t* e = reinterpret_cast(windowEvent); + + // XXX: Why button 8 and 9? + xcb_button_t button = e->detail; + if ((button == XCB_BUTTON_INDEX_1) || (button == XCB_BUTTON_INDEX_2) + || (button == XCB_BUTTON_INDEX_3) || (button == 8) || (button == 9)) { Event event; event.type = Event::MouseButtonPressed; - event.mouseButton.x = windowEvent.xbutton.x; - event.mouseButton.y = windowEvent.xbutton.y; - switch (button) + event.mouseButton.x = e->event_x; + event.mouseButton.y = e->event_y; + switch(button) { - case Button1: event.mouseButton.button = Mouse::Left; break; - case Button2: event.mouseButton.button = Mouse::Middle; break; - case Button3: event.mouseButton.button = Mouse::Right; break; - case 8: event.mouseButton.button = Mouse::XButton1; break; - case 9: event.mouseButton.button = Mouse::XButton2; break; + case XCB_BUTTON_INDEX_1: event.mouseButton.button = Mouse::Left; break; + case XCB_BUTTON_INDEX_2: event.mouseButton.button = Mouse::Middle; break; + case XCB_BUTTON_INDEX_3: event.mouseButton.button = Mouse::Right; break; + case 8: event.mouseButton.button = Mouse::XButton1; break; + case 9: event.mouseButton.button = Mouse::XButton2; break; } pushEvent(event); } @@ -910,50 +951,54 @@ bool WindowImplX11::processEvent(XEvent windowEvent) } // Mouse button released - case ButtonRelease: + case XCB_BUTTON_RELEASE: { - unsigned int button = windowEvent.xbutton.button; - if ((button == Button1) || (button == Button2) || (button == Button3) || (button == 8) || (button == 9)) + xcb_button_release_event_t* e = reinterpret_cast(windowEvent); + + xcb_button_t button = e->detail; + if ((button == XCB_BUTTON_INDEX_1) || (button == XCB_BUTTON_INDEX_2) + || (button == XCB_BUTTON_INDEX_3) || (button == 8) || (button == 9)) { Event event; - event.type = Event::MouseButtonReleased; - event.mouseButton.x = windowEvent.xbutton.x; - event.mouseButton.y = windowEvent.xbutton.y; - switch (button) + event.type = Event::MouseButtonPressed; + event.mouseButton.x = e->event_x; + event.mouseButton.y = e->event_y; + switch(button) { - case Button1: event.mouseButton.button = Mouse::Left; break; - case Button2: event.mouseButton.button = Mouse::Middle; break; - case Button3: event.mouseButton.button = Mouse::Right; break; - case 8: event.mouseButton.button = Mouse::XButton1; break; - case 9: event.mouseButton.button = Mouse::XButton2; break; + case XCB_BUTTON_INDEX_1: event.mouseButton.button = Mouse::Left; break; + case XCB_BUTTON_INDEX_2: event.mouseButton.button = Mouse::Middle; break; + case XCB_BUTTON_INDEX_3: event.mouseButton.button = Mouse::Right; break; + case 8: event.mouseButton.button = Mouse::XButton1; break; + case 9: event.mouseButton.button = Mouse::XButton2; break; } pushEvent(event); } - else if ((button == Button4) || (button == Button5)) + else if ((button == XCB_BUTTON_INDEX_4) || (button == XCB_BUTTON_INDEX_5)) { Event event; event.type = Event::MouseWheelMoved; - event.mouseWheel.delta = windowEvent.xbutton.button == Button4 ? 1 : -1; - event.mouseWheel.x = windowEvent.xbutton.x; - event.mouseWheel.y = windowEvent.xbutton.y; + event.mouseWheel.delta = button == XCB_BUTTON_INDEX_4 ? 1 : -1; + event.mouseWheel.x = e->event_x; + event.mouseWheel.y = e->event_y; pushEvent(event); } break; } // Mouse moved - case MotionNotify: + case XCB_MOTION_NOTIFY: { + xcb_motion_notify_event_t* e = reinterpret_cast(windowEvent); Event event; event.type = Event::MouseMoved; - event.mouseMove.x = windowEvent.xmotion.x; - event.mouseMove.y = windowEvent.xmotion.y; + event.mouseMove.x = e->event_x; + event.mouseMove.y = e->event_y; pushEvent(event); break; } // Mouse entered - case EnterNotify: + case XCB_ENTER_NOTIFY: { if (windowEvent.xcrossing.mode == NotifyNormal) { @@ -965,7 +1010,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent) } // Mouse left - case LeaveNotify: + case XCB_LEAVE_NOTIFY: { if (windowEvent.xcrossing.mode == NotifyNormal) { @@ -989,7 +1034,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent) //////////////////////////////////////////////////////////// -Keyboard::Key WindowImplX11::keysymToSF(KeySym symbol) +Keyboard::Key WindowImplX11::keysymToSF(xcb_keysym_t symbol) { // First convert to uppercase (to avoid dealing with two different keysyms for the same key) KeySym lower, key; diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index d824492c8..7882aa01c 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include @@ -213,7 +213,7 @@ private: /// \return True if the event was processed, false if it was discarded /// //////////////////////////////////////////////////////////// - bool processEvent(XEvent windowEvent); + bool processEvent(xcb_generic_event_t *windowEvent); //////////////////////////////////////////////////////////// /// \brief Convert a X11 keysym to SFML key code @@ -223,23 +223,24 @@ private: /// \return Corresponding SFML key code /// //////////////////////////////////////////////////////////// - static Keyboard::Key keysymToSF(KeySym symbol); + static Keyboard::Key keysymToSF(xcb_keysym_t symbol); //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - ::Window m_window; ///< X11 structure 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 - Atom m_atomClose; ///< Atom used to identify the close event - int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen - Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, 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? + ::Window m_window; ///< X11 structure defining our window + ::Display* m_display; ///< Pointer to the display + xcb_connection_t* m_connection; ///< Pointer to the xcb connection + 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 + Atom m_atomClose; ///< Atom used to identify the close event + 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? }; } // namespace priv From c7549cd2921de5c40a3b908329a4ea95dc140e9a Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Thu, 24 Apr 2014 12:55:47 +0200 Subject: [PATCH 2/8] Adjusted and fixed XCB patch. * Adjusted xcb_icccm calls (for recent XCB versions). * Fixed wrong parameter order in xcb_icccm_set_wm_protocols call. * Fixed XCB_BUTTON_RELEASE spawning a MouseButtonPressed event. * Moved files from obsolete Linux/ to Unix/ directory. * Added m_useSizeHints fix. * setTitle() converts to UTF-8 before passing to XCB -> Unicode window title support. * Added XCB-util dependency. * Replaced XSelectInput. Obtaining XCB connection when taking window handle. * Adjusted X11 example for XCB. * Removed AutoPointer, replaced by direct XCB and free() calls. * Added key repeat workaround. --- examples/X11/X11.cpp | 138 +++++++------ src/SFML/Window/CMakeLists.txt | 4 +- src/SFML/Window/Linux/AutoPointer.cpp | 44 ---- src/SFML/Window/Linux/AutoPointer.hpp | 132 ------------ src/SFML/Window/Unix/InputImpl.cpp | 42 ++-- src/SFML/Window/Unix/WindowImplX11.cpp | 267 +++++++++++++++++-------- src/SFML/Window/Unix/WindowImplX11.hpp | 26 +-- 7 files changed, 307 insertions(+), 346 deletions(-) delete mode 100644 src/SFML/Window/Linux/AutoPointer.cpp delete mode 100644 src/SFML/Window/Linux/AutoPointer.hpp diff --git a/examples/X11/X11.cpp b/examples/X11/X11.cpp index 17bb44886..5b623d936 100644 --- a/examples/X11/X11.cpp +++ b/examples/X11/X11.cpp @@ -3,7 +3,8 @@ // Headers //////////////////////////////////////////////////////////// #include -#include +#include +#include #include #include #include @@ -55,9 +56,9 @@ void draw(sf::Window& window, float elapsedTime) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.f, 0.f, -200.f); - glRotatef(elapsedTime * 0.05f, 1.f, 0.f, 0.f); - glRotatef(elapsedTime * 0.03f, 0.f, 1.f, 0.f); - glRotatef(elapsedTime * 0.09f, 0.f, 0.f, 1.f); + glRotatef(elapsedTime * 10.f, 1.f, 0.f, 0.f); + glRotatef(elapsedTime * 6.f, 0.f, 1.f, 0.f); + glRotatef(elapsedTime * 18.f, 0.f, 0.f, 1.f); // Draw a cube glBegin(GL_QUADS); @@ -115,85 +116,104 @@ int main() if (!display) return EXIT_FAILURE; - // Get the default screen - int screen = DefaultScreen(display); + // Get the XCB connection for the opened display. + xcb_connection_t* xcbConnection = XGetXCBConnection(display); - // 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) + if (!xcbConnection) + { + sf::err() << "Failed to get the XCB connection for opened display." << std::endl; return EXIT_FAILURE; + } - // Set the window's name - XStoreName(display, window , "SFML Window"); + // 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; - // 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); + if (!screen) + { + sf::err() << "Failed to get the XCB screen." << std::endl; + return EXIT_FAILURE; + } - // Show our windows - XMapWindow(display, window); - XFlush(display); + // 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); // Create our SFML views - sf::Window SFMLView1(view1); - sf::Window SFMLView2(view2); + sf::Window sfmlView1(view1WindowId); + sf::Window sfmlView2(view2WindowId); // Create a clock for measuring elapsed time sf::Clock clock; // Initialize our views - initialize(SFMLView1); - initialize(SFMLView2); + initialize(sfmlView1); + initialize(sfmlView2); // Start the event loop bool running = true; + xcb_generic_event_t* event = NULL; + while (running) { - while (XPending(display)) + while (event = xcb_poll_for_event(xcbConnection)) { - // 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; - } + running = false; } // Draw something into our views - draw(SFMLView1, clock.getElapsedTime().asSeconds()); - draw(SFMLView2, clock.getElapsedTime().asSeconds() * 0.3f); + draw(sfmlView1, clock.getElapsedTime().asSeconds()); + draw(sfmlView2, clock.getElapsedTime().asSeconds() * 0.3f); // Display the views on screen - SFMLView1.display(); - SFMLView2.display(); + sfmlView1.display(); + 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 20fb2b313..94e471b29 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -69,8 +69,6 @@ if(SFML_OS_WINDOWS) add_definitions(-DUNICODE -D_UNICODE) elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD) set(PLATFORM_SRC - ${SRCROOT}/Linux/AutoPointer.cpp - ${SRCROOT}/Linux/AutoPointer.hpp ${SRCROOT}/Unix/Display.cpp ${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/InputImpl.cpp @@ -195,7 +193,7 @@ 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 atom icccm image randr REQUIRED) + find_package(XCB COMPONENTS xlib_xcb icccm image randr util REQUIRED) if(NOT LIBXCB_FOUND) message(FATAL_ERROR "Xcb library not found") endif() diff --git a/src/SFML/Window/Linux/AutoPointer.cpp b/src/SFML/Window/Linux/AutoPointer.cpp deleted file mode 100644 index e20d01d6b..000000000 --- a/src/SFML/Window/Linux/AutoPointer.cpp +++ /dev/null @@ -1,44 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2012 Laurent Gomila (laurent.gom@gmail.com) -// -// 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. -// -//////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// - -#include -#include - -namespace sf -{ -namespace priv -{ -//////////////////////////////////////////////////////////// -ErrorPointer::ErrorPointer(xcb_connection_t *&connection, xcb_void_cookie_t &cookie) - : AutoPointer(xcb_request_check(connection, cookie)) -{ -} - -} // namespace priv - -} // namespace sf diff --git a/src/SFML/Window/Linux/AutoPointer.hpp b/src/SFML/Window/Linux/AutoPointer.hpp deleted file mode 100644 index 0d9296823..000000000 --- a/src/SFML/Window/Linux/AutoPointer.hpp +++ /dev/null @@ -1,132 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2012 Laurent Gomila (laurent.gom@gmail.com) -// -// 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 AUTOPOINTER_HPP -#define AUTOPOINTER_HPP - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include - -namespace sf -{ -namespace priv -{ -//////////////////////////////////////////////////////////// -/// \brief Pointer Wrapper. Memory is automatically free'd -/// on deletion of the object. -/// -//////////////////////////////////////////////////////////// -template -class AutoPointer -{ -public: - //////////////////////////////////////////////////////////// - /// \brief Constructor - /// - //////////////////////////////////////////////////////////// - AutoPointer(T* ptr) - { - pointer = ptr; - } - - //////////////////////////////////////////////////////////// - /// \brief Constructor - /// - //////////////////////////////////////////////////////////// - AutoPointer() - : pointer(NULL) - { - } - - //////////////////////////////////////////////////////////// - /// \brief Destructor, frees the error pointer - /// - //////////////////////////////////////////////////////////// - ~AutoPointer() - { - free(pointer); - } - - //////////////////////////////////////////////////////////// - /// \brief Operator for error member access - /// - //////////////////////////////////////////////////////////// - T* operator->() const - { - return pointer; - } - - //////////////////////////////////////////////////////////// - /// \brief Assignment operator. Frees the previous pointer - /// - //////////////////////////////////////////////////////////// - T* operator=(T*& new_pointer) const - { - free(pointer); - pointer = new_pointer; - } - - T** operator&() - { - return &pointer; - } - - //////////////////////////////////////////////////////////// - /// \brief Check if reqeust succeeded - /// - /// \return true if reqeust succeeded - /// - //////////////////////////////////////////////////////////// - bool isNull() const - { - return pointer == NULL; - } - -private: - T* pointer; -}; - - -//////////////////////////////////////////////////////////// -/// \brief Wrapper for automatically creating and freeing -/// an error struct out of a cookie -/// -//////////////////////////////////////////////////////////// -class ErrorPointer : public AutoPointer -{ -public: - //////////////////////////////////////////////////////////// - /// \brief Construct the error pointer from a cookie - /// - //////////////////////////////////////////////////////////// - ErrorPointer(xcb_connection_t*& connection, xcb_void_cookie_t& cookie); -}; - -} // namespace priv - -} // namespace sf - -#endif // AUTOPOINTER_HPP diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp index 68e396b64..d6aa5fb41 100644 --- a/src/SFML/Window/Unix/InputImpl.cpp +++ b/src/SFML/Window/Unix/InputImpl.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -158,13 +157,16 @@ bool InputImpl::isKeyPressed(Keyboard::Key key) if (keycode != 0) { // Get the whole keyboard state - AutoPointer keymap = xcb_query_keymap_reply(connection, xcb_query_keymap(connection), NULL); + xcb_query_keymap_reply_t* keymap = xcb_query_keymap_reply(connection, xcb_query_keymap(connection), NULL); // Close the connection with the X server CloseDisplay(display); // Check our keycode - return (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0; + bool isPressed = (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0; + + free(keymap); + return isPressed; } else { @@ -191,21 +193,25 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button) xcb_connection_t* connection = XGetXCBConnection(display); // Get pointer mask - AutoPointer pointer = - xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL); + xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL); // Close the connection with the X server CloseDisplay(display); + bool result = false; + switch (button) { - case Mouse::Left: return pointer->mask & XCB_BUTTON_MASK_1; - case Mouse::Right: return pointer->mask & XCB_BUTTON_MASK_3; - case Mouse::Middle: return pointer->mask & XCB_BUTTON_MASK_2; + case Mouse::Left: result = pointer->mask & XCB_BUTTON_MASK_1; + case Mouse::Right: result = pointer->mask & XCB_BUTTON_MASK_3; + case Mouse::Middle: result = pointer->mask & XCB_BUTTON_MASK_2; case Mouse::XButton1: // not supported by X case Mouse::XButton2: // not supported by X - default: return false; + default: result = false; } + + free(pointer); + return result; } @@ -216,13 +222,16 @@ Vector2i InputImpl::getMousePosition() Display* display = OpenDisplay(); xcb_connection_t* connection = XGetXCBConnection(display); - AutoPointer pointer = - xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL); + xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL); // Close the connection with the X server CloseDisplay(display); - return Vector2i(pointer->root_x, pointer->root_y); + // Prepare result. + Vector2i result(pointer->root_x, pointer->root_y); + free(pointer); + + return result; } @@ -235,13 +244,16 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo) // Open a connection with the X server xcb_connection_t* connection = OpenConnection(); - AutoPointer pointer = - xcb_query_pointer_reply(connection, xcb_query_pointer(connection, handle), NULL); + xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, handle), NULL); // Close the connection with the X server CloseConnection(connection); - return Vector2i(pointer->win_x, pointer->win_y); + // Prepare result. + Vector2i result(pointer->win_x, pointer->win_y); + free(pointer); + + return result; } else { diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 22ad33034..98b8e0ab3 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -28,20 +28,25 @@ #include // important to be included first (conflict with None) #include #include -#include #include #include #include #include +#include #include #include #include +#include #include +#include +#include +#include #include #include #include #include #include +#include #ifdef SFML_OPENGL_ES #include @@ -106,6 +111,14 @@ m_useSizeHints(false) // Open a connection with the X server m_display = OpenDisplay(); XSetEventQueueOwner(m_display, XCBOwnsEventQueue); + m_connection = XGetXCBConnection(m_display); + + if (!m_connection) + { + err() << "Failed cast Display object to an XCB connection object" << std::endl; + return; + } + m_screen = DefaultScreen(m_display); // Save the window handle @@ -114,7 +127,12 @@ m_useSizeHints(false) if (m_window) { // Make sure the window is listening to all the required events - XSelectInput(m_display, m_window, eventMask & ~ButtonPressMask); + const uint32_t value_list[] = {eventMask}; + + xcb_change_window_attributes(m_connection, + m_window, + XCB_CW_EVENT_MASK, + value_list); // Do some common initializations initialize(); @@ -188,8 +206,11 @@ m_useSizeHints(false) XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT, value_list); - ErrorPointer errptr(m_connection, cookie); - if(! errptr.isNull()) + xcb_generic_error_t* errptr = xcb_request_check(m_connection, cookie); + bool createWindowFailed = (errptr != NULL); + free(errptr); + + if (createWindowFailed) { err() << "Failed to create window" << std::endl; return; @@ -201,8 +222,20 @@ m_useSizeHints(false) // Set the window's style (tell the windows manager to change our window's decorations and functions according to the requested style) if (!fullscreen) { - xcb_atom_t WMHintsAtom = xcb_atom_get(m_connection, "_MOTIF_WM_HINTS"); - if (WMHintsAtom) + static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS"; + xcb_intern_atom_cookie_t hintsAtomRequest = xcb_intern_atom( + m_connection, + 0, + MOTIF_WM_HINTS.size(), + MOTIF_WM_HINTS.c_str() + ); + xcb_intern_atom_reply_t* hintsAtomReply = xcb_intern_atom_reply( + m_connection, + hintsAtomRequest, + NULL + ); + + if (hintsAtomReply) { static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1; @@ -254,17 +287,18 @@ m_useSizeHints(false) const unsigned char* ptr = reinterpret_cast(&hints); xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, - WMHintsAtom, WM_HINTS, 32, 5, ptr); + hintsAtomReply->atom, XA_WM_HINTS, 32, 5, ptr); } // This is a hack to force some windows managers to disable resizing if (!(style & Style::Resize)) { + m_useSizeHints = true; xcb_size_hints_t sizeHints; - sizeHints.flags = XCB_SIZE_HINT_P_MIN_SIZE | XCB_SIZE_HINT_P_MAX_SIZE; + sizeHints.flags = XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE; sizeHints.min_width = sizeHints.max_width = width; sizeHints.min_height = sizeHints.max_height = height; - xcb_set_wm_normal_hints(m_connection, m_window, &sizeHints); + xcb_icccm_set_wm_normal_hints(m_connection, m_window, &sizeHints); } } @@ -332,10 +366,61 @@ WindowHandle WindowImplX11::getSystemHandle() const //////////////////////////////////////////////////////////// void WindowImplX11::processEvents() { - while(xcb_generic_event_t* event = xcb_poll_for_event(m_connection)) + // Key repeat workaround: If key repeat is enabled, XCB will spawn two + // events for each repeat interval: key release and key press. Both have + // the same timestamp and key code. We are holding back the release event + // to check for the matching key press event and if so, discard the release + // event. + + xcb_generic_event_t* event = NULL; + xcb_key_release_event_t* lastKeyReleaseEvent = NULL; + uint8_t eventType = 0; + + while(event = xcb_poll_for_event(m_connection)) { - processEvent(event); - free(event); + eventType = event->response_type & ~0x80; + + // Key was pressed and one has been released prior to that. + if (eventType == XCB_KEY_PRESS && lastKeyReleaseEvent) + { + // If the key press event matches the held back key release event, + // then we have a key repeat and discard the held back release + // event. + if (lastKeyReleaseEvent->time == reinterpret_cast(event)->time && + lastKeyReleaseEvent->detail == reinterpret_cast(event)->detail) + { + free(lastKeyReleaseEvent); + lastKeyReleaseEvent = NULL; + } + } + + // If there's still a key release event held back, process it now. + if (lastKeyReleaseEvent) + { + processEvent(reinterpret_cast(lastKeyReleaseEvent)); + free(lastKeyReleaseEvent); + lastKeyReleaseEvent = NULL; + } + + if (eventType == XCB_KEY_RELEASE) + { + // Remember this key release event. + lastKeyReleaseEvent = reinterpret_cast(event); + event = NULL; // For safety reasons. + } + else + { + processEvent(event); + free(event); + } + } + + // Process any held back release event. + if (lastKeyReleaseEvent) + { + processEvent(reinterpret_cast(lastKeyReleaseEvent)); + free(lastKeyReleaseEvent); + lastKeyReleaseEvent = NULL; } } @@ -343,9 +428,11 @@ void WindowImplX11::processEvents() //////////////////////////////////////////////////////////// Vector2i WindowImplX11::getPosition() const { - AutoPointer reply = - xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL); - return Vector2i(reply->x, reply->y); + xcb_get_geometry_reply_t* reply = xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL); + Vector2i result(reply->x, reply->y); + free(reply); + + return result; } @@ -363,15 +450,26 @@ void WindowImplX11::setPosition(const Vector2i& position) //////////////////////////////////////////////////////////// Vector2u WindowImplX11::getSize() const { - AutoPointer reply = - xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL); - return Vector2u(reply->width, reply->height); + xcb_get_geometry_reply_t* reply = xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL); + Vector2u result(reply->width, reply->height); + free(reply); + + return result; } //////////////////////////////////////////////////////////// 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 ) { + xcb_size_hints_t sizeHints; + sizeHints.flags = XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE; + sizeHints.min_width = sizeHints.max_width = size.x; + sizeHints.min_height = sizeHints.max_height = size.y; + xcb_icccm_set_wm_normal_hints(m_connection, m_window, &sizeHints); + } + uint32_t values[] = {size.x, size.y}; xcb_configure_window(m_connection, m_window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, @@ -383,10 +481,16 @@ void WindowImplX11::setSize(const Vector2u& size) //////////////////////////////////////////////////////////// void WindowImplX11::setTitle(const String& title) { - const char* c_title = title.c_str(); + // XCB takes UTF-8-encoded strings. + std::basic_string utf8String; + sf::Utf<32>::toUtf8( + title.begin(), title.end(), + std::back_inserter( utf8String ) + ); + xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, - WM_NAME, STRING, - 8, title.length(), c_title); + XA_WM_NAME, XA_STRING, + 8, utf8String.length(), utf8String.c_str()); xcb_flush(m_connection); } @@ -418,8 +522,11 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 width, height, 0, 0, 0, defDepth, sizeof(iconPixels), iconPixels); xcb_free_gc(m_connection, iconGC); - ErrorPointer errptr(m_connection, cookie); - if (! errptr.isNull()) + xcb_generic_error_t* errptr = xcb_request_check(m_connection, cookie); + bool setWindowIconFailed = (errptr != NULL); + free(errptr); + + if (setWindowIconFailed) { err() << "Failed to set the window's icon: Error code " << (int)errptr->error_code << std::endl; return; @@ -445,11 +552,11 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 xcb_pixmap_t maskPixmap = xcb_create_pixmap_from_bitmap_data(m_connection, m_window, (Uint8*)&maskPixels[0], width, height, 1, 0, 1, NULL); // Send our new icon to the window through the WMHints - xcb_wm_hints_t hints; - hints.flags = XCB_WM_HINT_ICON_PIXMAP | XCB_WM_HINT_ICON_MASK; + xcb_icccm_wm_hints_t hints; + hints.flags = XCB_ICCCM_WM_HINT_ICON_PIXMAP | XCB_ICCCM_WM_HINT_ICON_MASK; hints.icon_pixmap = iconPixmap; hints.icon_mask = maskPixmap; - xcb_set_wm_hints(m_connection, m_window, &hints); + xcb_icccm_set_wm_hints(m_connection, m_window, &hints); xcb_flush(m_connection); } @@ -607,15 +714,52 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode) //////////////////////////////////////////////////////////// void WindowImplX11::initialize() { - // Make sure the "last key release" is initialized with invalid values - m_lastKeyReleaseEvent.response_type = -1; - m_lastKeyReleaseEvent.detail = 0; - m_lastKeyReleaseEvent.time = 0; + // Get the atoms for registering the close event + static const std::string WM_DELETE_WINDOW_NAME = "WM_DELETE_WINDOW"; - // Get the atom defining the close event - m_atomClose = xcb_atom_get(m_connection, "WM_DELETE_WINDOW"); - xcb_atom_t wmprotocolsAtom = xcb_atom_get(m_connection, "WM_PROTOCOLS"); - xcb_set_wm_protocols(m_connection, wmprotocolsAtom, m_window, 1, &m_atomClose); + xcb_intern_atom_cookie_t deleteWindowAtomRequest = xcb_intern_atom( + m_connection, + 0, + WM_DELETE_WINDOW_NAME.size(), + WM_DELETE_WINDOW_NAME.c_str() + ); + xcb_intern_atom_reply_t* deleteWindowAtomReply = xcb_intern_atom_reply( + m_connection, + deleteWindowAtomRequest, + NULL + ); + + static const std::string WM_PROTOCOLS_NAME = "WM_PROTOCOLS"; + + xcb_intern_atom_cookie_t protocolsAtomRequest = xcb_intern_atom( + m_connection, + 0, + WM_PROTOCOLS_NAME.size(), + WM_PROTOCOLS_NAME.c_str() + ); + xcb_intern_atom_reply_t* protocolsAtomReply = xcb_intern_atom_reply( + m_connection, + protocolsAtomRequest, + NULL + ); + + if (protocolsAtomReply && deleteWindowAtomReply) + { + xcb_icccm_set_wm_protocols( + m_connection, + m_window, + protocolsAtomReply->atom, + 1, + &deleteWindowAtomReply->atom + ); + + m_atomClose = deleteWindowAtomReply->atom; + } + else + { + // Should not happen, but better safe than sorry. + std::cerr << "Failed to request WM_PROTOCOLS/WM_DELETE_WINDOW_NAME atoms." << std::endl; + } // Create the input context m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL); @@ -708,49 +852,6 @@ void WindowImplX11::cleanup() //////////////////////////////////////////////////////////// bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) { - // This function implements a workaround to properly discard - // repeated key events when necessary. The problem is that the - // system's key events policy doesn't match SFML's one: X server will generate - // both repeated KeyPress and KeyRelease events when maintaining a key down, while - // SFML only wants repeated KeyPress events. Thus, we have to: - // - Discard duplicated KeyRelease events when KeyRepeatEnabled is true - // - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false - - // Detect repeated key events - if ((windowEvent->response_type == XCB_KEY_PRESS) || - (windowEvent->response_type == XCB_KEY_RELEASE)) - { - xcb_key_press_event_t* press = reinterpret_cast(windowEvent); - if (press->detail < 256) - { - // To detect if it is a repeated key event, we check the current state of the key. - // - If the state is "down", KeyReleased events must obviously be discarded. - // - KeyPress events are a little bit harder to handle: they depend on the EnableKeyRepeat state, - // and we need to properly forward the first one. - xcb_query_keymap_cookie_t cookie = xcb_query_keymap(m_connection); - AutoPointer keymap = xcb_query_keymap_reply(m_connection, - cookie, NULL); - - if (keymap->keys[press->detail / 8] & (1 << (press->detail % 8))) - { - // KeyRelease event + key down = repeated event --> discard - if (windowEvent->response_type == XCB_KEY_RELEASE) - { - m_lastKeyReleaseEvent = *press; - return false; - } - - // KeyPress event + key repeat disabled + matching KeyRelease event = repeated event --> discard - if ((windowEvent->response_type == XCB_KEY_PRESS) && !m_keyRepeat && - (m_lastKeyReleaseEvent.detail == press->detail) && - (m_lastKeyReleaseEvent.time == press->time)) - { - return false; - } - } - } - } - // Convert the X11 event to a sf::Event switch (windowEvent->response_type & ~0x80) { @@ -827,6 +928,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) case XCB_KEY_PRESS: { xcb_key_press_event_t* e = reinterpret_cast(windowEvent); + // Get the keysym of the key that has been pressed static XComposeStatus keyboard; char buffer[32]; @@ -895,9 +997,10 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) } // Key up event - case KeyRelease: + case XCB_KEY_RELEASE: { xcb_key_release_event_t* e = reinterpret_cast(windowEvent); + // Get the keysym of the key that has been pressed char buffer[32]; KeySym symbol; @@ -1000,7 +1103,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) // Mouse entered case XCB_ENTER_NOTIFY: { - if (windowEvent.xcrossing.mode == NotifyNormal) + xcb_enter_notify_event_t* enterNotifyEvent = reinterpret_cast(windowEvent); + + if (enterNotifyEvent->mode == NotifyNormal) { Event event; event.type = Event::MouseEntered; @@ -1012,7 +1117,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) // Mouse left case XCB_LEAVE_NOTIFY: { - if (windowEvent.xcrossing.mode == NotifyNormal) + xcb_leave_notify_event_t* leaveNotifyEvent = reinterpret_cast(windowEvent); + + if (leaveNotifyEvent->mode == NotifyNormal) { Event event; event.type = Event::MouseLeft; diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index 7882aa01c..5a625dc48 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -228,19 +228,19 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - ::Window m_window; ///< X11 structure defining our window - ::Display* m_display; ///< Pointer to the display - xcb_connection_t* m_connection; ///< Pointer to the xcb connection - 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 - Atom m_atomClose; ///< Atom used to identify the close event - 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? + ::Window m_window; ///< X11 structure defining our window + ::Display* m_display; ///< Pointer to the display + xcb_connection_t* m_connection; ///< Pointer to the xcb connection + 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 + Atom m_atomClose; ///< Atom used to identify the close event + 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? }; } // namespace priv From d17b4bad962d8da7bb55bc3eedf18a7230fb74fd Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Mon, 13 Oct 2014 09:39:00 +0200 Subject: [PATCH 3/8] Source code format. --- src/SFML/Window/Unix/WindowImplX11.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 98b8e0ab3..6d078ef66 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -498,7 +498,7 @@ 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 + // X11 wants BGRA pixels: swap red and blue channels Uint8 iconPixels[width * height * 4]; for (std::size_t i = 0; i < width * height; ++i) { From 17090367dcea8ee03713e078ff8650fff8f8d920 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Mon, 13 Oct 2014 10:11:43 +0200 Subject: [PATCH 4/8] Fixed WindowImplX11::getPosition. --- src/SFML/Window/Unix/WindowImplX11.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 6d078ef66..acf7cf71e 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -428,9 +428,12 @@ void WindowImplX11::processEvents() //////////////////////////////////////////////////////////// Vector2i WindowImplX11::getPosition() const { - xcb_get_geometry_reply_t* reply = xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL); - Vector2i result(reply->x, reply->y); - free(reply); + ::Window rootWindow = RootWindow(m_display, m_screen); + xcb_translate_coordinates_cookie_t translateCookie = xcb_translate_coordinates(m_connection, m_window, rootWindow, 0, 0); + xcb_translate_coordinates_reply_t* translateReply = xcb_translate_coordinates_reply(m_connection, translateCookie, NULL); + + Vector2i result(translateReply->dst_x, translateReply->dst_y); + free(translateReply); return result; } From 896bd51b22772b1543031d211d2cb846c9417a34 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Tue, 14 Oct 2014 10:10:20 +0200 Subject: [PATCH 5/8] getPosition workaround for X11. Fixed memory leaks. --- src/SFML/Window/Unix/WindowImplX11.cpp | 28 ++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index acf7cf71e..778898eb7 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -288,6 +288,8 @@ m_useSizeHints(false) const unsigned char* ptr = reinterpret_cast(&hints); xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, hintsAtomReply->atom, XA_WM_HINTS, 32, 5, ptr); + + free(hintsAtomReply); } // This is a hack to force some windows managers to disable resizing @@ -429,11 +431,26 @@ void WindowImplX11::processEvents() Vector2i WindowImplX11::getPosition() const { ::Window rootWindow = RootWindow(m_display, m_screen); - xcb_translate_coordinates_cookie_t translateCookie = xcb_translate_coordinates(m_connection, m_window, rootWindow, 0, 0); - xcb_translate_coordinates_reply_t* translateReply = xcb_translate_coordinates_reply(m_connection, translateCookie, NULL); + ::Window topLevelWindow = m_window; + ::Window nextWindow = topLevelWindow; + xcb_query_tree_cookie_t treeCookie; + xcb_query_tree_reply_t* treeReply = NULL; - Vector2i result(translateReply->dst_x, translateReply->dst_y); - free(translateReply); + // Get "top level" window, i.e. the window with the root window as its parent. + while (nextWindow != rootWindow) + { + topLevelWindow = nextWindow; + + treeCookie = xcb_query_tree(m_connection, topLevelWindow); + treeReply = xcb_query_tree_reply(m_connection, treeCookie, NULL); + nextWindow = treeReply->parent; + free(treeReply); + } + + xcb_get_geometry_cookie_t geometryCookie = xcb_get_geometry(m_connection, topLevelWindow); + xcb_get_geometry_reply_t* geometryReply = xcb_get_geometry_reply(m_connection, geometryCookie, NULL); + sf::Vector2i result(geometryReply->x, geometryReply->y); + free(geometryReply); return result; } @@ -764,6 +781,9 @@ void WindowImplX11::initialize() std::cerr << "Failed to request WM_PROTOCOLS/WM_DELETE_WINDOW_NAME atoms." << std::endl; } + free(protocolsAtomReply); + free(deleteWindowAtomReply); + // Create the input context m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL); if (m_inputMethod) From 92ca32b2f9ead70eb940cf80c3d644d65ded9ad0 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Mon, 5 Jan 2015 22:23:16 +0100 Subject: [PATCH 6/8] Code adjustments to fix warnings. Change-Id: Iba40752c6c5baaadc2a1b6a0fd03cbb0e3cde8a3 --- examples/X11/X11.cpp | 2 +- src/SFML/Window/Unix/InputImpl.cpp | 2 +- src/SFML/Window/Unix/VideoModeImpl.cpp | 1 - src/SFML/Window/Unix/WindowImplX11.cpp | 20 +++++--------------- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/examples/X11/X11.cpp b/examples/X11/X11.cpp index 5b623d936..b8263a051 100644 --- a/examples/X11/X11.cpp +++ b/examples/X11/X11.cpp @@ -201,7 +201,7 @@ int main() while (running) { - while (event = xcb_poll_for_event(xcbConnection)) + while ((event = xcb_poll_for_event(xcbConnection))) { running = false; } diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp index d6aa5fb41..a41fa46b8 100644 --- a/src/SFML/Window/Unix/InputImpl.cpp +++ b/src/SFML/Window/Unix/InputImpl.cpp @@ -179,7 +179,7 @@ bool InputImpl::isKeyPressed(Keyboard::Key key) //////////////////////////////////////////////////////////// -void InputImpl::setVirtualKeyboardVisible(bool visible) +void InputImpl::setVirtualKeyboardVisible(bool /*visible*/) { // Not applicable } diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp index 01ddf0363..48637980e 100644 --- a/src/SFML/Window/Unix/VideoModeImpl.cpp +++ b/src/SFML/Window/Unix/VideoModeImpl.cpp @@ -139,7 +139,6 @@ VideoMode VideoModeImpl::getDesktopMode() if (! errors) { // Get the current video mode - xcb_randr_rotation_t Rotation = (xcb_randr_rotation_t)config->rotation; xcb_randr_mode_t currentMode = config->sizeID; // Get the available screen sizes diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 778898eb7..066093d15 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -67,13 +67,6 @@ namespace PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask; - // Filter the events received by windows (only allow those matching a specific window) - Bool checkEvent(::Display*, XEvent* event, XPointer userData) - { - // Just check if the event matches the window - return event->xany.window == reinterpret_cast< ::Window >(userData); - } - // Find the name of the current executable void findExecutableName(char* buffer, std::size_t bufferSize) { @@ -127,7 +120,7 @@ m_useSizeHints(false) if (m_window) { // Make sure the window is listening to all the required events - const uint32_t value_list[] = {eventMask}; + const uint32_t value_list[] = {static_cast(eventMask)}; xcb_change_window_attributes(m_connection, m_window, @@ -141,7 +134,7 @@ m_useSizeHints(false) //////////////////////////////////////////////////////////// -WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) : +WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& /*settings*/) : m_window (0), m_inputMethod (NULL), m_inputContext(NULL), @@ -184,11 +177,8 @@ m_useSizeHints(false) if (fullscreen) switchToFullscreen(mode); - // Choose the visual according to the context settings - XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings); - // Define the window attributes - const uint32_t value_list[] = {fullscreen, eventMask}; + const uint32_t value_list[] = {fullscreen, static_cast(eventMask)}; // Create the window m_window = xcb_generate_id(m_connection); @@ -378,7 +368,7 @@ void WindowImplX11::processEvents() xcb_key_release_event_t* lastKeyReleaseEvent = NULL; uint8_t eventType = 0; - while(event = xcb_poll_for_event(m_connection)) + while((event = xcb_poll_for_event(m_connection))) { eventType = event->response_type & ~0x80; @@ -459,7 +449,7 @@ Vector2i WindowImplX11::getPosition() const //////////////////////////////////////////////////////////// void WindowImplX11::setPosition(const Vector2i& position) { - uint32_t values[] = {position.x, position.y}; + 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); From 132ae26ce1ff888ab24f9c27e6fa4c8af330e2a7 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Tue, 6 Jan 2015 09:34:31 +0100 Subject: [PATCH 7/8] Adjusted window focus changes to be XCB-compatible. Change-Id: I0fe2c7d1698bce23b81f5c6a9db018f7a3fe49d8 --- src/SFML/Window/Unix/WindowImplX11.cpp | 62 ++++++++++++++------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 066093d15..3724709c8 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -618,34 +618,38 @@ void WindowImplX11::requestFocus() // Check if window is viewable (not on other desktop, ...) // TODO: Check also if minimized - XWindowAttributes attributes; - if (XGetWindowAttributes(m_display, m_window, &attributes) == 0) + xcb_get_window_attributes_cookie_t attribCookie = xcb_get_window_attributes(m_connection, m_window); + xcb_get_window_attributes_reply_t* attributes = xcb_get_window_attributes_reply(m_connection, + attribCookie, + NULL); + if (!attributes) { sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl; return; // error getting attribute } - bool windowViewable = (attributes.map_state == IsViewable); + bool windowViewable = (attributes->map_state == XCB_MAP_STATE_VIEWABLE); + free(attributes); if (sfmlWindowFocused && windowViewable) { // Another SFML window of this application has the focus and the current window is viewable: // steal focus (i.e. bring window to the front and give it input focus) - XRaiseWindow(m_display, m_window); - XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); + xcb_set_input_focus(m_connection, XCB_INPUT_FOCUS_POINTER_ROOT, m_window, XCB_CURRENT_TIME); + const uint32_t values[] = {XCB_STACK_MODE_ABOVE}; + xcb_configure_window(m_connection, m_window, XCB_CONFIG_WINDOW_STACK_MODE, values); } else { - // 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(); - - // Add urgency (notification) flag to hints - hints->flags |= XUrgencyHint; - XSetWMHints(m_display, m_window, hints); - XFree(hints); + // Get current WM hints. + xcb_get_property_cookie_t hintsCookie = xcb_icccm_get_wm_hints_unchecked(m_connection, m_window); + xcb_icccm_wm_hints_t hints; + xcb_icccm_get_wm_hints_reply(m_connection, hintsCookie, &hints, NULL); + + // 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 |= XCB_ICCCM_WM_HINT_X_URGENCY; + xcb_icccm_set_wm_hints_checked(m_connection, m_window, &hints); } } @@ -653,11 +657,13 @@ void WindowImplX11::requestFocus() //////////////////////////////////////////////////////////// bool WindowImplX11::hasFocus() const { - ::Window focusedWindow = 0; - int revertToReturn = 0; - XGetInputFocus(m_display, &focusedWindow, &revertToReturn); + xcb_get_input_focus_cookie_t cookie = xcb_get_input_focus_unchecked(m_connection); + xcb_get_input_focus_reply_t* reply = xcb_get_input_focus_reply(m_connection, cookie, NULL); - return m_window == focusedWindow; + bool focussed = (reply->focus == m_window); + free(reply); + + return focussed; } @@ -838,7 +844,7 @@ void WindowImplX11::cleanup() xcb_generic_error_t* errors; xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply( m_connection, xcb_randr_get_screen_info(m_connection, screen->root), &errors); - if (! errors) + if (!errors) { // Reset the video mode xcb_randr_set_screen_config(m_connection, @@ -888,14 +894,14 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) pushEvent(event); // If the window has been previously marked urgent (notification) as a result of a focus request, undo that - XWMHints* hints = XGetWMHints(m_display, m_window); - if (hints != NULL) - { - // Remove urgency (notification) flag from hints - hints->flags &= ~XUrgencyHint; - XSetWMHints(m_display, m_window, hints); - XFree(hints); - } + xcb_get_property_cookie_t hintsCookie = xcb_icccm_get_wm_hints_unchecked(m_connection, m_window); + xcb_icccm_wm_hints_t hints; + xcb_icccm_get_wm_hints_reply(m_connection, hintsCookie, &hints, NULL); + + // Remove urgency (notification) flag from hints + hints.flags &= ~XUrgencyHint; + xcb_icccm_set_wm_hints_checked(m_connection, m_window, &hints); + break; } From f464e2502af84ab4a0e8777e32e101812c4e6563 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Tue, 6 Jan 2015 11:04:44 +0100 Subject: [PATCH 8/8] Removed link to Xlib. Replaced more Xlib calls by XCB calls. Change-Id: I05d8b24508e88b604f7cc76622cc8af695204990 --- src/SFML/Window/CMakeLists.txt | 2 +- src/SFML/Window/Unix/VideoModeImpl.cpp | 1 - src/SFML/Window/Unix/WindowImplX11.cpp | 57 +++++++++++--------------- src/SFML/Window/Unix/WindowImplX11.hpp | 2 +- 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index 94e471b29..83d6df678 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -218,7 +218,7 @@ endif() if(SFML_OS_WINDOWS) list(APPEND WINDOW_EXT_LIBS winmm gdi32) elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD) - list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) + list(APPEND WINDOW_EXT_LIBS ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) if(SFML_OS_FREEBSD) list(APPEND WINDOW_EXT_LIBS usbhid) endif() diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp index 48637980e..2a3489fc6 100644 --- a/src/SFML/Window/Unix/VideoModeImpl.cpp +++ b/src/SFML/Window/Unix/VideoModeImpl.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 3724709c8..ba3b96fd5 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -30,9 +30,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -112,7 +109,10 @@ m_useSizeHints(false) return; } - m_screen = DefaultScreen(m_display); + // Get connection info. + const xcb_setup_t* setup = xcb_get_setup(m_connection); + xcb_screen_iterator_t screenIter = xcb_setup_roots_iterator(setup); + m_screen = screenIter.data; // Save the window handle m_window = handle; @@ -150,20 +150,24 @@ m_useSizeHints(false) m_display = OpenDisplay(); XSetEventQueueOwner(m_display, XCBOwnsEventQueue); m_connection = XGetXCBConnection(m_display); - if (! m_connection) + if (!m_connection) { err() << "Failed cast Display object to an XCB connection object" << std::endl; return; } - m_screen = DefaultScreen(m_display); + + // Get connection info. + const xcb_setup_t* setup = xcb_get_setup(m_connection); + xcb_screen_iterator_t screenIter = xcb_setup_roots_iterator(setup); + m_screen = screenIter.data; // Compute position and size int left, top; bool fullscreen = (style & Style::Fullscreen) != 0; if (!fullscreen) { - left = (DisplayWidth(m_display, m_screen) - mode.width) / 2; - top = (DisplayHeight(m_display, m_screen) - mode.height) / 2; + left = (m_screen->width_in_pixels - mode.width) / 2; + top = (m_screen->height_in_pixels - mode.height) / 2; } else { @@ -187,7 +191,7 @@ m_useSizeHints(false) m_connection, XCB_COPY_FROM_PARENT, m_window, - RootWindow(m_display, m_screen), + m_screen->root, left, top, width, height, 0, @@ -277,7 +281,7 @@ m_useSizeHints(false) const unsigned char* ptr = reinterpret_cast(&hints); xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, - hintsAtomReply->atom, XA_WM_HINTS, 32, 5, ptr); + hintsAtomReply->atom, XCB_ATOM_WM_HINTS, 32, 5, ptr); free(hintsAtomReply); } @@ -297,11 +301,7 @@ m_useSizeHints(false) // Set the window's WM class (this can be used by window managers) char windowClass[512]; findExecutableName(windowClass, sizeof(windowClass)); - XClassHint* classHint = XAllocClassHint(); - classHint->res_name = windowClass; - classHint->res_class = windowClass; - XSetClassHint(m_display, m_window, classHint); - XFree(classHint); + xcb_icccm_set_wm_class_checked(m_connection, m_window, std::strlen(windowClass), windowClass); // Do some common initializations initialize(); @@ -420,14 +420,13 @@ void WindowImplX11::processEvents() //////////////////////////////////////////////////////////// Vector2i WindowImplX11::getPosition() const { - ::Window rootWindow = RootWindow(m_display, m_screen); ::Window topLevelWindow = m_window; ::Window nextWindow = topLevelWindow; xcb_query_tree_cookie_t treeCookie; xcb_query_tree_reply_t* treeReply = NULL; // Get "top level" window, i.e. the window with the root window as its parent. - while (nextWindow != rootWindow) + while (nextWindow != m_screen->root) { topLevelWindow = nextWindow; @@ -499,7 +498,7 @@ void WindowImplX11::setTitle(const String& title) ); xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window, - XA_WM_NAME, XA_STRING, + XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, utf8String.length(), utf8String.c_str()); xcb_flush(m_connection); } @@ -519,17 +518,15 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 } // Create the icon pixmap - uint8_t defDepth = DefaultDepth(m_display, m_screen); - xcb_pixmap_t iconPixmap = xcb_generate_id(m_connection); - xcb_create_pixmap(m_connection, defDepth, iconPixmap, RootWindow(m_display, m_screen), + xcb_create_pixmap(m_connection, m_screen->root_depth, iconPixmap, m_screen->root, width, height); xcb_gcontext_t iconGC = xcb_generate_id(m_connection); xcb_create_gc(m_connection, iconGC, iconPixmap, 0, NULL); xcb_void_cookie_t cookie = xcb_put_image_checked( m_connection, XCB_IMAGE_FORMAT_Z_PIXMAP, iconPixmap, iconGC, - width, height, 0, 0, 0, defDepth, sizeof(iconPixels), iconPixels); + width, height, 0, 0, 0, m_screen->root_depth, sizeof(iconPixels), iconPixels); xcb_free_gc(m_connection, iconGC); xcb_generic_error_t* errptr = xcb_request_check(m_connection, cookie); @@ -675,12 +672,11 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode) xcb_query_extension_reply(m_connection, xcb_query_extension(m_connection, 5, "RANDR"), NULL); if (randr_ext->present) { - xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, m_screen); // Get the current configuration xcb_generic_error_t* errors; xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply(m_connection, - xcb_randr_get_screen_info(m_connection, screen->root), + xcb_randr_get_screen_info(m_connection, m_screen->root), &errors); if (! errors) { @@ -698,7 +694,7 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode) { // Switch to fullscreen mode xcb_randr_set_screen_config(m_connection, - screen->root, + m_screen->root, config->timestamp, config->config_timestamp, i, config->rotation, config->rate); @@ -837,18 +833,15 @@ void WindowImplX11::cleanup() // Restore the previous video mode (in case we were running in fullscreen) if (fullscreenWindow == this) { - // Retrieve the default screen - xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, m_screen); - // Get current screen info xcb_generic_error_t* errors; xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply( - m_connection, xcb_randr_get_screen_info(m_connection, screen->root), &errors); + m_connection, xcb_randr_get_screen_info(m_connection, m_screen->root), &errors); if (!errors) { // Reset the video mode xcb_randr_set_screen_config(m_connection, - screen->root, + m_screen->root, CurrentTime, config->config_timestamp, m_oldVideoMode, @@ -1148,9 +1141,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) } // Parent window changed - case ReparentNotify: + case XCB_REPARENT_NOTIFY: { - XSync(m_display, True); // Discard remaining events + xcb_flush(m_connection); // Discard remaining events break; } } diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index 5a625dc48..edf3aad80 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -231,7 +231,7 @@ private: ::Window m_window; ///< X11 structure defining our window ::Display* m_display; ///< Pointer to the display xcb_connection_t* m_connection; ///< Pointer to the xcb connection - int m_screen; ///< Screen identifier + 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