From fc50d231530ae85da5cc3f3ebd131310c15bf359 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Thu, 27 Oct 2016 18:34:24 +0100 Subject: New upstream version 2.4.1~git15.b61c2f8+dfsg --- src/SFML/Window/CMakeLists.txt | 16 +- src/SFML/Window/Context.cpp | 80 +- src/SFML/Window/EglContext.cpp | 10 +- src/SFML/Window/EglContext.hpp | 4 +- src/SFML/Window/GlContext.cpp | 210 +++- src/SFML/Window/GlContext.hpp | 28 +- src/SFML/Window/GlResource.cpp | 46 +- src/SFML/Window/OSX/SFContext.hpp | 4 +- src/SFML/Window/OSX/SFContext.mm | 29 +- src/SFML/Window/OSX/SFOpenGLView+mouse.mm | 2 +- src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h | 3 +- src/SFML/Window/Unix/Display.cpp | 89 +- src/SFML/Window/Unix/Display.hpp | 56 +- src/SFML/Window/Unix/GlxContext.cpp | 81 +- src/SFML/Window/Unix/GlxContext.hpp | 7 +- src/SFML/Window/Unix/InputImpl.cpp | 188 +-- src/SFML/Window/Unix/ScopedXcbPtr.hpp | 102 -- src/SFML/Window/Unix/ScopedXcbPtr.inl | 72 -- src/SFML/Window/Unix/VideoModeImpl.cpp | 274 ++--- src/SFML/Window/Unix/WindowImplX11.cpp | 1512 ++++++++++--------------- src/SFML/Window/Unix/WindowImplX11.hpp | 96 +- src/SFML/Window/Win32/WglContext.cpp | 22 +- src/SFML/Window/Win32/WglContext.hpp | 4 +- src/SFML/Window/iOS/EaglContext.hpp | 4 +- src/SFML/Window/iOS/EaglContext.mm | 21 +- src/SFML/Window/iOS/SFAppDelegate.mm | 4 +- 26 files changed, 1159 insertions(+), 1805 deletions(-) delete mode 100644 src/SFML/Window/Unix/ScopedXcbPtr.hpp delete mode 100644 src/SFML/Window/Unix/ScopedXcbPtr.inl (limited to 'src/SFML/Window') diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index 231dee8..a887766 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -75,8 +75,6 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD) ${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/InputImpl.cpp ${SRCROOT}/Unix/InputImpl.hpp - ${SRCROOT}/Unix/ScopedXcbPtr.hpp - ${SRCROOT}/Unix/ScopedXcbPtr.inl ${SRCROOT}/Unix/SensorImpl.cpp ${SRCROOT}/Unix/SensorImpl.hpp ${SRCROOT}/Unix/VideoModeImpl.cpp @@ -200,18 +198,14 @@ if(SFML_OS_LINUX OR SFML_OS_FREEBSD) if(NOT X11_FOUND) message(FATAL_ERROR "X11 library not found") endif() + if(NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "Xrandr library not found") + endif() include_directories(${X11_INCLUDE_DIR}) endif() if(NOT SFML_OPENGL_ES) find_package(OpenGL REQUIRED) include_directories(${OPENGL_INCLUDE_DIR}) - if(SFML_OS_LINUX OR SFML_OS_FREEBSD) - find_package(XCB COMPONENTS xlib_xcb image randr REQUIRED) - if(NOT LIBXCB_FOUND) - message(FATAL_ERROR "Xcb library not found") - endif() - include_directories(${LIBXCB_INCLUDE_DIRS}) - endif() endif() if(SFML_OPENGL_ES AND SFML_OS_LINUX) find_package(EGL REQUIRED) @@ -231,9 +225,9 @@ endif() if(SFML_OS_WINDOWS) list(APPEND WINDOW_EXT_LIBS winmm gdi32) elseif(SFML_OS_LINUX) - list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES}) + list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} ${UDEV_LIBRARIES}) elseif(SFML_OS_FREEBSD) - list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${LIBXCB_LIBRARIES} usbhid) + list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} usbhid) elseif(SFML_OS_MACOSX) list(APPEND WINDOW_EXT_LIBS "-framework Foundation -framework AppKit -framework IOKit -framework Carbon") elseif(SFML_OS_IOS) diff --git a/src/SFML/Window/Context.cpp b/src/SFML/Window/Context.cpp index 2d51bbc..7617e1a 100644 --- a/src/SFML/Window/Context.cpp +++ b/src/SFML/Window/Context.cpp @@ -28,24 +28,6 @@ #include #include #include -#include -#include -#include -#include - -#if defined(SFML_SYSTEM_WINDOWS) - - typedef const GLubyte* (APIENTRY *glGetStringiFuncType)(GLenum, GLuint); - -#else - - typedef const GLubyte* (*glGetStringiFuncType)(GLenum, GLuint); - -#endif - -#if !defined(GL_NUM_EXTENSIONS) - #define GL_NUM_EXTENSIONS 0x821D -#endif namespace @@ -99,70 +81,16 @@ const Context* Context::getActiveContext() //////////////////////////////////////////////////////////// -GlFunctionPointer Context::getFunction(const char* name) +bool Context::isExtensionAvailable(const char* name) { - return priv::GlContext::getFunction(name); + return priv::GlContext::isExtensionAvailable(name); } //////////////////////////////////////////////////////////// -bool Context::isExtensionAvailable(const char* name) +GlFunctionPointer Context::getFunction(const char* name) { - static std::vector extensions; - static bool loaded = false; - - if (!loaded) - { - const Context* context = getActiveContext(); - - if (!context) - return false; - - const char* extensionString = NULL; - - if(context->getSettings().majorVersion < 3) - { - // Try to load the < 3.0 way - extensionString = reinterpret_cast(glGetString(GL_EXTENSIONS)); - - do - { - const char* extension = extensionString; - - while(*extensionString && (*extensionString != ' ')) - extensionString++; - - extensions.push_back(std::string(extension, extensionString)); - } - while (*extensionString++); - } - else - { - // Try to load the >= 3.0 way - glGetStringiFuncType glGetStringiFunc = NULL; - glGetStringiFunc = reinterpret_cast(getFunction("glGetStringi")); - - if (glGetStringiFunc) - { - int numExtensions = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); - - if (numExtensions) - { - for (unsigned int i = 0; i < static_cast(numExtensions); ++i) - { - extensionString = reinterpret_cast(glGetStringiFunc(GL_EXTENSIONS, i)); - - extensions.push_back(extensionString); - } - } - } - } - - loaded = true; - } - - return std::find(extensions.begin(), extensions.end(), name) != extensions.end(); + return priv::GlContext::getFunction(name); } diff --git a/src/SFML/Window/EglContext.cpp b/src/SFML/Window/EglContext.cpp index f6686f1..03c4197 100644 --- a/src/SFML/Window/EglContext.cpp +++ b/src/SFML/Window/EglContext.cpp @@ -173,9 +173,12 @@ EglContext::~EglContext() //////////////////////////////////////////////////////////// -bool EglContext::makeCurrent() +bool EglContext::makeCurrent(bool current) { - return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context)); + if (current) + return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context)); + + return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); } @@ -209,6 +212,9 @@ void EglContext::createContext(EglContext* shared) else toShared = EGL_NO_CONTEXT; + if (toShared != EGL_NO_CONTEXT) + eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + // Create EGL context m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion)); } diff --git a/src/SFML/Window/EglContext.hpp b/src/SFML/Window/EglContext.hpp index 6df6a53..a889c3a 100644 --- a/src/SFML/Window/EglContext.hpp +++ b/src/SFML/Window/EglContext.hpp @@ -83,10 +83,12 @@ public: /// \brief Activate the context as the current target /// for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); //////////////////////////////////////////////////////////// /// \brief Display what has been rendered to the context so far diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index b74725e..23cf483 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -31,9 +31,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include #if !defined(SFML_OPENGL_ES) @@ -126,6 +130,8 @@ namespace // AMD drivers have issues with internal synchronization // We need to make sure that no operating system context // or pixel format operations are performed simultaneously + // This mutex is also used to protect the shared context + // from being locked on multiple threads sf::Mutex mutex; // This per-thread variable holds the current context for each thread @@ -134,35 +140,12 @@ namespace // The hidden, inactive context that will be shared with all other contexts ContextType* sharedContext = NULL; - // Internal contexts - sf::ThreadLocalPtr internalContext(NULL); - std::set internalContexts; - sf::Mutex internalContextsMutex; + // This per-thread variable is set to point to the shared context + // if we had to acquire it when a TransientContextLock was required + sf::ThreadLocalPtr currentSharedContext(NULL); - // Check if the internal context of the current thread is valid - bool hasInternalContext() - { - // The internal context can be null... - if (!internalContext) - return false; - - // ... or non-null but deleted from the list of internal contexts - sf::Lock lock(internalContextsMutex); - return internalContexts.find(internalContext) != internalContexts.end(); - } - - // Retrieve the internal context for the current thread - sf::Context* getInternalContext() - { - if (!hasInternalContext()) - { - internalContext = new sf::Context; - sf::Lock lock(internalContextsMutex); - internalContexts.insert(internalContext); - } - - return internalContext; - } + // Supported OpenGL extensions + std::vector extensions; } @@ -182,9 +165,53 @@ void GlContext::globalInit() sharedContext = new ContextType(NULL); sharedContext->initialize(ContextSettings()); - // This call makes sure that: - // - the shared context is inactive (it must never be) - // - another valid context is activated in the current thread + // Load our extensions vector + extensions.clear(); + + // Check whether a >= 3.0 context is available + int majorVersion = 0; + glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); + + if (glGetError() == GL_INVALID_ENUM) + { + // Try to load the < 3.0 way + const char* extensionString = reinterpret_cast(glGetString(GL_EXTENSIONS)); + + do + { + const char* extension = extensionString; + + while(*extensionString && (*extensionString != ' ')) + extensionString++; + + extensions.push_back(std::string(extension, extensionString)); + } + while (*extensionString++); + } + else + { + // Try to load the >= 3.0 way + glGetStringiFuncType glGetStringiFunc = NULL; + glGetStringiFunc = reinterpret_cast(getFunction("glGetStringi")); + + if (glGetStringiFunc) + { + int numExtensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + + if (numExtensions) + { + for (unsigned int i = 0; i < static_cast(numExtensions); ++i) + { + const char* extensionString = reinterpret_cast(glGetStringiFunc(GL_EXTENSIONS, i)); + + extensions.push_back(extensionString); + } + } + } + } + + // Deactivate the shared context so that others can activate it when necessary sharedContext->setActive(false); } @@ -200,31 +227,65 @@ void GlContext::globalCleanup() // Destroy the shared context delete sharedContext; sharedContext = NULL; - - // Destroy the internal contexts - Lock internalContextsLock(internalContextsMutex); - for (std::set::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it) - delete *it; - internalContexts.clear(); } //////////////////////////////////////////////////////////// void GlContext::ensureContext() { - // If there's no active context on the current thread, activate an internal one - if (!currentContext) - getInternalContext()->setActive(true); +} + + +//////////////////////////////////////////////////////////// +void GlContext::acquireTransientContext() +{ + // If a capable context is already active on this thread + // there is no need to use the shared context for the operation + if (currentContext) + { + currentSharedContext = NULL; + return; + } + + mutex.lock(); + currentSharedContext = sharedContext; + sharedContext->setActive(true); +} + + +//////////////////////////////////////////////////////////// +void GlContext::releaseTransientContext() +{ + if (!currentSharedContext) + return; + + sharedContext->setActive(false); + mutex.unlock(); } //////////////////////////////////////////////////////////// GlContext* GlContext::create() { + // Make sure that there's an active context (context creation may need extensions, and thus a valid context) + assert(sharedContext != NULL); + Lock lock(mutex); - // Create the context - GlContext* context = new ContextType(sharedContext); + GlContext* context = NULL; + + // We don't use acquireTransientContext here since we have + // to ensure we have exclusive access to the shared context + // in order to make sure it is not active during context creation + { + sharedContext->setActive(true); + + // Create the context + context = new ContextType(sharedContext); + + sharedContext->setActive(false); + } + context->initialize(ContextSettings()); return context; @@ -235,12 +296,24 @@ GlContext* GlContext::create() GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) { // Make sure that there's an active context (context creation may need extensions, and thus a valid context) - ensureContext(); + assert(sharedContext != NULL); Lock lock(mutex); - // Create the context - GlContext* context = new ContextType(sharedContext, settings, owner, bitsPerPixel); + GlContext* context = NULL; + + // We don't use acquireTransientContext here since we have + // to ensure we have exclusive access to the shared context + // in order to make sure it is not active during context creation + { + sharedContext->setActive(true); + + // Create the context + context = new ContextType(sharedContext, settings, owner, bitsPerPixel); + + sharedContext->setActive(false); + } + context->initialize(settings); context->checkSettings(settings); @@ -252,12 +325,24 @@ GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* GlContext* GlContext::create(const ContextSettings& settings, unsigned int width, unsigned int height) { // Make sure that there's an active context (context creation may need extensions, and thus a valid context) - ensureContext(); + assert(sharedContext != NULL); Lock lock(mutex); - // Create the context - GlContext* context = new ContextType(sharedContext, settings, width, height); + GlContext* context = NULL; + + // We don't use acquireTransientContext here since we have + // to ensure we have exclusive access to the shared context + // in order to make sure it is not active during context creation + { + sharedContext->setActive(true); + + // Create the context + context = new ContextType(sharedContext, settings, width, height); + + sharedContext->setActive(false); + } + context->initialize(settings); context->checkSettings(settings); @@ -265,6 +350,13 @@ GlContext* GlContext::create(const ContextSettings& settings, unsigned int width } +//////////////////////////////////////////////////////////// +bool GlContext::isExtensionAvailable(const char* name) +{ + return std::find(extensions.begin(), extensions.end(), name) != extensions.end(); +} + + //////////////////////////////////////////////////////////// GlFunctionPointer GlContext::getFunction(const char* name) { @@ -287,7 +379,10 @@ GlContext::~GlContext() { // Deactivate the context before killing it, unless we're inside Cleanup() if (sharedContext) - setActive(false); + { + if (this == currentContext) + currentContext = NULL; + } } @@ -308,7 +403,7 @@ bool GlContext::setActive(bool active) Lock lock(mutex); // Activate the context - if (makeCurrent()) + if (makeCurrent(true)) { // Set it as the new current context for this thread currentContext = this; @@ -329,9 +424,18 @@ bool GlContext::setActive(bool active) { if (this == currentContext) { - // To deactivate the context, we actually activate another one so that we make - // sure that there is always an active context for subsequent graphics operations - return getInternalContext()->setActive(true); + Lock lock(mutex); + + // Deactivate the context + if (makeCurrent(false)) + { + currentContext = NULL; + return true; + } + else + { + return false; + } } else { diff --git a/src/SFML/Window/GlContext.hpp b/src/SFML/Window/GlContext.hpp index 8c4ce01..abcda4b 100644 --- a/src/SFML/Window/GlContext.hpp +++ b/src/SFML/Window/GlContext.hpp @@ -73,10 +73,22 @@ public: static void globalCleanup(); //////////////////////////////////////////////////////////// - /// \brief Ensures that an OpenGL context is active in the current thread + /// \brief Empty function for ABI compatibility, use acquireTransientContext instead /// //////////////////////////////////////////////////////////// static void ensureContext(); + + //////////////////////////////////////////////////////////// + /// \brief Acquires a context for short-term use on the current thread + /// + //////////////////////////////////////////////////////////// + static void acquireTransientContext(); + + //////////////////////////////////////////////////////////// + /// \brief Releases a context after short-term use on the current thread + /// + //////////////////////////////////////////////////////////// + static void releaseTransientContext(); //////////////////////////////////////////////////////////// /// \brief Create a new context, not associated to a window @@ -120,6 +132,16 @@ public: static GlContext* create(const ContextSettings& settings, unsigned int width, unsigned int height); public: + //////////////////////////////////////////////////////////// + /// \brief Check whether a given OpenGL extension is available + /// + /// \param name Name of the extension to check for + /// + /// \return True if available, false if unavailable + /// + //////////////////////////////////////////////////////////// + static bool isExtensionAvailable(const char* name); + //////////////////////////////////////////////////////////// /// \brief Get the address of an OpenGL function /// @@ -197,10 +219,12 @@ protected: /// \brief Activate the context as the current target /// for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent() = 0; + virtual bool makeCurrent(bool current) = 0; //////////////////////////////////////////////////////////// /// \brief Evaluate a pixel format configuration diff --git a/src/SFML/Window/GlResource.cpp b/src/SFML/Window/GlResource.cpp index dfcbe7a..a3cdddf 100644 --- a/src/SFML/Window/GlResource.cpp +++ b/src/SFML/Window/GlResource.cpp @@ -27,6 +27,7 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include @@ -44,20 +45,15 @@ namespace sf //////////////////////////////////////////////////////////// GlResource::GlResource() { - { - // Protect from concurrent access - Lock lock(mutex); - - // If this is the very first resource, trigger the global context initialization - if (count == 0) - priv::GlContext::globalInit(); + // Protect from concurrent access + Lock lock(mutex); - // Increment the resources counter - count++; - } + // If this is the very first resource, trigger the global context initialization + if (count == 0) + priv::GlContext::globalInit(); - // Now make sure that there is an active OpenGL context in the current thread - priv::GlContext::ensureContext(); + // Increment the resources counter + count++; } @@ -77,9 +73,31 @@ GlResource::~GlResource() //////////////////////////////////////////////////////////// -void GlResource::ensureGlContext() +GlResource::TransientContextLock::TransientContextLock() : +m_context(0) +{ + Lock lock(mutex); + + if (count == 0) + { + m_context = new Context; + return; + } + + priv::GlContext::acquireTransientContext(); +} + + +//////////////////////////////////////////////////////////// +GlResource::TransientContextLock::~TransientContextLock() { - priv::GlContext::ensureContext(); + if (m_context) + { + delete m_context; + return; + } + + priv::GlContext::releaseTransientContext(); } } // namespace sf diff --git a/src/SFML/Window/OSX/SFContext.hpp b/src/SFML/Window/OSX/SFContext.hpp index 3e2a979..75e6794 100644 --- a/src/SFML/Window/OSX/SFContext.hpp +++ b/src/SFML/Window/OSX/SFContext.hpp @@ -137,10 +137,12 @@ protected: /// \brief Activate the context as the current target /// for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); private: //////////////////////////////////////////////////////////// diff --git a/src/SFML/Window/OSX/SFContext.mm b/src/SFML/Window/OSX/SFContext.mm index 0970007..d458a6e 100644 --- a/src/SFML/Window/OSX/SFContext.mm +++ b/src/SFML/Window/OSX/SFContext.mm @@ -104,6 +104,10 @@ m_window(0) SFContext::~SFContext() { [m_context clearDrawable]; + + if (m_context == [NSOpenGLContext currentContext]) + [NSOpenGLContext clearCurrentContext]; + [m_context release]; [m_view release]; // Might be nil but we don't care. @@ -124,10 +128,18 @@ GlFunctionPointer SFContext::getFunction(const char* name) //////////////////////////////////////////////////////////// -bool SFContext::makeCurrent() +bool SFContext::makeCurrent(bool current) { - [m_context makeCurrentContext]; - return m_context == [NSOpenGLContext currentContext]; // Should be true. + if (current) + { + [m_context makeCurrentContext]; + return m_context == [NSOpenGLContext currentContext]; // Should be true. + } + else + { + [NSOpenGLContext clearCurrentContext]; + return m_context != [NSOpenGLContext currentContext]; // Should be true. + } } @@ -257,6 +269,17 @@ void SFContext::createContext(SFContext* shared, // Use the shared context if one is given. NSOpenGLContext* sharedContext = shared != NULL ? shared->m_context : nil; + if (sharedContext != nil) + { + [NSOpenGLContext clearCurrentContext]; + + if (sharedContext == [NSOpenGLContext currentContext]) + { + sf::err() << "Failed to deactivate shared context before sharing" << std::endl; + return; + } + } + // Create the context. m_context = [[NSOpenGLContext alloc] initWithFormat:pixFmt shareContext:sharedContext]; diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse.mm b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm index 6349081..5cc1f89 100644 --- a/src/SFML/Window/OSX/SFOpenGLView+mouse.mm +++ b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm @@ -230,7 +230,7 @@ //////////////////////////////////////////////////////// -(BOOL)isCursorCurrentlyGrabbed { - return [[self window] isKeyWindow] && (m_cursorGrabbed || m_fullscreen); + return [[self window] isKeyWindow] && m_cursorGrabbed; } diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h b/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h index f9b2ab7..27cd388 100644 --- a/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h +++ b/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h @@ -70,8 +70,7 @@ /// \brief Check whether the cursor is grabbed or not /// /// The cursor is grabbed if the window is active (key) and -/// either it is in fullscreen mode or the user wants to -/// grab it. +/// the user wants to grab it. /// //////////////////////////////////////////////////////////// -(BOOL)isCursorCurrentlyGrabbed; diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp index a078b97..7445508 100644 --- a/src/SFML/Window/Unix/Display.cpp +++ b/src/SFML/Window/Unix/Display.cpp @@ -26,10 +26,12 @@ // Headers //////////////////////////////////////////////////////////// #include +#include +#include #include -#include #include #include +#include #include @@ -38,8 +40,9 @@ namespace // The shared display and its reference counter Display* sharedDisplay = NULL; unsigned int referenceCount = 0; + sf::Mutex mutex; - typedef std::map AtomMap; + typedef std::map AtomMap; AtomMap atoms; } @@ -50,6 +53,8 @@ namespace priv //////////////////////////////////////////////////////////// Display* OpenDisplay() { + Lock lock(mutex); + if (referenceCount == 0) { sharedDisplay = XOpenDisplay(NULL); @@ -68,16 +73,11 @@ Display* OpenDisplay() } -//////////////////////////////////////////////////////////// -xcb_connection_t* OpenConnection() -{ - return XGetXCBConnection(OpenDisplay()); -} - - //////////////////////////////////////////////////////////// void CloseDisplay(Display* display) { + Lock lock(mutex); + assert(display == sharedDisplay); referenceCount--; @@ -87,81 +87,22 @@ void CloseDisplay(Display* display) //////////////////////////////////////////////////////////// -void CloseConnection(xcb_connection_t* connection) -{ - assert(connection == XGetXCBConnection(sharedDisplay)); - return CloseDisplay(sharedDisplay); -} - - -//////////////////////////////////////////////////////////// -xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr) -{ - xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); - - for (; iter.rem; --screen_nbr, xcb_screen_next (&iter)) - { - if (screen_nbr == 0) - return iter.data; - } - - return NULL; -} - - -//////////////////////////////////////////////////////////// -xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection) -{ - assert(connection == XGetXCBConnection(sharedDisplay)); - return XCBScreenOfDisplay(connection, XDefaultScreen(sharedDisplay)); -} - - -//////////////////////////////////////////////////////////// -xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection) -{ - assert(connection == XGetXCBConnection(sharedDisplay)); - xcb_screen_t* screen = XCBScreenOfDisplay(connection, XDefaultScreen(sharedDisplay)); - if (screen) - return screen->root; - return 0; -} - - -//////////////////////////////////////////////////////////// -xcb_atom_t getAtom(const std::string& name, bool onlyIfExists) +Atom getAtom(const std::string& name, bool onlyIfExists) { AtomMap::const_iterator iter = atoms.find(name); if (iter != atoms.end()) return iter->second; - ScopedXcbPtr error(NULL); + Display* display = OpenDisplay(); - xcb_connection_t* connection = OpenConnection(); + Atom atom = XInternAtom(display, name.c_str(), onlyIfExists ? True : False); - ScopedXcbPtr reply(xcb_intern_atom_reply( - connection, - xcb_intern_atom( - connection, - onlyIfExists, - name.size(), - name.c_str() - ), - &error - )); - - CloseConnection(connection); - - if (error || !reply) - { - err() << "Failed to get " << name << " atom." << std::endl; - return XCB_ATOM_NONE; - } + CloseDisplay(display); - atoms[name] = reply->atom; + atoms[name] = atom; - return reply->atom; + return atom; } } // namespace priv diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp index 2743678..f0eb302 100644 --- a/src/SFML/Window/Unix/Display.hpp +++ b/src/SFML/Window/Unix/Display.hpp @@ -28,7 +28,7 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include +#include #include @@ -47,17 +47,6 @@ namespace priv //////////////////////////////////////////////////////////// Display* OpenDisplay(); -//////////////////////////////////////////////////////////// -/// \brief Get the xcb connection of the shared Display -/// -/// This function increments the reference count of the display, -/// it must be matched with a call to CloseConnection. -/// -/// \return Pointer to the shared connection -/// -//////////////////////////////////////////////////////////// -xcb_connection_t* OpenConnection(); - //////////////////////////////////////////////////////////// /// \brief Release a reference to the shared display /// @@ -66,55 +55,16 @@ xcb_connection_t* OpenConnection(); //////////////////////////////////////////////////////////// void CloseDisplay(Display* display); -//////////////////////////////////////////////////////////// -/// \brief Release a reference to the shared display -/// -/// \param connection Connection of display to release -/// -//////////////////////////////////////////////////////////// -void CloseConnection(xcb_connection_t* connection); - -//////////////////////////////////////////////////////////// -/// \brief Get screen of a display by index (equivalent to XScreenOfDisplay) -/// -/// \param connection Connection of display -/// \param screen_nbr The index of the screen -/// -/// \return Pointer to the screen -/// -//////////////////////////////////////////////////////////// -xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr); - -//////////////////////////////////////////////////////////// -/// \brief Get default screen of a display (equivalent to XDefaultScreen) -/// -/// \param connection Connection of display -/// -/// \return Pointer to the default screen of the display -/// -//////////////////////////////////////////////////////////// -xcb_screen_t* XCBDefaultScreen(xcb_connection_t* connection); - -//////////////////////////////////////////////////////////// -/// \brief Get default root window of a display (equivalent to XDefaultRootWindow) -/// -/// \param connection Connection of display -/// -/// \return Root window of the display -/// -//////////////////////////////////////////////////////////// -xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection); - //////////////////////////////////////////////////////////// /// \brief Get the atom with the specified name /// /// \param name Name of the atom /// \param onlyIfExists Don't try to create the atom if it doesn't already exist /// -/// \return Atom if it exists or XCB_ATOM_NONE (0) if it doesn't +/// \return Atom if it exists or None (0) if it doesn't /// //////////////////////////////////////////////////////////// -xcb_atom_t getAtom(const std::string& name, bool onlyIfExists = false); +Atom getAtom(const std::string& name, bool onlyIfExists = false); } // namespace priv diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index 7251db2..4efee9f 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -194,8 +194,8 @@ GlxContext::~GlxContext() // Destroy the window if we own it if (m_window && m_ownsWindow) { - xcb_destroy_window(m_connection, m_window); - xcb_flush(m_connection); + XDestroyWindow(m_display, m_window); + XFlush(m_display); } // Close the connection with the X server @@ -211,7 +211,7 @@ GlFunctionPointer GlxContext::getFunction(const char* name) //////////////////////////////////////////////////////////// -bool GlxContext::makeCurrent() +bool GlxContext::makeCurrent(bool current) { if (!m_context) return false; @@ -222,13 +222,20 @@ bool GlxContext::makeCurrent() bool result = false; - if (m_pbuffer) + if (current) { - result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context); + if (m_pbuffer) + { + result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context); + } + else if (m_window) + { + result = glXMakeCurrent(m_display, m_window, m_context); + } } - else if (m_window) + else { - result = glXMakeCurrent(m_display, m_window, m_context); + result = glXMakeCurrent(m_display, None, NULL); } #if defined(GLX_DEBUGGING) @@ -444,7 +451,6 @@ void GlxContext::updateSettingsFromWindow() void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel) { m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); // Choose the visual according to the context settings XVisualInfo visualInfo = selectBestVisual(m_display, bitsPerPixel, m_settings); @@ -482,8 +488,11 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned if (visual->visualid == visualInfo.visualid) { config = &configs[i]; + XFree(visual); break; } + + XFree(visual); } if (config) @@ -510,28 +519,22 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned } // If pbuffers are not available we use a hidden window as the off-screen surface to draw to - xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display)); + int screen = DefaultScreen(m_display); // Define the window attributes - xcb_colormap_t colormap = xcb_generate_id(m_connection); - xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, screen->root, visualInfo.visualid); - const uint32_t value_list[] = {colormap}; - - // Create a dummy window (disabled and hidden) - m_window = xcb_generate_id(m_connection); - xcb_create_window( - m_connection, - static_cast(visualInfo.depth), - m_window, - screen->root, - 0, 0, - width, height, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - visualInfo.visualid, - XCB_CW_COLORMAP, - value_list - ); + XSetWindowAttributes attributes; + attributes.colormap = XCreateColormap(m_display, RootWindow(m_display, screen), visualInfo.visual, AllocNone); + + m_window = XCreateWindow(m_display, + RootWindow(m_display, screen), + 0, 0, + width, height, + 0, + DefaultDepth(m_display, screen), + InputOutput, + visualInfo.visual, + CWColormap, + &attributes); m_ownsWindow = true; @@ -543,7 +546,6 @@ void GlxContext::createSurface(GlxContext* shared, unsigned int width, unsigned void GlxContext::createSurface(::Window window) { m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); // A window already exists, so just use it m_window = window; @@ -640,8 +642,11 @@ void GlxContext::createContext(GlxContext* shared) if (visual->visualid == visualInfo->visualid) { config = &configs[i]; + XFree(visual); break; } + + XFree(visual); } if (!config) @@ -688,6 +693,15 @@ void GlxContext::createContext(GlxContext* shared) // On an error, glXCreateContextAttribsARB will return 0 anyway GlxErrorHandler handler(m_display); + if (toShare) + { + if (!glXMakeCurrent(m_display, None, NULL)) + { + err() << "Failed to deactivate shared context before sharing" << std::endl; + return; + } + } + // Create the context m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, &attributes[0]); @@ -734,6 +748,15 @@ void GlxContext::createContext(GlxContext* shared) GlxErrorHandler handler(m_display); #endif + if (toShare) + { + if (!glXMakeCurrent(m_display, None, NULL)) + { + err() << "Failed to deactivate shared context before sharing" << std::endl; + return; + } + } + // Create the context, using the target window's visual m_context = glXCreateContext(m_display, visualInfo, toShare, true); diff --git a/src/SFML/Window/Unix/GlxContext.hpp b/src/SFML/Window/Unix/GlxContext.hpp index 4a9444f..360906b 100644 --- a/src/SFML/Window/Unix/GlxContext.hpp +++ b/src/SFML/Window/Unix/GlxContext.hpp @@ -30,7 +30,7 @@ //////////////////////////////////////////////////////////// #include #include -#include +#include namespace sf @@ -94,10 +94,12 @@ public: //////////////////////////////////////////////////////////// /// \brief Activate the context as the current target for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); //////////////////////////////////////////////////////////// /// \brief Display what has been rendered to the context so far @@ -178,7 +180,6 @@ private: //////////////////////////////////////////////////////////// ::Display* m_display; ///< Connection to the X server ::Window m_window; ///< Window to which the context is attached - xcb_connection_t* m_connection; ///< Pointer to the xcb connection GLXContext m_context; ///< OpenGL context GLXPbuffer m_pbuffer; ///< GLX pbuffer ID if one was created bool m_ownsWindow; ///< Do we own the window associated to the context? diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp index ad62cd5..90cae1a 100644 --- a/src/SFML/Window/Unix/InputImpl.cpp +++ b/src/SFML/Window/Unix/InputImpl.cpp @@ -28,9 +28,8 @@ #include // important to be included first (conflict with None) #include #include -#include #include -#include +#include #include @@ -157,36 +156,26 @@ bool InputImpl::isKeyPressed(Keyboard::Key key) Display* display = OpenDisplay(); // Convert to keycode - xcb_keycode_t keycode = XKeysymToKeycode(display, keysym); - - CloseDisplay(display); - - ScopedXcbPtr error(NULL); - - // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Get the whole keyboard state - ScopedXcbPtr keymap( - xcb_query_keymap_reply( - connection, - xcb_query_keymap(connection), - &error - ) - ); + KeyCode keycode = XKeysymToKeycode(display, keysym); + if (keycode != 0) + { + // Get the whole keyboard state + char keys[32]; + XQueryKeymap(display, keys); - // Close the connection with the X server - CloseConnection(connection); + // Close the connection with the X server + CloseDisplay(display); - if (error) + // Check our keycode + return (keys[keycode / 8] & (1 << (keycode % 8))) != 0; + } + else { - err() << "Failed to query keymap" << std::endl; + // Close the connection with the X server + CloseDisplay(display); return false; } - - // Check our keycode - return (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0; } @@ -201,43 +190,30 @@ void InputImpl::setVirtualKeyboardVisible(bool /*visible*/) bool InputImpl::isMouseButtonPressed(Mouse::Button button) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - ScopedXcbPtr error(NULL); - - // Get pointer mask - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - XCBDefaultRootWindow(connection) - ), - &error - ) - ); - - // Close the connection with the X server - CloseConnection(connection); + Display* display = OpenDisplay(); - if (error) - { - err() << "Failed to query pointer" << std::endl; + // we don't care about these but they are required + ::Window root, child; + int wx, wy; + int gx, gy; - return false; - } + unsigned int buttons = 0; + XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &wx, &wy, &buttons); - uint16_t buttons = pointer->mask; + // Close the connection with the X server + CloseDisplay(display); switch (button) { - case Mouse::Left: return buttons & XCB_BUTTON_MASK_1; - case Mouse::Right: return buttons & XCB_BUTTON_MASK_3; - case Mouse::Middle: return buttons & XCB_BUTTON_MASK_2; + case Mouse::Left: return buttons & Button1Mask; + case Mouse::Right: return buttons & Button3Mask; + case Mouse::Middle: return buttons & Button2Mask; case Mouse::XButton1: return false; // not supported by X case Mouse::XButton2: return false; // not supported by X default: return false; } + + return false; } @@ -245,32 +221,21 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button) Vector2i InputImpl::getMousePosition() { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(NULL); + // we don't care about these but they are required + ::Window root, child; + int x, y; + unsigned int buttons; - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - XCBDefaultRootWindow(connection) - ), - &error - ) - ); + int gx = 0; + int gy = 0; + XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &x, &y, &buttons); // Close the connection with the X server - CloseConnection(connection); - - if (error) - { - err() << "Failed to query pointer" << std::endl; - - return Vector2i(0, 0); - } + CloseDisplay(display); - return Vector2i(pointer->root_x, pointer->root_y); + return Vector2i(gx, gy); } @@ -281,32 +246,21 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo) if (handle) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); - ScopedXcbPtr error(NULL); + // we don't care about these but they are required + ::Window root, child; + int gx, gy; + unsigned int buttons; - ScopedXcbPtr pointer( - xcb_query_pointer_reply( - connection, - xcb_query_pointer( - connection, - handle - ), - &error - ) - ); + int x = 0; + int y = 0; + XQueryPointer(display, handle, &root, &child, &gx, &gy, &x, &y, &buttons); // Close the connection with the X server - CloseConnection(connection); - - if (error) - { - err() << "Failed to query pointer" << std::endl; - - return Vector2i(0, 0); - } + CloseDisplay(display); - return Vector2i(pointer->win_x, pointer->win_y); + return Vector2i(x, y); } else { @@ -319,27 +273,13 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo) void InputImpl::setMousePosition(const Vector2i& position) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - ScopedXcbPtr error(xcb_request_check( - connection, - xcb_warp_pointer( - connection, - None, // Source window - XCBDefaultRootWindow(connection), // Destination window - 0, 0, // Source position - 0, 0, // Source size - position.x, position.y // Destination position - ) - )); - - if (error) - err() << "Failed to set mouse position" << std::endl; + Display* display = OpenDisplay(); - xcb_flush(connection); + XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y); + XFlush(display); // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); } @@ -347,31 +287,17 @@ void InputImpl::setMousePosition(const Vector2i& position) void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo) { // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); + Display* display = OpenDisplay(); WindowHandle handle = relativeTo.getSystemHandle(); if (handle) { - ScopedXcbPtr error(xcb_request_check( - connection, - xcb_warp_pointer( - connection, - None, // Source window - handle, // Destination window - 0, 0, // Source position - 0, 0, // Source size - position.x, position.y // Destination position - ) - )); - - if (error) - err() << "Failed to set mouse position" << std::endl; - - xcb_flush(connection); + XWarpPointer(display, None, handle, 0, 0, 0, 0, position.x, position.y); + XFlush(display); } // Close the connection with the X server - CloseConnection(connection); + CloseDisplay(display); } diff --git a/src/SFML/Window/Unix/ScopedXcbPtr.hpp b/src/SFML/Window/Unix/ScopedXcbPtr.hpp deleted file mode 100644 index f610d81..0000000 --- a/src/SFML/Window/Unix/ScopedXcbPtr.hpp +++ /dev/null @@ -1,102 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -#ifndef SFML_SCOPEDXCBPTR_HPP -#define SFML_SCOPEDXCBPTR_HPP - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include - - -namespace sf -{ -namespace priv -{ -//////////////////////////////////////////////////////////// -/// \brief Scoped pointer that frees memory returned in XCB replies -/// -//////////////////////////////////////////////////////////// -template -class ScopedXcbPtr -{ -public: - //////////////////////////////////////////////////////////// - /// \brief Constructor - /// - /// \param pointer Pointer value to store - /// - //////////////////////////////////////////////////////////// - ScopedXcbPtr(T* pointer); - - //////////////////////////////////////////////////////////// - /// \brief Destructor, calls std::free() on the stored pointer - /// - //////////////////////////////////////////////////////////// - ~ScopedXcbPtr(); - - //////////////////////////////////////////////////////////// - /// \brief Structure dereference operator - /// - /// \return Stored pointer - /// - //////////////////////////////////////////////////////////// - T* operator ->() const; - - //////////////////////////////////////////////////////////// - /// \brief Address operator. - /// - /// \return Address of the stored pointer - /// - //////////////////////////////////////////////////////////// - T** operator &(); - - //////////////////////////////////////////////////////////// - /// \brief Check if stored pointer is valid - /// - /// \return true if stored pointer is valid - /// - //////////////////////////////////////////////////////////// - operator bool() const; - - //////////////////////////////////////////////////////////// - /// \brief Retrieve the stored pointer. - /// - /// \return The stored pointer - /// - //////////////////////////////////////////////////////////// - T* get() const; - -private: - T* m_pointer; ///< Stored pointer -}; - -#include - -} // namespace priv - -} // namespace sf - -#endif // SFML_SCOPEDXCBPTR_HPP diff --git a/src/SFML/Window/Unix/ScopedXcbPtr.inl b/src/SFML/Window/Unix/ScopedXcbPtr.inl deleted file mode 100644 index 5869d91..0000000 --- a/src/SFML/Window/Unix/ScopedXcbPtr.inl +++ /dev/null @@ -1,72 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////// -template -inline ScopedXcbPtr::ScopedXcbPtr(T* pointer) : -m_pointer(pointer) -{ - -} - - -//////////////////////////////////////////////////////////// -template -inline ScopedXcbPtr::~ScopedXcbPtr() -{ - std::free(m_pointer); -} - - -//////////////////////////////////////////////////////////// -template -inline T* ScopedXcbPtr::operator ->() const -{ - return m_pointer; -} - - -//////////////////////////////////////////////////////////// -template -inline T** ScopedXcbPtr::operator &() -{ - return &m_pointer; -} - - -//////////////////////////////////////////////////////////// -template -inline ScopedXcbPtr::operator bool() const -{ - return m_pointer != NULL; -} - - -//////////////////////////////////////////////////////////// -template -inline T* ScopedXcbPtr::get() const -{ - return m_pointer; -} diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp index f95d323..cd78c54 100644 --- a/src/SFML/Window/Unix/VideoModeImpl.cpp +++ b/src/SFML/Window/Unix/VideoModeImpl.cpp @@ -27,9 +27,9 @@ //////////////////////////////////////////////////////////// #include #include -#include #include -#include +#include +#include #include @@ -43,95 +43,78 @@ std::vector VideoModeImpl::getFullscreenModes() std::vector modes; // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Retrieve the default screen - xcb_screen_t* screen = XCBDefaultScreen(connection); - - ScopedXcbPtr error(NULL); - - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) - { - // Randr extension is not supported: we cannot get the video modes - err() << "Failed to use the RandR extension while trying to get the supported video modes" << std::endl; - - // Close the connection with the X server - CloseConnection(connection); - - return modes; - } - - // Load RandR and check its version - ScopedXcbPtr randrVersion(xcb_randr_query_version_reply( - connection, - xcb_randr_query_version( - connection, - 1, - 1 - ), - &error - )); - - if (error) - { - err() << "Failed to load the RandR extension while trying to get the supported video modes" << std::endl; - - // Close the connection with the X server - CloseConnection(connection); - - return modes; - } - - // Get the current configuration - ScopedXcbPtr config(xcb_randr_get_screen_info_reply( - connection, - xcb_randr_get_screen_info( - connection, - screen->root - ), - &error - )); - - if (error) + Display* display = OpenDisplay(); + if (display) { - // Failed to get the screen configuration - err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl; + // Retrieve the default screen number + int screen = DefaultScreen(display); - // Close the connection with the X server - CloseConnection(connection); - - return modes; - } - - // Get the available screen sizes - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - if (sizes && (config->nSizes > 0)) - { - // Get the list of supported depths - xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen); - // Combine depths and sizes to fill the array of supported modes - for (; iter.rem; xcb_depth_next(&iter)) + // Check if the XRandR extension is present + int version; + if (XQueryExtension(display, "RANDR", &version, &version, &version)) { - for (int j = 0; j < config->nSizes; ++j) + // Get the current configuration + XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); + if (config) { - // Convert to VideoMode - VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth); - - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(mode.width, mode.height); - - // Add it only if it is not already in the array - if (std::find(modes.begin(), modes.end(), mode) == modes.end()) - modes.push_back(mode); + // Get the available screen sizes + int nbSizes; + XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); + if (sizes && (nbSizes > 0)) + { + // Get the list of supported depths + int nbDepths = 0; + int* depths = XListDepths(display, screen, &nbDepths); + if (depths && (nbDepths > 0)) + { + // Combine depths and sizes to fill the array of supported modes + for (int i = 0; i < nbDepths; ++i) + { + for (int j = 0; j < nbSizes; ++j) + { + // Convert to VideoMode + VideoMode mode(sizes[j].width, sizes[j].height, depths[i]); + + Rotation currentRotation; + XRRConfigRotations(config, ¤tRotation); + + if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) + std::swap(mode.width, mode.height); + + // Add it only if it is not already in the array + if (std::find(modes.begin(), modes.end(), mode) == modes.end()) + modes.push_back(mode); + } + } + + // Free the array of depths + XFree(depths); + } + } + + // Free the configuration instance + XRRFreeScreenConfigInfo(config); + } + else + { + // Failed to get the screen configuration + err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl; } } - } + else + { + // XRandr extension is not supported: we cannot get the video modes + err() << "Failed to use the XRandR extension while trying to get the supported video modes" << std::endl; + } - // Close the connection with the X server - CloseConnection(connection); + // Close the connection with the X server + CloseDisplay(display); + } + else + { + // We couldn't connect to the X server + err() << "Failed to connect to the X server while trying to get the supported video modes" << std::endl; + } return modes; } @@ -143,91 +126,62 @@ VideoMode VideoModeImpl::getDesktopMode() VideoMode desktopMode; // Open a connection with the X server - xcb_connection_t* connection = OpenConnection(); - - // Retrieve the default screen - xcb_screen_t* screen = XCBDefaultScreen(connection); - - ScopedXcbPtr error(NULL); - - // Check if the RandR extension is present - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) - { - // Randr extension is not supported: we cannot get the video modes - err() << "Failed to use the RandR extension while trying to get the desktop video mode" << std::endl; - - // Close the connection with the X server - CloseConnection(connection); - - return desktopMode; - } - - // Load RandR and check its version - ScopedXcbPtr randrVersion(xcb_randr_query_version_reply( - connection, - xcb_randr_query_version( - connection, - 1, - 1 - ), - &error - )); - - if (error) + Display* display = OpenDisplay(); + if (display) { - err() << "Failed to load the RandR extension while trying to get the desktop video mode" << std::endl; - - // Close the connection with the X server - CloseConnection(connection); - - return desktopMode; - } + // Retrieve the default screen number + int screen = DefaultScreen(display); - // Get the current configuration - ScopedXcbPtr config(xcb_randr_get_screen_info_reply( - connection, - xcb_randr_get_screen_info( - connection, - screen->root - ), - &error - )); - - if (error) - { - // Failed to get the screen configuration - err() << "Failed to retrieve the screen configuration while trying to get the desktop video mode" << std::endl; + // Check if the XRandR extension is present + int version; + if (XQueryExtension(display, "RANDR", &version, &version, &version)) + { + // Get the current configuration + XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); + if (config) + { + // Get the current video mode + Rotation currentRotation; + int currentMode = XRRConfigCurrentConfiguration(config, ¤tRotation); + + // Get the available screen sizes + int nbSizes; + XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); + if (sizes && (nbSizes > 0)) + { + desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, DefaultDepth(display, screen)); + + Rotation currentRotation; + XRRConfigRotations(config, ¤tRotation); + + if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) + std::swap(desktopMode.width, desktopMode.height); + } + + // Free the configuration instance + XRRFreeScreenConfigInfo(config); + } + else + { + // Failed to get the screen configuration + err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl; + } + } + else + { + // XRandr extension is not supported: we cannot get the video modes + err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl; + } // Close the connection with the X server - CloseConnection(connection); - - return desktopMode; - } - - // Get the current video mode - xcb_randr_mode_t currentMode = config->sizeID; - - // Get the available screen sizes - int nbSizes = xcb_randr_get_screen_info_sizes_length(config.get()); - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - if (sizes && (nbSizes > 0)) - { - desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth); - - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) - std::swap(desktopMode.width, desktopMode.height); + CloseDisplay(display); } else { - err() << "Failed to retrieve any screen sizes while trying to get the desktop video mode" << std::endl; + // We couldn't connect to the X server + err() << "Failed to connect to the X server while trying to get the desktop video modes" << std::endl; } - // Close the connection with the X server - CloseConnection(connection); - return desktopMode; } diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 88176bf..530bea5 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -29,15 +29,16 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include +#include +#include +#include +#include #include #include #include @@ -66,12 +67,12 @@ namespace sf::Mutex allWindowsMutex; sf::String windowManagerName; - static const unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | - XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS | - XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | - XCB_EVENT_MASK_VISIBILITY_CHANGE; + static const unsigned long eventMask = FocusChangeMask | ButtonPressMask | + ButtonReleaseMask | ButtonMotionMask | + PointerMotionMask | KeyPressMask | + KeyReleaseMask | StructureNotifyMask | + EnterWindowMask | LeaveWindowMask | + VisibilityChangeMask | PropertyChangeMask; static const unsigned int maxTrialsCount = 5; @@ -127,76 +128,88 @@ namespace checked = true; - xcb_connection_t* connection = sf::priv::OpenConnection(); - - xcb_atom_t netSupportingWmCheck = sf::priv::getAtom("_NET_SUPPORTING_WM_CHECK", true); - xcb_atom_t netSupported = sf::priv::getAtom("_NET_SUPPORTED", true); + Atom netSupportingWmCheck = sf::priv::getAtom("_NET_SUPPORTING_WM_CHECK", true); + Atom netSupported = sf::priv::getAtom("_NET_SUPPORTED", true); if (!netSupportingWmCheck || !netSupported) return false; - sf::priv::ScopedXcbPtr error(NULL); - - sf::priv::ScopedXcbPtr rootSupportingWindow(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - sf::priv::XCBDefaultRootWindow(connection), - netSupportingWmCheck, - XCB_ATOM_WINDOW, - 0, - 1 - ), - &error - )); - - if (!rootSupportingWindow || rootSupportingWindow->length != 1) + ::Display* display = sf::priv::OpenDisplay(); + + Atom actualType; + int actualFormat; + unsigned long numItems; + unsigned long numBytes; + unsigned char* data; + + int result = XGetWindowProperty(display, + DefaultRootWindow(display), + netSupportingWmCheck, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); + + if (result != Success || actualType != XA_WINDOW || numItems != 1) { - sf::priv::CloseConnection(connection); + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return false; } - xcb_window_t* rootWindow = reinterpret_cast(xcb_get_property_value(rootSupportingWindow.get())); + ::Window rootWindow = *reinterpret_cast< ::Window* >(data); + + XFree(data); if (!rootWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } - sf::priv::ScopedXcbPtr childSupportingWindow(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - *rootWindow, - netSupportingWmCheck, - XCB_ATOM_WINDOW, - 0, - 1 - ), - &error - )); - - if (!childSupportingWindow || childSupportingWindow->length != 1) + result = XGetWindowProperty(display, + rootWindow, + netSupportingWmCheck, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); + + if (result != Success || actualType != XA_WINDOW || numItems != 1) { - sf::priv::CloseConnection(connection); + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return false; } - xcb_window_t* childWindow = reinterpret_cast(xcb_get_property_value(childSupportingWindow.get())); + ::Window childWindow = *reinterpret_cast< ::Window* >(data); + + XFree(data); if (!childWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } // Conforming window managers should return the same window for both queries - if (*rootWindow != *childWindow) + if (rootWindow != childWindow) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return false; } @@ -204,45 +217,51 @@ namespace // We try to get the name of the window manager // for window manager specific workarounds - xcb_atom_t netWmName = sf::priv::getAtom("_NET_WM_NAME", true); - xcb_atom_t utf8StringType = sf::priv::getAtom("UTF8_STRING"); - - if (!utf8StringType) - utf8StringType = XCB_ATOM_STRING; + Atom netWmName = sf::priv::getAtom("_NET_WM_NAME", true); if (!netWmName) { - sf::priv::CloseConnection(connection); + sf::priv::CloseDisplay(display); return true; } - sf::priv::ScopedXcbPtr wmName(xcb_get_property_reply( - connection, - xcb_get_property( - connection, - 0, - *childWindow, - netWmName, - utf8StringType, - 0, - 0x7fffffff - ), - &error - )); - - sf::priv::CloseConnection(connection); - - // It seems the wm name string reply is not necessarily - // null-terminated. The work around is to get its actual - // length to build a proper string - const char* begin = reinterpret_cast(xcb_get_property_value(wmName.get())); - const char* end = begin + xcb_get_property_value_length(wmName.get()); - windowManagerName = sf::String::fromUtf8(begin, end); + Atom utf8StringType = sf::priv::getAtom("UTF8_STRING"); + + if (!utf8StringType) + utf8StringType = XA_STRING; + + result = XGetWindowProperty(display, + rootWindow, + netWmName, + 0, + 0x7fffffff, + False, + utf8StringType, + &actualType, + &actualFormat, + &numItems, + &numBytes, + &data); + + if (actualType && numItems) + { + // It seems the wm name string reply is not necessarily + // null-terminated. The work around is to get its actual + // length to build a proper string + const char* begin = reinterpret_cast(data); + const char* end = begin + numItems; + windowManagerName = sf::String::fromUtf8(begin, end); + } + + if(result == Success) + XFree(data); + + sf::priv::CloseDisplay(display); return true; } - sf::Keyboard::Key keysymToSF(xcb_keysym_t symbol) + sf::Keyboard::Key keysymToSF(KeySym symbol) { switch (symbol) { @@ -362,34 +381,29 @@ namespace priv //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(WindowHandle handle) : m_window (0), -m_screen (NULL), +m_screen (0), m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (true), +m_oldVideoMode (0), m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), m_useSizeHints (false), m_fullscreen (false), m_cursorGrabbed (false), -m_windowMapped (false) +m_windowMapped (false), +m_iconPixmap (0), +m_iconMaskPixmap (0), +m_lastInputTime (0) { // Open a connection with the X server m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); - - std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); - - if (!m_connection) - { - err() << "Failed cast Display object to an XCB connection object" << std::endl; - return; - } // Make sure to check for EWMH support before we do anything ewmhSupported(); - m_screen = XCBDefaultScreen(m_connection); + m_screen = DefaultScreen(m_display); // Save the window handle m_window = handle; @@ -397,14 +411,10 @@ m_windowMapped (false) if (m_window) { // Make sure the window is listening to all the required events - const uint32_t value_list[] = {static_cast(eventMask)}; + XSetWindowAttributes attributes; + attributes.event_mask = eventMask; - xcb_change_window_attributes( - m_connection, - m_window, - XCB_CW_EVENT_MASK, - value_list - ); + XChangeWindowAttributes(m_display, m_window, CWEventMask, &attributes); // Set the WM protocols setProtocols(); @@ -418,38 +428,33 @@ m_windowMapped (false) //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) : m_window (0), -m_screen (NULL), +m_screen (0), m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (false), +m_oldVideoMode (0), m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), m_useSizeHints (false), m_fullscreen ((style & Style::Fullscreen) != 0), m_cursorGrabbed (m_fullscreen), -m_windowMapped (false) +m_windowMapped (false), +m_iconPixmap (0), +m_iconMaskPixmap (0), +m_lastInputTime (0) { // Open a connection with the X server m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); - - std::memset(&m_oldVideoMode, 0, sizeof(m_oldVideoMode)); - - if (!m_connection) - { - err() << "Failed cast Display object to an XCB connection object" << std::endl; - return; - } // Make sure to check for EWMH support before we do anything ewmhSupported(); - m_screen = XCBDefaultScreen(m_connection); + m_screen = DefaultScreen(m_display); // Compute position and size - int left = m_fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2; - int top = m_fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2; + int left = m_fullscreen ? 0 : (DisplayWidth(m_display, m_screen) - mode.width) / 2; + int top = m_fullscreen ? 0 : (DisplayHeight(m_display, m_screen) - mode.height) / 2; int width = mode.width; int height = mode.height; @@ -457,31 +462,23 @@ m_windowMapped (false) XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings); // Define the window attributes - xcb_colormap_t colormap = xcb_generate_id(m_connection); - xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, m_screen->root, visualInfo.visualid); - const uint32_t value_list[] = {m_fullscreen && !ewmhSupported(), static_cast(eventMask), colormap}; - - // Create the window - m_window = xcb_generate_id(m_connection); - - ScopedXcbPtr errptr(xcb_request_check( - m_connection, - xcb_create_window_checked( - m_connection, - static_cast(visualInfo.depth), - m_window, - m_screen->root, - left, top, - width, height, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - visualInfo.visualid, - XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP, - value_list - ) - )); - - if (errptr) + XSetWindowAttributes attributes; + attributes.colormap = XCreateColormap(m_display, DefaultRootWindow(m_display), visualInfo.visual, AllocNone); + attributes.event_mask = eventMask; + attributes.override_redirect = (m_fullscreen && !ewmhSupported()) ? True : False; + + m_window = XCreateWindow(m_display, + DefaultRootWindow(m_display), + left, top, + width, height, + 0, + visualInfo.depth, + InputOutput, + visualInfo.visual, + CWEventMask | CWOverrideRedirect | CWColormap, + &attributes); + + if (!m_window) { err() << "Failed to create window" << std::endl; return; @@ -491,54 +488,113 @@ m_windowMapped (false) setProtocols(); // Set the WM initial state to the normal state - WMHints hints; - std::memset(&hints, 0, sizeof(hints)); - hints.initial_state = 1; - hints.flags |= 1 << 1; - setWMHints(hints); + XWMHints* hints = XAllocWMHints(); + hints->flags = StateHint; + hints->initial_state = NormalState; + XSetWMHints(m_display, m_window, hints); + XFree(hints); // If not in fullscreen, set the window's style (tell the window manager to // change our window's decorations and functions according to the requested style) if (!m_fullscreen) - setMotifHints(style); + { + Atom WMHintsAtom = getAtom("_MOTIF_WM_HINTS", false); + if (WMHintsAtom) + { + static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; + static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1; + + //static const unsigned long MWM_DECOR_ALL = 1 << 0; + static const unsigned long MWM_DECOR_BORDER = 1 << 1; + static const unsigned long MWM_DECOR_RESIZEH = 1 << 2; + static const unsigned long MWM_DECOR_TITLE = 1 << 3; + static const unsigned long MWM_DECOR_MENU = 1 << 4; + static const unsigned long MWM_DECOR_MINIMIZE = 1 << 5; + static const unsigned long MWM_DECOR_MAXIMIZE = 1 << 6; + + //static const unsigned long MWM_FUNC_ALL = 1 << 0; + static const unsigned long MWM_FUNC_RESIZE = 1 << 1; + static const unsigned long MWM_FUNC_MOVE = 1 << 2; + static const unsigned long MWM_FUNC_MINIMIZE = 1 << 3; + static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4; + static const unsigned long MWM_FUNC_CLOSE = 1 << 5; + + struct WMHints + { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long inputMode; + unsigned long state; + }; + + WMHints hints; + std::memset(&hints, 0, sizeof(hints)); + hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; + hints.decorations = 0; + hints.functions = 0; + + if (style & Style::Titlebar) + { + hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; + hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; + } + if (style & Style::Resize) + { + hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; + hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; + } + if (style & Style::Close) + { + hints.decorations |= 0; + hints.functions |= MWM_FUNC_CLOSE; + } - WMSizeHints sizeHints; - std::memset(&sizeHints, 0, sizeof(sizeHints)); + XChangeProperty(m_display, + m_window, + WMHintsAtom, + WMHintsAtom, + 32, + PropModeReplace, + reinterpret_cast(&hints), + 5); + } + } // This is a hack to force some windows managers to disable resizing - // Fullscreen is bugged on Openbox. Unless size hints are set, there - // will be a region of the window that is off-screen. We try to workaround - // this by setting size hints even in fullscreen just for Openbox. - if ((!m_fullscreen || (windowManagerName == "Openbox")) && !(style & Style::Resize)) + if (!(style & Style::Resize)) { m_useSizeHints = true; - sizeHints.flags |= ((1 << 4) | (1 << 5)); - sizeHints.min_width = width; - sizeHints.max_width = width; - sizeHints.min_height = height; - sizeHints.max_height = height; + XSizeHints* sizeHints = XAllocSizeHints(); + sizeHints->flags = PMinSize | PMaxSize; + sizeHints->min_width = sizeHints->max_width = width; + sizeHints->min_height = sizeHints->max_height = height; + XSetWMNormalHints(m_display, m_window, sizeHints); + XFree(sizeHints); } - // Set the WM hints of the normal state - setWMSizeHints(sizeHints); - // Set the window's WM class (this can be used by window managers) - // The WM_CLASS property actually consists of 2 parts, - // the instance name and the class name both of which should be - // null terminated strings. - // The instance name should be something unique to this invokation + XClassHint* hint = XAllocClassHint(); + + // The instance name should be something unique to this invocation // of the application but is rarely if ever used these days. // For simplicity, we retrieve it via the base executable name. + std::string executableName = findExecutableName(); + std::vector windowInstance(executableName.size() + 1, 0); + std::copy(executableName.begin(), executableName.end(), windowInstance.begin()); + hint->res_name = &windowInstance[0]; + // The class name identifies a class of windows that // "are of the same type". We simply use the initial window name as // the class name. - std::string windowClass = findExecutableName(); - windowClass += '\0'; // Important to separate instance from class - windowClass += title.toAnsiString(); + std::string ansiTitle = title.toAnsiString(); + std::vector windowClass(ansiTitle.size() + 1, 0); + std::copy(ansiTitle.begin(), ansiTitle.end(), windowClass.begin()); + hint->res_class = &windowClass[0]; + + XSetClassHint(m_display, m_window, hint); - // We add 1 to the size of the string to include the null at the end - if (!changeWindowProperty(XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, windowClass.size() + 1, windowClass.c_str())) - sf::err() << "Failed to set WM_CLASS property" << std::endl; + XFree(hint); // Set the window's name setTitle(title); @@ -562,18 +618,27 @@ WindowImplX11::~WindowImplX11() // Cleanup graphical resources cleanup(); + // Destroy icon pixmap + if(m_iconPixmap) + XFreePixmap(m_display, m_iconPixmap); + + // Destroy icon mask pixmap + if(m_iconMaskPixmap) + XFreePixmap(m_display, m_iconMaskPixmap); + // Destroy the cursor if (m_hiddenCursor) - xcb_free_cursor(m_connection, m_hiddenCursor); + XFreeCursor(m_display, m_hiddenCursor); // Destroy the input context if (m_inputContext) XDestroyIC(m_inputContext); + // Destroy the window if (m_window && !m_isExternal) { - xcb_destroy_window(m_connection, m_window); - xcb_flush(m_connection); + XDestroyWindow(m_display, m_window); + XFlush(m_display); } // Close the input method @@ -610,70 +675,31 @@ void WindowImplX11::processEvents() //////////////////////////////////////////////////////////// Vector2i WindowImplX11::getPosition() const { - ::Window topLevelWindow = m_window; - ::Window nextWindow = topLevelWindow; + ::Window root, child; + int localX, localY, x, y; + unsigned int width, height, border, depth; - ScopedXcbPtr error(NULL); + XGetGeometry(m_display, m_window, &root, &localX, &localY, &width, &height, &border, &depth); + XTranslateCoordinates(m_display, m_window, root, localX, localY, &x, &y, &child); - // Get "top level" window, i.e. the window with the root window as its parent. - while (nextWindow != m_screen->root) - { - topLevelWindow = nextWindow; - - ScopedXcbPtr treeReply(xcb_query_tree_reply( - m_connection, - xcb_query_tree( - m_connection, - topLevelWindow - ), - &error - )); - - if (error) - { - err() << "Failed to get window position (query_tree)" << std::endl; - return Vector2i(0, 0); - } - - nextWindow = treeReply->parent; - } - - ScopedXcbPtr geometryReply(xcb_get_geometry_reply( - m_connection, - xcb_get_geometry( - m_connection, - topLevelWindow - ), - &error - )); - - if (error) - { - err() << "Failed to get window position (get_geometry)" << std::endl; - return Vector2i(0, 0); - } - - return Vector2i(geometryReply->x, geometryReply->y); + return Vector2i(x, y); } //////////////////////////////////////////////////////////// void WindowImplX11::setPosition(const Vector2i& position) { - uint32_t values[] = {static_cast(position.x), static_cast(position.y)}; - xcb_configure_window(m_connection, m_window, - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, - values); - xcb_flush(m_connection); + XMoveWindow(m_display, m_window, position.x, position.y); + XFlush(m_display); } //////////////////////////////////////////////////////////// Vector2u WindowImplX11::getSize() const { - ScopedXcbPtr reply(xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL)); - - return Vector2u(reply->width, reply->height); + XWindowAttributes attributes; + XGetWindowAttributes(m_display, m_window, &attributes); + return Vector2u(attributes.width, attributes.height); } @@ -681,75 +707,65 @@ Vector2u WindowImplX11::getSize() const void WindowImplX11::setSize(const Vector2u& size) { // If resizing is disable for the window we have to update the size hints (required by some window managers). - if( m_useSizeHints ) { - WMSizeHints sizeHints; - std::memset(&sizeHints, 0, sizeof(sizeHints)); - - sizeHints.flags |= (1 << 4 | 1 << 5); - sizeHints.min_width = size.x; - sizeHints.max_width = size.x; - sizeHints.min_height = size.y; - sizeHints.max_height = size.y; - - setWMSizeHints(sizeHints); + if (m_useSizeHints) + { + XSizeHints* sizeHints = XAllocSizeHints(); + sizeHints->flags = PMinSize | PMaxSize; + sizeHints->min_width = sizeHints->max_width = size.x; + sizeHints->min_height = sizeHints->max_height = size.y; + XSetWMNormalHints(m_display, m_window, sizeHints); + XFree(sizeHints); } - uint32_t values[] = {size.x, size.y}; - - ScopedXcbPtr configureWindowError(xcb_request_check( - m_connection, - xcb_configure_window( - m_connection, - m_window, - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - values - ) - )); - - if (configureWindowError) - err() << "Failed to set window size" << std::endl; - - xcb_flush(m_connection); + XResizeWindow(m_display, m_window, size.x, size.y); + XFlush(m_display); } //////////////////////////////////////////////////////////// void WindowImplX11::setTitle(const String& title) { - // XCB takes UTF-8-encoded strings. - xcb_atom_t utf8StringType = getAtom("UTF8_STRING"); - - if (!utf8StringType) - utf8StringType = XCB_ATOM_STRING; - - std::string utf8String; - Utf<32>::toUtf8(title.begin(), title.end(), std::back_inserter(utf8String)); - - if (!changeWindowProperty(XCB_ATOM_WM_NAME, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set window title" << std::endl; - - if (!changeWindowProperty(XCB_ATOM_WM_ICON_NAME, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set WM_ICON_NAME property" << std::endl; - - if (ewmhSupported()) - { - xcb_atom_t netWmName = getAtom("_NET_WM_NAME", true); - xcb_atom_t netWmIconName = getAtom("_NET_WM_ICON_NAME", true); - - if (utf8StringType && netWmName) - { - if (!changeWindowProperty(netWmName, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set _NET_WM_NAME property" << std::endl; - } - - if (utf8StringType && netWmIconName) - { - if (!changeWindowProperty(netWmIconName, utf8StringType, 8, utf8String.length(), utf8String.c_str())) - err() << "Failed to set _NET_WM_ICON_NAME property" << std::endl; - } - } - - xcb_flush(m_connection); + // 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)); + + Atom useUtf8 = getAtom("UTF8_STRING", false); + + // Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title. + Atom wmName = getAtom("_NET_WM_NAME", false); + XChangeProperty(m_display, m_window, wmName, useUtf8, 8, + PropModeReplace, utf8Title.c_str(), utf8Title.size()); + + // Set the _NET_WM_ICON_NAME atom, which specifies a UTF-8 encoded window title. + Atom wmIconName = getAtom("_NET_WM_ICON_NAME", false); + XChangeProperty(m_display, m_window, wmIconName, useUtf8, 8, + PropModeReplace, utf8Title.c_str(), utf8Title.size()); + + // Set the non-Unicode title as a fallback for window managers who don't support _NET_WM_NAME. + #ifdef X_HAVE_UTF8_STRING + Xutf8SetWMProperties(m_display, + m_window, + title.toAnsiString().c_str(), + title.toAnsiString().c_str(), + NULL, + 0, + NULL, + NULL, + NULL); + #else + XmbSetWMProperties(m_display, + m_window, + title.toAnsiString().c_str(), + title.toAnsiString().c_str(), + NULL, + 0, + NULL, + NULL, + NULL); + #endif } @@ -757,99 +773,42 @@ void WindowImplX11::setTitle(const String& title) void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels) { // X11 wants BGRA pixels: swap red and blue channels - Uint8 iconPixels[width * height * 4]; + // Note: this memory will be freed by XDestroyImage + Uint8* iconPixels = static_cast(std::malloc(width * height * 4)); for (std::size_t i = 0; i < width * height; ++i) { - iconPixels[i * 4 + 0] = pixels[i * 4 + 2]; - iconPixels[i * 4 + 1] = pixels[i * 4 + 1]; - iconPixels[i * 4 + 2] = pixels[i * 4 + 0]; - iconPixels[i * 4 + 3] = pixels[i * 4 + 3]; + iconPixels[8 + i * 4 + 0] = pixels[i * 4 + 2]; + iconPixels[8 + i * 4 + 1] = pixels[i * 4 + 1]; + iconPixels[8 + i * 4 + 2] = pixels[i * 4 + 0]; + iconPixels[8 + i * 4 + 3] = pixels[i * 4 + 3]; } // Create the icon pixmap - xcb_pixmap_t iconPixmap = xcb_generate_id(m_connection); - - ScopedXcbPtr createPixmapError(xcb_request_check( - m_connection, - xcb_create_pixmap_checked( - m_connection, - m_screen->root_depth, - iconPixmap, - m_screen->root, - width, - height - ) - )); - - if (createPixmapError) + Visual* defVisual = DefaultVisual(m_display, m_screen); + unsigned int defDepth = DefaultDepth(m_display, m_screen); + XImage* iconImage = XCreateImage(m_display, defVisual, defDepth, ZPixmap, 0, (char*)iconPixels, width, height, 32, 0); + if (!iconImage) { - err() << "Failed to set the window's icon (create_pixmap): "; - err() << "Error code " << static_cast(createPixmapError->error_code) << std::endl; + err() << "Failed to set the window's icon" << std::endl; return; } - xcb_gcontext_t iconGC = xcb_generate_id(m_connection); - - ScopedXcbPtr createGcError(xcb_request_check( - m_connection, - xcb_create_gc( - m_connection, - iconGC, - iconPixmap, - 0, - NULL - ) - )); - - if (createGcError) - { - err() << "Failed to set the window's icon (create_gc): "; - err() << "Error code " << static_cast(createGcError->error_code) << std::endl; - return; - } + if(m_iconPixmap) + XFreePixmap(m_display, m_iconPixmap); - ScopedXcbPtr putImageError(xcb_request_check( - m_connection, - xcb_put_image_checked( - m_connection, - XCB_IMAGE_FORMAT_Z_PIXMAP, - iconPixmap, - iconGC, - width, - height, - 0, - 0, - 0, - m_screen->root_depth, - sizeof(iconPixels), - iconPixels - ) - )); - - ScopedXcbPtr freeGcError(xcb_request_check( - m_connection, - xcb_free_gc( - m_connection, - iconGC - ) - )); - - if (freeGcError) - { - err() << "Failed to free icon GC: "; - err() << "Error code " << static_cast(freeGcError->error_code) << std::endl; - } + if(m_iconMaskPixmap) + XFreePixmap(m_display, m_iconMaskPixmap); - if (putImageError) - { - err() << "Failed to set the window's icon (put_image): "; - err() << "Error code " << static_cast(putImageError->error_code) << std::endl; - return; - } + m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth); + XGCValues values; + GC iconGC = XCreateGC(m_display, m_iconPixmap, 0, &values); + XPutImage(m_display, m_iconPixmap, iconGC, iconImage, 0, 0, 0, 0, width, height); + XFreeGC(m_display, iconGC); + XDestroyImage(iconImage); // Create the mask pixmap (must have 1 bit depth) std::size_t pitch = (width + 7) / 8; - static std::vector maskPixels(pitch * height, 0); + std::vector maskPixels(pitch * height, 0); for (std::size_t j = 0; j < height; ++j) { for (std::size_t i = 0; i < pitch; ++i) @@ -864,43 +823,42 @@ 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, - reinterpret_cast(&maskPixels[0]), - width, - height, - 1, - 0, - 1, - NULL - ); + m_iconMaskPixmap = XCreatePixmapFromBitmapData(m_display, m_window, (char*)&maskPixels[0], width, height, 1, 0, 1); // Send our new icon to the window through the WMHints - WMHints hints; - std::memset(&hints, 0, sizeof(hints)); - hints.flags |= ((1 << 2) | (1 << 5)); - hints.icon_pixmap = iconPixmap; - hints.icon_mask = maskPixmap; - - setWMHints(hints); + XWMHints* hints = XAllocWMHints(); + hints->flags = IconPixmapHint | IconMaskHint; + hints->icon_pixmap = m_iconPixmap; + hints->icon_mask = m_iconMaskPixmap; + XSetWMHints(m_display, m_window, hints); + XFree(hints); + + // ICCCM wants BGRA pixels: swap red and blue channels + // ICCCM also wants the first 2 unsigned 32-bit values to be width and height + std::vector icccmIconPixels(8 + width * height * 4, 0); + for (std::size_t i = 0; i < width * height; ++i) + { + icccmIconPixels[8 + i * 4 + 0] = pixels[i * 4 + 2]; + icccmIconPixels[8 + i * 4 + 1] = pixels[i * 4 + 1]; + icccmIconPixels[8 + i * 4 + 2] = pixels[i * 4 + 0]; + icccmIconPixels[8 + i * 4 + 3] = pixels[i * 4 + 3]; + } - xcb_flush(m_connection); + reinterpret_cast(&icccmIconPixels[0])[0] = width; + reinterpret_cast(&icccmIconPixels[0])[1] = height; - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap_checked( - m_connection, - iconPixmap - ) - )); + Atom netWmIcon = getAtom("_NET_WM_ICON"); - if (freePixmapError) - { - err() << "Failed to free icon pixmap: "; - err() << "Error code " << static_cast(freePixmapError->error_code) << std::endl; - } + XChangeProperty(m_display, + m_window, + netWmIcon, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&icccmIconPixels[0]), + 2 + width * height); + + XFlush(m_display); } @@ -909,42 +867,24 @@ void WindowImplX11::setVisible(bool visible) { if (visible) { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_map_window( - m_connection, - m_window - ) - )); - - if (error) - err() << "Failed to change window visibility" << std::endl; + XMapWindow(m_display, m_window); - xcb_flush(m_connection); + XFlush(m_display); // Before continuing, make sure the WM has // internally marked the window as viewable - while (!m_windowMapped) + while (!m_windowMapped && !m_isExternal) processEvents(); } else { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_unmap_window( - m_connection, - m_window - ) - )); + XUnmapWindow(m_display, m_window); - if (error) - err() << "Failed to change window visibility" << std::endl; - - xcb_flush(m_connection); + XFlush(m_display); // Before continuing, make sure the WM has // internally marked the window as unviewable - while (m_windowMapped) + while (m_windowMapped && !m_isExternal) processEvents(); } } @@ -953,22 +893,8 @@ void WindowImplX11::setVisible(bool visible) //////////////////////////////////////////////////////////// void WindowImplX11::setMouseCursorVisible(bool visible) { - const uint32_t values = visible ? XCB_NONE : m_hiddenCursor; - - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_change_window_attributes( - m_connection, - m_window, - XCB_CW_CURSOR, - &values - ) - )); - - if (error) - err() << "Failed to change mouse cursor visibility" << std::endl; - - xcb_flush(m_connection); + XDefineCursor(m_display, m_window, visible ? None : m_hiddenCursor); + XFlush(m_display); } @@ -984,25 +910,9 @@ void WindowImplX11::setMouseCursorGrabbed(bool grabbed) // Try multiple times to grab the cursor for (unsigned int trial = 0; trial < maxTrialsCount; ++trial) { - sf::priv::ScopedXcbPtr error(NULL); + int result = XGrabPointer(m_display, m_window, True, None, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); - sf::priv::ScopedXcbPtr grabPointerReply(xcb_grab_pointer_reply( - m_connection, - xcb_grab_pointer( - m_connection, - true, - m_window, - XCB_NONE, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, - m_window, - XCB_NONE, - XCB_CURRENT_TIME - ), - &error - )); - - if (!error && grabPointerReply && (grabPointerReply->status == XCB_GRAB_STATUS_SUCCESS)) + if (result == GrabSuccess) { m_cursorGrabbed = true; break; @@ -1017,22 +927,7 @@ void WindowImplX11::setMouseCursorGrabbed(bool grabbed) } else { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_ungrab_pointer_checked( - m_connection, - XCB_CURRENT_TIME - ) - )); - - if (!error) - { - m_cursorGrabbed = false; - } - else - { - err() << "Failed to ungrab mouse cursor" << std::endl; - } + XUngrabPointer(m_display, CurrentTime); } } @@ -1064,26 +959,16 @@ void WindowImplX11::requestFocus() } } - ScopedXcbPtr error(NULL); - // Check if window is viewable (not on other desktop, ...) // TODO: Check also if minimized - ScopedXcbPtr attributes(xcb_get_window_attributes_reply( - m_connection, - xcb_get_window_attributes( - m_connection, - m_window - ), - &error - )); - - if (error || !attributes) + XWindowAttributes attributes; + if (XGetWindowAttributes(m_display, m_window, &attributes) == 0) { - err() << "Failed to check if window is viewable while requesting focus" << std::endl; + sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl; return; // error getting attribute } - bool windowViewable = (attributes->map_state == XCB_MAP_STATE_VIEWABLE); + bool windowViewable = (attributes.map_state == IsViewable); if (sfmlWindowFocused && windowViewable) { @@ -1093,31 +978,16 @@ void WindowImplX11::requestFocus() } else { - // Get current WM hints. - ScopedXcbPtr hintsReply(xcb_get_property_reply( - m_connection, - xcb_get_property(m_connection, 0, m_window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9), - &error - )); - - if (error || !hintsReply) - { - err() << "Failed to get WM hints while requesting focus" << std::endl; - return; - } - - WMHints* hints = reinterpret_cast(xcb_get_property_value(hintsReply.get())); - - if (!hints) - { - err() << "Failed to get WM hints while requesting focus" << std::endl; - return; - } - - // Even if no hints were returned, we can simply set the proper flags we need and go on. This is - // different from Xlib where XAllocWMHints() has to be called. - hints->flags |= (1 << 8); - setWMHints(*hints); + // 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); } } @@ -1125,91 +995,59 @@ void WindowImplX11::requestFocus() //////////////////////////////////////////////////////////// bool WindowImplX11::hasFocus() const { - ScopedXcbPtr error(NULL); + ::Window focusedWindow = 0; + int revertToReturn = 0; + XGetInputFocus(m_display, &focusedWindow, &revertToReturn); - ScopedXcbPtr reply(xcb_get_input_focus_reply( - m_connection, - xcb_get_input_focus_unchecked( - m_connection - ), - &error - )); - - if (error) - err() << "Failed to check if window has focus" << std::endl; - - return (reply->focus == m_window); + return (m_window == focusedWindow); } //////////////////////////////////////////////////////////// void WindowImplX11::grabFocus() { - xcb_atom_t netActiveWindow = XCB_ATOM_NONE; + Atom netActiveWindow = None; if (ewmhSupported()) netActiveWindow = getAtom("_NET_ACTIVE_WINDOW"); + // Only try to grab focus if the window is mapped + XWindowAttributes attr; + + XGetWindowAttributes(m_display, m_window, &attr); + + if (attr.map_state == IsUnmapped) + return; + if (netActiveWindow) { - xcb_client_message_event_t event; + XEvent event; std::memset(&event, 0, sizeof(event)); - event.response_type = XCB_CLIENT_MESSAGE; - event.window = m_window; - event.format = 32; - event.sequence = 0; - event.type = netActiveWindow; - event.data.data32[0] = 1; // Normal application - event.data.data32[1] = XCB_CURRENT_TIME; - event.data.data32[2] = 0; // We don't know the currently active window - - ScopedXcbPtr activeWindowError(xcb_request_check( - m_connection, - xcb_send_event_checked( - m_connection, - 0, - XCBDefaultRootWindow(m_connection), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - reinterpret_cast(&event) - ) - )); - - if (activeWindowError) + event.type = ClientMessage; + event.xclient.window = m_window; + event.xclient.format = 32; + event.xclient.message_type = netActiveWindow; + event.xclient.data.l[0] = 1; // Normal application + event.xclient.data.l[1] = m_lastInputTime; + event.xclient.data.l[2] = 0; // We don't know the currently active window + + int result = XSendEvent(m_display, + DefaultRootWindow(m_display), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + + XFlush(m_display); + + if (!result) err() << "Setting fullscreen failed, could not send \"_NET_ACTIVE_WINDOW\" event" << std::endl; } else { - ScopedXcbPtr setInputFocusError(xcb_request_check( - m_connection, - xcb_set_input_focus( - m_connection, - XCB_INPUT_FOCUS_POINTER_ROOT, - m_window, - XCB_CURRENT_TIME - ) - )); - - if (setInputFocusError) - { - err() << "Failed to change active window (set_input_focus)" << std::endl; - return; - } - - const uint32_t values[] = {XCB_STACK_MODE_ABOVE}; - - ScopedXcbPtr configureWindowError(xcb_request_check( - m_connection, - xcb_configure_window( - m_connection, - m_window, - XCB_CONFIG_WINDOW_STACK_MODE, - values - ) - )); - - if (configureWindowError) - err() << "Failed to change active window (configure_window)" << std::endl; + XRaiseWindow(m_display, m_window); + XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); + XFlush(m_display); } } @@ -1221,46 +1059,19 @@ void WindowImplX11::setVideoMode(const VideoMode& mode) if (mode == VideoMode::getDesktopMode()) return; - ScopedXcbPtr error(NULL); - - // Check if the RandR extension is present - const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(m_connection, &xcb_randr_id); - - if (!randrExt || !randrExt->present) + // Check if the XRandR extension is present + int version; + if (!XQueryExtension(m_display, "RANDR", &version, &version, &version)) { - // RandR extension is not supported: we cannot use fullscreen mode + // XRandR extension is not supported: we cannot use fullscreen mode err() << "Fullscreen is not supported, switching to window mode" << std::endl; return; } - // Load RandR and check its version - ScopedXcbPtr randrVersion(xcb_randr_query_version_reply( - m_connection, - xcb_randr_query_version( - m_connection, - 1, - 1 - ), - &error - )); - - if (error) - { - err() << "Failed to load RandR, switching to window mode" << std::endl; - return; - } - // Get the current configuration - ScopedXcbPtr config(xcb_randr_get_screen_info_reply( - m_connection, - xcb_randr_get_screen_info( - m_connection, - m_screen->root - ), - &error - )); - - if (error || !config) + XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); + + if (!config) { // Failed to get the screen configuration err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl; @@ -1268,52 +1079,34 @@ void WindowImplX11::setVideoMode(const VideoMode& mode) } // Save the current video mode before we switch to fullscreen - m_oldVideoMode = *config.get(); + Rotation currentRotation; + m_oldVideoMode = XRRConfigCurrentConfiguration(config, ¤tRotation); // Get the available screen sizes - xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); - - if (!sizes || !config->nSizes) - { - err() << "Failed to get the fullscreen sizes, switching to window mode" << std::endl; - return; - } + int nbSizes; + XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); // Search for a matching size - for (int i = 0; i < config->nSizes; ++i) + for (int i = 0; (sizes && i < nbSizes); ++i) { - if (config->rotation == XCB_RANDR_ROTATION_ROTATE_90 || - config->rotation == XCB_RANDR_ROTATION_ROTATE_270) + XRRConfigRotations(config, ¤tRotation); + + if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) std::swap(sizes[i].height, sizes[i].width); - if ((sizes[i].width == static_cast(mode.width)) && - (sizes[i].height == static_cast(mode.height))) + if ((sizes[i].width == static_cast(mode.width)) && (sizes[i].height == static_cast(mode.height))) { // Switch to fullscreen mode - ScopedXcbPtr setScreenConfig(xcb_randr_set_screen_config_reply( - m_connection, - xcb_randr_set_screen_config( - m_connection, - config->root, - XCB_CURRENT_TIME, - config->config_timestamp, - i, - config->rotation, - config->rate - ), - &error - )); - - if (error) - err() << "Failed to set new screen configuration" << std::endl; + XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime); // Set "this" as the current fullscreen window fullscreenWindow = this; - return; + break; } } - err() << "Failed to find matching fullscreen size, switching to window mode" << std::endl; + // Free the configuration instance + XRRFreeScreenConfigInfo(config); } @@ -1323,25 +1116,19 @@ void WindowImplX11::resetVideoMode() if (fullscreenWindow == this) { // Get current screen info - ScopedXcbPtr error(NULL); - - // Reset the video mode - ScopedXcbPtr setScreenConfig(xcb_randr_set_screen_config_reply( - m_connection, - xcb_randr_set_screen_config( - m_connection, - m_oldVideoMode.root, - XCB_CURRENT_TIME, - m_oldVideoMode.config_timestamp, - m_oldVideoMode.sizeID, - m_oldVideoMode.rotation, - m_oldVideoMode.rate - ), - &error - )); - - if (error) - err() << "Failed to reset old screen configuration" << std::endl; + XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); + if (config) + { + // Get the current rotation + Rotation currentRotation; + XRRConfigCurrentConfiguration(config, ¤tRotation); + + // Reset the video mode + XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime); + + // Free the configuration instance + XRRFreeScreenConfigInfo(config); + } // Reset the fullscreen window fullscreenWindow = NULL; @@ -1356,19 +1143,24 @@ void WindowImplX11::switchToFullscreen() if (ewmhSupported()) { - xcb_atom_t netWmBypassCompositor = getAtom("_NET_WM_BYPASS_COMPOSITOR"); + Atom netWmBypassCompositor = getAtom("_NET_WM_BYPASS_COMPOSITOR"); if (netWmBypassCompositor) { static const Uint32 bypassCompositor = 1; - // Not being able to bypass the compositor is not a fatal error - if (!changeWindowProperty(netWmBypassCompositor, XCB_ATOM_CARDINAL, 32, 1, &bypassCompositor)) - err() << "xcb_change_property failed, unable to set _NET_WM_BYPASS_COMPOSITOR" << std::endl; + XChangeProperty(m_display, + m_window, + netWmBypassCompositor, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&bypassCompositor), + 1); } - xcb_atom_t netWmState = getAtom("_NET_WM_STATE", true); - xcb_atom_t netWmStateFullscreen = getAtom("_NET_WM_STATE_FULLSCREEN", true); + Atom netWmState = getAtom("_NET_WM_STATE", true); + Atom netWmStateFullscreen = getAtom("_NET_WM_STATE_FULLSCREEN", true); if (!netWmState || !netWmStateFullscreen) { @@ -1376,32 +1168,26 @@ void WindowImplX11::switchToFullscreen() return; } - xcb_client_message_event_t event; + XEvent event; std::memset(&event, 0, sizeof(event)); - event.response_type = XCB_CLIENT_MESSAGE; - event.window = m_window; - event.format = 32; - event.sequence = 0; - event.type = netWmState; - event.data.data32[0] = 1; // _NET_WM_STATE_ADD - event.data.data32[1] = netWmStateFullscreen; - event.data.data32[2] = 0; // No second property - event.data.data32[3] = 1; // Normal window - - ScopedXcbPtr wmStateError(xcb_request_check( - m_connection, - xcb_send_event_checked( - m_connection, - 0, - XCBDefaultRootWindow(m_connection), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - reinterpret_cast(&event) - ) - )); - - if (wmStateError) - err() << "Setting fullscreen failed. Could not send \"_NET_WM_STATE\" event" << std::endl; + event.type = ClientMessage; + event.xclient.window = m_window; + event.xclient.format = 32; + event.xclient.message_type = netWmState; + event.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD + event.xclient.data.l[1] = netWmStateFullscreen; + event.xclient.data.l[2] = 0; // No second property + event.xclient.data.l[3] = 1; // Normal window + + int result = XSendEvent(m_display, + DefaultRootWindow(m_display), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + + if (!result) + err() << "Setting fullscreen failed, could not send \"_NET_WM_STATE\" event" << std::endl; } } @@ -1409,8 +1195,8 @@ void WindowImplX11::switchToFullscreen() //////////////////////////////////////////////////////////// void WindowImplX11::setProtocols() { - xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); - xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); + Atom wmProtocols = getAtom("WM_PROTOCOLS"); + Atom wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); if (!wmProtocols) { @@ -1418,7 +1204,7 @@ void WindowImplX11::setProtocols() return; } - std::vector atoms; + std::vector atoms; if (wmDeleteWindow) { @@ -1429,8 +1215,8 @@ void WindowImplX11::setProtocols() err() << "Failed to request WM_DELETE_WINDOW atom." << std::endl; } - xcb_atom_t netWmPing = XCB_ATOM_NONE; - xcb_atom_t netWmPid = XCB_ATOM_NONE; + Atom netWmPing = None; + Atom netWmPid = None; if (ewmhSupported()) { @@ -1438,20 +1224,32 @@ void WindowImplX11::setProtocols() netWmPid = getAtom("_NET_WM_PID", true); } - ScopedXcbPtr error(NULL); - if (netWmPing && netWmPid) { uint32_t pid = getpid(); - if (changeWindowProperty(netWmPid, XCB_ATOM_CARDINAL, 32, 1, &pid)) - atoms.push_back(netWmPing); + XChangeProperty(m_display, + m_window, + netWmPid, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&pid), + 1); + + atoms.push_back(netWmPing); } if (!atoms.empty()) { - if (!changeWindowProperty(wmProtocols, XCB_ATOM_ATOM, 32, atoms.size(), &atoms[0])) - err() << "Failed to set window protocols" << std::endl; + XChangeProperty(m_display, + m_window, + wmProtocols, + XA_ATOM, + 32, + PropModeReplace, + reinterpret_cast(&atoms[0]), + atoms.size()); } else { @@ -1460,122 +1258,6 @@ void WindowImplX11::setProtocols() } -//////////////////////////////////////////////////////////// -void WindowImplX11::setMotifHints(unsigned long style) -{ - ScopedXcbPtr error(NULL); - - static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS"; - ScopedXcbPtr hintsAtomReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - 0, - MOTIF_WM_HINTS.size(), - MOTIF_WM_HINTS.c_str() - ), - &error - )); - - if (!error && hintsAtomReply) - { - static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; - static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1; - - //static const unsigned long MWM_DECOR_ALL = 1 << 0; - static const unsigned long MWM_DECOR_BORDER = 1 << 1; - static const unsigned long MWM_DECOR_RESIZEH = 1 << 2; - static const unsigned long MWM_DECOR_TITLE = 1 << 3; - static const unsigned long MWM_DECOR_MENU = 1 << 4; - static const unsigned long MWM_DECOR_MINIMIZE = 1 << 5; - static const unsigned long MWM_DECOR_MAXIMIZE = 1 << 6; - - //static const unsigned long MWM_FUNC_ALL = 1 << 0; - static const unsigned long MWM_FUNC_RESIZE = 1 << 1; - static const unsigned long MWM_FUNC_MOVE = 1 << 2; - static const unsigned long MWM_FUNC_MINIMIZE = 1 << 3; - static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4; - static const unsigned long MWM_FUNC_CLOSE = 1 << 5; - - struct MotifWMHints - { - uint32_t flags; - uint32_t functions; - uint32_t decorations; - int32_t inputMode; - uint32_t state; - }; - - MotifWMHints hints; - hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; - hints.decorations = 0; - hints.functions = 0; - hints.inputMode = 0; - hints.state = 0; - - if (style & Style::Titlebar) - { - hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; - hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; - } - if (style & Style::Resize) - { - hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; - hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; - } - if (style & Style::Close) - { - hints.decorations |= 0; - hints.functions |= MWM_FUNC_CLOSE; - } - - if (!changeWindowProperty(hintsAtomReply->atom, hintsAtomReply->atom, 32, 5, &hints)) - err() << "xcb_change_property failed, could not set window hints" << std::endl; - } - else - { - err() << "Failed to request _MOTIF_WM_HINTS atom." << std::endl; - } -} - - -//////////////////////////////////////////////////////////// -void WindowImplX11::setWMHints(const WMHints& hints) -{ - if (!changeWindowProperty(XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, sizeof(hints) / 4, &hints)) - sf::err() << "Failed to set WM_HINTS property" << std::endl; -} - - -//////////////////////////////////////////////////////////// -void WindowImplX11::setWMSizeHints(const WMSizeHints& hints) -{ - if (!changeWindowProperty(XCB_ATOM_WM_NORMAL_HINTS, XCB_ATOM_WM_SIZE_HINTS, 32, sizeof(hints) / 4, &hints)) - sf::err() << "Failed to set XCB_ATOM_WM_NORMAL_HINTS property" << std::endl; -} - - -//////////////////////////////////////////////////////////// -bool WindowImplX11::changeWindowProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void* data) -{ - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_change_property_checked( - m_connection, - XCB_PROP_MODE_REPLACE, - m_window, - property, - type, - format, - length, - data - ) - )); - - return !error; -} - - //////////////////////////////////////////////////////////// void WindowImplX11::initialize() { @@ -1584,16 +1266,14 @@ void WindowImplX11::initialize() if (m_inputMethod) { - m_inputContext = XCreateIC( - m_inputMethod, - XNClientWindow, - m_window, - XNFocusWindow, - m_window, - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - reinterpret_cast(NULL) - ); + m_inputContext = XCreateIC(m_inputMethod, + XNClientWindow, + m_window, + XNFocusWindow, + m_window, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + reinterpret_cast(NULL)); } else { @@ -1603,6 +1283,21 @@ void WindowImplX11::initialize() if (!m_inputContext) err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl; + Atom wmWindowType = getAtom("_NET_WM_WINDOW_TYPE", false); + Atom wmWindowTypeNormal = getAtom("_NET_WM_WINDOW_TYPE_NORMAL", false); + + if (wmWindowType && wmWindowTypeNormal) + { + XChangeProperty(m_display, + m_window, + wmWindowType, + XA_ATOM, + 32, + PropModeReplace, + reinterpret_cast(&wmWindowTypeNormal), + 1); + } + // Show the window setVisible(true); @@ -1613,7 +1308,7 @@ void WindowImplX11::initialize() createHiddenCursor(); // Flush the commands queue - xcb_flush(m_connection); + XFlush(m_display); // Add this window to the global list of windows (required for focus request) Lock lock(allWindowsMutex); @@ -1622,60 +1317,46 @@ void WindowImplX11::initialize() //////////////////////////////////////////////////////////// -void WindowImplX11::createHiddenCursor() +void WindowImplX11::updateLastInputTime(::Time time) { - xcb_pixmap_t cursorPixmap = xcb_generate_id(m_connection); - - // Create the cursor's pixmap (1x1 pixels) - ScopedXcbPtr createPixmapError(xcb_request_check( - m_connection, - xcb_create_pixmap( - m_connection, - 1, - cursorPixmap, - m_window, - 1, - 1 - ) - )); - - if (createPixmapError) + if (time && (time != m_lastInputTime)) { - err() << "Failed to create pixmap for hidden cursor" << std::endl; - return; + Atom netWmUserTime = getAtom("_NET_WM_USER_TIME", true); + + if(netWmUserTime) + { + XChangeProperty(m_display, + m_window, + netWmUserTime, + XA_CARDINAL, + 32, + PropModeReplace, + reinterpret_cast(&time), + 1); + } + + m_lastInputTime = time; } +} - m_hiddenCursor = xcb_generate_id(m_connection); + +//////////////////////////////////////////////////////////// +void WindowImplX11::createHiddenCursor() +{ + // 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); // Create the cursor, using the pixmap as both the shape and the mask of the cursor - ScopedXcbPtr createCursorError(xcb_request_check( - m_connection, - xcb_create_cursor( - m_connection, - m_hiddenCursor, - cursorPixmap, - cursorPixmap, - 0, 0, 0, // Foreground RGB color - 0, 0, 0, // Background RGB color - 0, // X - 0 // Y - ) - )); - - if (createCursorError) - err() << "Failed to create hidden cursor" << std::endl; + XColor color; + color.flags = DoRed | DoGreen | DoBlue; + color.red = color.blue = color.green = 0; + m_hiddenCursor = XCreatePixmapCursor(m_display, cursorPixmap, cursorPixmap, &color, &color, 0, 0); // We don't need the pixmap any longer, free it - ScopedXcbPtr freePixmapError(xcb_request_check( - m_connection, - xcb_free_pixmap( - m_connection, - cursorPixmap - ) - )); - - if (freePixmapError) - err() << "Failed to free pixmap for hidden cursor" << std::endl; + XFreePixmap(m_display, cursorPixmap); } @@ -1752,25 +1433,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Try multiple times to grab the cursor for (unsigned int trial = 0; trial < maxTrialsCount; ++trial) { - sf::priv::ScopedXcbPtr error(NULL); - - sf::priv::ScopedXcbPtr grabPointerReply(xcb_grab_pointer_reply( - m_connection, - xcb_grab_pointer( - m_connection, - true, - m_window, - XCB_NONE, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, - m_window, - XCB_NONE, - XCB_CURRENT_TIME - ), - &error - )); + int result = XGrabPointer(m_display, m_window, True, None, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); - if (!error && grabPointerReply && (grabPointerReply->status == XCB_GRAB_STATUS_SUCCESS)) + if (result == GrabSuccess) { m_cursorGrabbed = true; break; @@ -1789,33 +1454,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) pushEvent(event); // If the window has been previously marked urgent (notification) as a result of a focus request, undo that - ScopedXcbPtr error(NULL); - - ScopedXcbPtr hintsReply(xcb_get_property_reply( - m_connection, - xcb_get_property(m_connection, 0, m_window, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9), - &error - )); - - if (error || !hintsReply) + XWMHints* hints = XGetWMHints(m_display, m_window); + if (hints != NULL) { - err() << "Failed to get WM hints in XCB_FOCUS_IN" << std::endl; - break; + // Remove urgency (notification) flag from hints + hints->flags &= ~XUrgencyHint; + XSetWMHints(m_display, m_window, hints); + XFree(hints); } - WMHints* hints = reinterpret_cast(xcb_get_property_value(hintsReply.get())); - - if (!hints) - { - err() << "Failed to get WM hints in XCB_FOCUS_IN" << std::endl; - break; - } - - // Remove urgency (notification) flag from hints - hints->flags &= ~(1 << 8); - - setWMHints(*hints); - break; } @@ -1828,18 +1475,7 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Release cursor if (m_cursorGrabbed) - { - ScopedXcbPtr error(xcb_request_check( - m_connection, - xcb_ungrab_pointer_checked( - m_connection, - XCB_CURRENT_TIME - ) - )); - - if (error) - err() << "Failed to ungrab mouse cursor" << std::endl; - } + XUngrabPointer(m_display, CurrentTime); Event event; event.type = Event::LostFocus; @@ -1868,13 +1504,13 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Close event case ClientMessage: { - static xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); + static Atom wmProtocols = getAtom("WM_PROTOCOLS"); // Handle window manager protocol messages we support if (windowEvent.xclient.message_type == wmProtocols) { - static xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); - static xcb_atom_t netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : XCB_ATOM_NONE; + static Atom wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); + static Atom netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : None; if ((windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast(wmDeleteWindow)) { @@ -1886,9 +1522,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) else if (netWmPing && (windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast(netWmPing)) { // Handle the _NET_WM_PING message, send pong back to WM to show that we are responsive - windowEvent.xclient.window = XCBDefaultRootWindow(m_connection); + windowEvent.xclient.window = DefaultRootWindow(m_display); - XSendEvent(m_display, windowEvent.xclient.window, False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent); + XSendEvent(m_display, DefaultRootWindow(m_display), False, SubstructureNotifyMask | SubstructureRedirectMask, &windowEvent); } } break; @@ -1966,6 +1602,8 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) } } + updateLastInputTime(windowEvent.xkey.time); + break; } @@ -2023,6 +1661,9 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) } pushEvent(event); } + + updateLastInputTime(windowEvent.xbutton.time); + break; } @@ -2144,6 +1785,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) break; } + + // Window property change + case PropertyNotify: + { + if (!m_lastInputTime) + m_lastInputTime = windowEvent.xproperty.time; + + break; + } } return true; diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index ea6f741..fd2295e 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -31,8 +31,7 @@ #include #include #include -#include -#include +#include #include @@ -188,33 +187,6 @@ protected: private: - struct WMHints - { - int32_t flags; - uint32_t input; - int32_t initial_state; - xcb_pixmap_t icon_pixmap; - xcb_window_t icon_window; - int32_t icon_x; - int32_t icon_y; - xcb_pixmap_t icon_mask; - xcb_window_t window_group; - }; - - struct WMSizeHints - { - uint32_t flags; - int32_t x, y; - int32_t width, height; - int32_t min_width, min_height; - int32_t max_width, max_height; - int32_t width_inc, height_inc; - int32_t min_aspect_num, min_aspect_den; - int32_t max_aspect_num, max_aspect_den; - int32_t base_width, base_height; - uint32_t win_gravity; - }; - //////////////////////////////////////////////////////////// /// \brief Request the WM to make the current window active /// @@ -248,40 +220,12 @@ private: void setProtocols(); //////////////////////////////////////////////////////////// - /// \brief Set Motif WM hints - /// - //////////////////////////////////////////////////////////// - void setMotifHints(unsigned long style); - - //////////////////////////////////////////////////////////// - /// \brief Set WM hints - /// - /// \param hints Hints - /// - //////////////////////////////////////////////////////////// - void setWMHints(const WMHints& hints); - - //////////////////////////////////////////////////////////// - /// \brief Set WM size hints - /// - /// \param hints Size hints - /// - //////////////////////////////////////////////////////////// - void setWMSizeHints(const WMSizeHints& hints); - - //////////////////////////////////////////////////////////// - /// \brief Change a XCB window property - /// - /// \param property Property to change - /// \param type Type of the property - /// \param format Format of the property - /// \param length Length of the new value - /// \param data The new value of the property + /// \brief Update the last time we received user input /// - /// \return True if successful, false if unsuccessful + /// \param time Last time we received user input /// //////////////////////////////////////////////////////////// - bool changeWindowProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void* data); + void updateLastInputTime(::Time time); //////////////////////////////////////////////////////////// /// \brief Do some common initializations after the window has been created @@ -314,21 +258,23 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - xcb_window_t m_window; ///< xcb identifier defining our window - ::Display* m_display; ///< Pointer to the display - xcb_connection_t* m_connection; ///< Pointer to the xcb connection - xcb_screen_t* m_screen; ///< Screen identifier - XIM m_inputMethod; ///< Input method linked to the X display - XIC m_inputContext; ///< Input context used to get unicode input in our window - bool m_isExternal; ///< Tell whether the window has been created externally or by SFML - xcb_randr_get_screen_info_reply_t m_oldVideoMode; ///< Video mode in use before we switch to fullscreen - Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one - bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? - Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) - bool m_useSizeHints; ///< Is the size of the window fixed with size hints? - bool m_fullscreen; ///< Is the window in fullscreen? - bool m_cursorGrabbed; ///< Is the mouse cursor trapped? - bool m_windowMapped; ///< Has the window been mapped by the window manager? + ::Window m_window; ///< X identifier defining our window + ::Display* m_display; ///< Pointer to the display + int m_screen; ///< Screen identifier + XIM m_inputMethod; ///< Input method linked to the X display + XIC m_inputContext; ///< Input context used to get unicode input in our window + bool m_isExternal; ///< Tell whether the window has been created externally or by SFML + int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen + Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one + bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? + Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) + bool m_useSizeHints; ///< Is the size of the window fixed with size hints? + bool m_fullscreen; ///< Is the window in fullscreen? + bool m_cursorGrabbed; ///< Is the mouse cursor trapped? + bool m_windowMapped; ///< Has the window been mapped by the window manager? + Pixmap m_iconPixmap; ///< The current icon pixmap if in use + Pixmap m_iconMaskPixmap; ///< The current icon mask pixmap if in use + ::Time m_lastInputTime; ///< Last time we received user input }; } // namespace priv diff --git a/src/SFML/Window/Win32/WglContext.cpp b/src/SFML/Window/Win32/WglContext.cpp index 486946f..a44c0c5 100644 --- a/src/SFML/Window/Win32/WglContext.cpp +++ b/src/SFML/Window/Win32/WglContext.cpp @@ -200,9 +200,9 @@ GlFunctionPointer WglContext::getFunction(const char* name) //////////////////////////////////////////////////////////// -bool WglContext::makeCurrent() +bool WglContext::makeCurrent(bool current) { - return m_deviceContext && m_context && wglMakeCurrent(m_deviceContext, m_context); + return m_deviceContext && m_context && wglMakeCurrent(current ? m_deviceContext : NULL, current ? m_context : NULL); } @@ -599,6 +599,18 @@ void WglContext::createContext(WglContext* shared) attributes.push_back(0); attributes.push_back(0); + if (sharedContext) + { + static Mutex mutex; + Lock lock(mutex); + + if (!wglMakeCurrent(NULL, NULL)) + { + err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + return; + } + } + // Create the context m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]); } @@ -657,6 +669,12 @@ void WglContext::createContext(WglContext* shared) static Mutex mutex; Lock lock(mutex); + if (!wglMakeCurrent(NULL, NULL)) + { + err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + return; + } + if (!wglShareLists(sharedContext, m_context)) err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl; } diff --git a/src/SFML/Window/Win32/WglContext.hpp b/src/SFML/Window/Win32/WglContext.hpp index ceecc2d..9017c93 100644 --- a/src/SFML/Window/Win32/WglContext.hpp +++ b/src/SFML/Window/Win32/WglContext.hpp @@ -93,10 +93,12 @@ public: //////////////////////////////////////////////////////////// /// \brief Activate the context as the current target for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); //////////////////////////////////////////////////////////// /// \brief Display what has been rendered to the context so far diff --git a/src/SFML/Window/iOS/EaglContext.hpp b/src/SFML/Window/iOS/EaglContext.hpp index a3c48ea..2bcdc36 100644 --- a/src/SFML/Window/iOS/EaglContext.hpp +++ b/src/SFML/Window/iOS/EaglContext.hpp @@ -126,10 +126,12 @@ protected: /// \brief Activate the context as the current target /// for rendering /// + /// \param current Whether to make the context current or no longer current + /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - virtual bool makeCurrent(); + virtual bool makeCurrent(bool current); private: diff --git a/src/SFML/Window/iOS/EaglContext.mm b/src/SFML/Window/iOS/EaglContext.mm index e033718..37ab4c3 100644 --- a/src/SFML/Window/iOS/EaglContext.mm +++ b/src/SFML/Window/iOS/EaglContext.mm @@ -107,6 +107,9 @@ EaglContext::~EaglContext() // Restore the previous context [EAGLContext setCurrentContext:previousContext]; + + if (m_context == [EAGLContext currentContext]) + [EAGLContext setCurrentContext:nil]; } } @@ -167,9 +170,12 @@ void EaglContext::recreateRenderBuffers(SFView* glView) //////////////////////////////////////////////////////////// -bool EaglContext::makeCurrent() +bool EaglContext::makeCurrent(bool current) { - return [EAGLContext setCurrentContext:m_context]; + if (current) + return [EAGLContext setCurrentContext:m_context]; + + return [EAGLContext setCurrentContext:nil]; } @@ -215,12 +221,18 @@ void EaglContext::createContext(EaglContext* shared, // Create the context if (shared) + { + [EAGLContext setCurrentContext:nil]; + m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]]; + } else + { m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; + } // Activate it - makeCurrent(); + makeCurrent(true); // Create the framebuffer (this is the only allowed drawable on iOS) glGenFramebuffersOES(1, &m_framebuffer); @@ -230,6 +242,9 @@ void EaglContext::createContext(EaglContext* shared, // Attach the context to the GL view for future updates window->getGlView().context = this; + + // Deactivate it + makeCurrent(false); } } // namespace priv diff --git a/src/SFML/Window/iOS/SFAppDelegate.mm b/src/SFML/Window/iOS/SFAppDelegate.mm index 3284b9a..09fa42e 100644 --- a/src/SFML/Window/iOS/SFAppDelegate.mm +++ b/src/SFML/Window/iOS/SFAppDelegate.mm @@ -214,8 +214,8 @@ namespace // Send a Resized event to the current window sf::Event event; event.type = sf::Event::Resized; - event.size.width = size.x * backingScaleFactor; - event.size.height = size.y * backingScaleFactor; + event.size.width = size.x; + event.size.height = size.y; sfWindow->forwardEvent(event); } } -- cgit v1.2.3