diff options
author | James Cowgill <jcowgill@debian.org> | 2016-08-09 15:20:03 +0000 |
---|---|---|
committer | James Cowgill <jcowgill@debian.org> | 2016-08-09 15:20:03 +0000 |
commit | df93e238e30e97850d76ad5585b8ab9ad9c03e67 (patch) | |
tree | 2ae5f3305e1ee1882f563d2803f94aa6446dc367 /src/SFML/Window | |
parent | 301fd78b3ac87cf1fbce9d2c955db89094a304a5 (diff) |
Imported Upstream version 2.4.0+dfsg
Diffstat (limited to 'src/SFML/Window')
128 files changed, 2908 insertions, 1405 deletions
diff --git a/src/SFML/Window/Android/InputImpl.cpp b/src/SFML/Window/Android/InputImpl.cpp index 8940b9e..9da3a13 100644 --- a/src/SFML/Window/Android/InputImpl.cpp +++ b/src/SFML/Window/Android/InputImpl.cpp @@ -125,7 +125,6 @@ void InputImpl::setVirtualKeyboardVisible(bool visible) MethodHideSoftInput, lBinder, lFlags); lJNIEnv->DeleteLocalRef(lBinder); } - lJNIEnv->DeleteLocalRef(lNativeActivity); lJNIEnv->DeleteLocalRef(ClassNativeActivity); lJNIEnv->DeleteLocalRef(ClassInputMethodManager); lJNIEnv->DeleteLocalRef(lDecorView); diff --git a/src/SFML/Window/Android/SensorImpl.cpp b/src/SFML/Window/Android/SensorImpl.cpp index 2b691a1..756833f 100644 --- a/src/SFML/Window/Android/SensorImpl.cpp +++ b/src/SFML/Window/Android/SensorImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Android/SensorImpl.hpp b/src/SFML/Window/Android/SensorImpl.hpp index 0b34997..0adb44d 100644 --- a/src/SFML/Window/Android/SensorImpl.hpp +++ b/src/SFML/Window/Android/SensorImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Android/WindowImplAndroid.cpp b/src/SFML/Window/Android/WindowImplAndroid.cpp index fb1906b..27d2f10 100644 --- a/src/SFML/Window/Android/WindowImplAndroid.cpp +++ b/src/SFML/Window/Android/WindowImplAndroid.cpp @@ -179,6 +179,13 @@ void WindowImplAndroid::setMouseCursorVisible(bool visible) //////////////////////////////////////////////////////////// +void WindowImplAndroid::setMouseCursorGrabbed(bool grabbed) +{ + // Not applicable +} + + +//////////////////////////////////////////////////////////// void WindowImplAndroid::setKeyRepeatEnabled(bool enabled) { // Not applicable @@ -433,7 +440,7 @@ int WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* s if (device == AINPUT_SOURCE_MOUSE) event.type = Event::MouseMoved; - else if (device == AINPUT_SOURCE_TOUCHSCREEN) + else if (device & AINPUT_SOURCE_TOUCHSCREEN) event.type = Event::TouchMoved; int pointerCount = AMotionEvent_getPointerCount(_event); @@ -452,7 +459,7 @@ int WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* s states->mousePosition = Vector2i(event.mouseMove.x, event.mouseMove.y); } - else if (device == AINPUT_SOURCE_TOUCHSCREEN) + else if (device & AINPUT_SOURCE_TOUCHSCREEN) { if (states->touchEvents[id].x == x && states->touchEvents[id].y == y) continue; @@ -496,7 +503,7 @@ int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, Act if (id >= 0 && id < Mouse::ButtonCount) states->isButtonPressed[id] = true; } - else if (device == AINPUT_SOURCE_TOUCHSCREEN) + else if (device & AINPUT_SOURCE_TOUCHSCREEN) { event.type = Event::TouchBegan; event.touch.finger = id; @@ -518,7 +525,7 @@ int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, Act if (id >= 0 && id < Mouse::ButtonCount) states->isButtonPressed[id] = false; } - else if (device == AINPUT_SOURCE_TOUCHSCREEN) + else if (device & AINPUT_SOURCE_TOUCHSCREEN) { event.type = Event::TouchEnded; event.touch.finger = id; diff --git a/src/SFML/Window/Android/WindowImplAndroid.hpp b/src/SFML/Window/Android/WindowImplAndroid.hpp index fb05b35..88250d4 100644 --- a/src/SFML/Window/Android/WindowImplAndroid.hpp +++ b/src/SFML/Window/Android/WindowImplAndroid.hpp @@ -147,6 +147,14 @@ public: virtual void setMouseCursorVisible(bool visible); //////////////////////////////////////////////////////////// + /// \brief Clips or releases the mouse cursor + /// + /// \param grabbed True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursorGrabbed(bool grabbed); + + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// /// \param enabled True to enable, false to disable diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index 386c077..231dee8 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -111,7 +111,7 @@ elseif(SFML_OS_MACOSX) ${SRCROOT}/OSX/cpp_objc_conversion.h ${SRCROOT}/OSX/cpp_objc_conversion.mm ${SRCROOT}/OSX/cg_sf_conversion.hpp - ${SRCROOT}/OSX/cg_sf_conversion.cpp + ${SRCROOT}/OSX/cg_sf_conversion.mm ${SRCROOT}/OSX/InputImpl.mm ${SRCROOT}/OSX/InputImpl.hpp ${SRCROOT}/OSX/HIDInputManager.hpp @@ -120,6 +120,9 @@ elseif(SFML_OS_MACOSX) ${SRCROOT}/OSX/HIDJoystickManager.cpp ${SRCROOT}/OSX/JoystickImpl.cpp ${SRCROOT}/OSX/JoystickImpl.hpp + ${SRCROOT}/OSX/NSImage+raw.h + ${SRCROOT}/OSX/NSImage+raw.mm + ${SRCROOT}/OSX/Scaling.h ${SRCROOT}/OSX/SensorImpl.cpp ${SRCROOT}/OSX/SensorImpl.hpp ${SRCROOT}/OSX/SFApplication.h @@ -132,6 +135,10 @@ elseif(SFML_OS_MACOSX) ${SRCROOT}/OSX/SFKeyboardModifiersHelper.mm ${SRCROOT}/OSX/SFOpenGLView.h ${SRCROOT}/OSX/SFOpenGLView.mm + ${SRCROOT}/OSX/SFOpenGLView+keyboard.mm + ${SRCROOT}/OSX/SFOpenGLView+keyboard_priv.h + ${SRCROOT}/OSX/SFOpenGLView+mouse.mm + ${SRCROOT}/OSX/SFOpenGLView+mouse_priv.h ${SRCROOT}/OSX/SFSilentResponder.h ${SRCROOT}/OSX/SFSilentResponder.m ${SRCROOT}/OSX/SFWindow.h diff --git a/src/SFML/Window/Context.cpp b/src/SFML/Window/Context.cpp index 0ec500a..2d51bbc 100644 --- a/src/SFML/Window/Context.cpp +++ b/src/SFML/Window/Context.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -27,7 +27,32 @@ //////////////////////////////////////////////////////////// #include <SFML/Window/Context.hpp> #include <SFML/Window/GlContext.hpp> +#include <SFML/System/ThreadLocalPtr.hpp> +#include <SFML/OpenGL.hpp> +#include <algorithm> +#include <vector> +#include <string> +#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 +{ + // This per-thread variable holds the current context for each thread + sf::ThreadLocalPtr<sf::Context> currentContext(NULL); +} namespace sf { @@ -42,6 +67,7 @@ Context::Context() //////////////////////////////////////////////////////////// Context::~Context() { + setActive(false); delete m_context; } @@ -49,7 +75,26 @@ Context::~Context() //////////////////////////////////////////////////////////// bool Context::setActive(bool active) { - return m_context->setActive(active); + bool result = m_context->setActive(active); + + if (result) + currentContext = (active ? this : NULL); + + return result; +} + + +//////////////////////////////////////////////////////////// +const ContextSettings& Context::getSettings() const +{ + return m_context->getSettings(); +} + + +//////////////////////////////////////////////////////////// +const Context* Context::getActiveContext() +{ + return currentContext; } @@ -61,6 +106,67 @@ GlFunctionPointer Context::getFunction(const char* name) //////////////////////////////////////////////////////////// +bool Context::isExtensionAvailable(const char* name) +{ + static std::vector<std::string> 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<const char*>(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<glGetStringiFuncType>(getFunction("glGetStringi")); + + if (glGetStringiFunc) + { + int numExtensions = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + + if (numExtensions) + { + for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i) + { + extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i)); + + extensions.push_back(extensionString); + } + } + } + } + + loaded = true; + } + + return std::find(extensions.begin(), extensions.end(), name) != extensions.end(); +} + + +//////////////////////////////////////////////////////////// Context::Context(const ContextSettings& settings, unsigned int width, unsigned int height) { m_context = priv::GlContext::create(settings, width, height); diff --git a/src/SFML/Window/EglContext.cpp b/src/SFML/Window/EglContext.cpp index ed7d294..f6686f1 100644 --- a/src/SFML/Window/EglContext.cpp +++ b/src/SFML/Window/EglContext.cpp @@ -85,6 +85,7 @@ m_config (NULL) // Get the best EGL config matching the default video settings m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings()); + updateSettings(); // Note: The EGL specs say that attrib_list can be NULL when passed to eglCreatePbufferSurface, // but this is resulting in a segfault. Bug in Android? @@ -123,6 +124,7 @@ m_config (NULL) // Get the best EGL config matching the requested video settings m_config = getBestConfig(m_display, bitsPerPixel, settings); + updateSettings(); // Create EGL context createContext(shared); @@ -250,10 +252,33 @@ EGLConfig EglContext::getBestConfig(EGLDisplay display, unsigned int bitsPerPixe // Ask EGL for the best config matching our video settings eglCheck(eglChooseConfig(display, attributes, configs, 1, &configCount)); + // TODO: This should check EGL_CONFORMANT and pick the first conformant configuration. + return configs[0]; } +//////////////////////////////////////////////////////////// +void EglContext::updateSettings() +{ + EGLint tmp; + + // Update the internal context settings with the current config + eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_DEPTH_SIZE, &tmp)); + m_settings.depthBits = tmp; + + eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_STENCIL_SIZE, &tmp)); + m_settings.stencilBits = tmp; + + eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_SAMPLES, &tmp)); + m_settings.antialiasingLevel = tmp; + + m_settings.majorVersion = 1; + m_settings.minorVersion = 1; + m_settings.attributeFlags = ContextSettings::Default; +} + + #ifdef SFML_SYSTEM_LINUX //////////////////////////////////////////////////////////// XVisualInfo EglContext::selectBestVisual(::Display* XDisplay, unsigned int bitsPerPixel, const ContextSettings& settings) diff --git a/src/SFML/Window/EglContext.hpp b/src/SFML/Window/EglContext.hpp index ef30cb4..6df6a53 100644 --- a/src/SFML/Window/EglContext.hpp +++ b/src/SFML/Window/EglContext.hpp @@ -166,6 +166,11 @@ public: private: //////////////////////////////////////////////////////////// + /// \brief Helper to copy the picked EGL configuration + //////////////////////////////////////////////////////////// + void updateSettings(); + + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// EGLDisplay m_display; ///< The internal EGL display diff --git a/src/SFML/Window/FreeBSD/JoystickImpl.cpp b/src/SFML/Window/FreeBSD/JoystickImpl.cpp index ff21293..4409893 100644 --- a/src/SFML/Window/FreeBSD/JoystickImpl.cpp +++ b/src/SFML/Window/FreeBSD/JoystickImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org) // 2013-2013 David Demelier (demelier.david@gmail.com) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/FreeBSD/JoystickImpl.hpp b/src/SFML/Window/FreeBSD/JoystickImpl.hpp index b52307c..f861815 100644 --- a/src/SFML/Window/FreeBSD/JoystickImpl.hpp +++ b/src/SFML/Window/FreeBSD/JoystickImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index 1a66774..b74725e 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -100,6 +100,10 @@ #define GL_CONTEXT_FLAGS 0x821E #endif +#if !defined(GL_FRAMEBUFFER_SRGB) + #define GL_FRAMEBUFFER_SRGB 0x8DB9 +#endif + #if !defined(GL_CONTEXT_FLAG_DEBUG_BIT) #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #endif @@ -131,8 +135,8 @@ namespace ContextType* sharedContext = NULL; // Internal contexts - sf::ThreadLocalPtr<sf::priv::GlContext> internalContext(NULL); - std::set<sf::priv::GlContext*> internalContexts; + sf::ThreadLocalPtr<sf::Context> internalContext(NULL); + std::set<sf::Context*> internalContexts; sf::Mutex internalContextsMutex; // Check if the internal context of the current thread is valid @@ -148,11 +152,11 @@ namespace } // Retrieve the internal context for the current thread - sf::priv::GlContext* getInternalContext() + sf::Context* getInternalContext() { if (!hasInternalContext()) { - internalContext = sf::priv::GlContext::create(); + internalContext = new sf::Context; sf::Lock lock(internalContextsMutex); internalContexts.insert(internalContext); } @@ -171,9 +175,12 @@ void GlContext::globalInit() { Lock lock(mutex); + if (sharedContext) + return; + // Create the shared context sharedContext = new ContextType(NULL); - sharedContext->initialize(); + sharedContext->initialize(ContextSettings()); // This call makes sure that: // - the shared context is inactive (it must never be) @@ -187,13 +194,16 @@ void GlContext::globalCleanup() { Lock lock(mutex); + if (!sharedContext) + return; + // Destroy the shared context delete sharedContext; sharedContext = NULL; // Destroy the internal contexts Lock internalContextsLock(internalContextsMutex); - for (std::set<GlContext*>::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it) + for (std::set<Context*>::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it) delete *it; internalContexts.clear(); } @@ -215,7 +225,7 @@ GlContext* GlContext::create() // Create the context GlContext* context = new ContextType(sharedContext); - context->initialize(); + context->initialize(ContextSettings()); return context; } @@ -231,7 +241,7 @@ GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* // Create the context GlContext* context = new ContextType(sharedContext, settings, owner, bitsPerPixel); - context->initialize(); + context->initialize(settings); context->checkSettings(settings); return context; @@ -248,7 +258,7 @@ GlContext* GlContext::create(const ContextSettings& settings, unsigned int width // Create the context GlContext* context = new ContextType(sharedContext, settings, width, height); - context->initialize(); + context->initialize(settings); context->checkSettings(settings); return context; @@ -340,7 +350,7 @@ GlContext::GlContext() //////////////////////////////////////////////////////////// -int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated) +int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated, bool sRgb) { int colorDiff = static_cast<int>(bitsPerPixel) - colorBits; int depthDiff = static_cast<int>(settings.depthBits) - depthBits; @@ -356,6 +366,10 @@ int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& // Aggregate the scores int score = std::abs(colorDiff) + std::abs(depthDiff) + std::abs(stencilDiff) + std::abs(antialiasingDiff); + // If the user wants an sRGB capable format, try really hard to get one + if (settings.sRgbCapable && !sRgb) + score += 10000000; + // Make sure we prefer hardware acceleration over features if (!accelerated) score += 100000000; @@ -365,7 +379,7 @@ int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& //////////////////////////////////////////////////////////// -void GlContext::initialize() +void GlContext::initialize(const ContextSettings& requestedSettings) { // Activate the context setActive(true); @@ -462,9 +476,32 @@ void GlContext::initialize() } } - // Enable antialiasing if needed - if (m_settings.antialiasingLevel > 0) + // Enable anti-aliasing if requested by the user and supported + if ((requestedSettings.antialiasingLevel > 0) && (m_settings.antialiasingLevel > 0)) + { glEnable(GL_MULTISAMPLE); + } + else + { + m_settings.antialiasingLevel = 0; + } + + // Enable sRGB if requested by the user and supported + if (requestedSettings.sRgbCapable && m_settings.sRgbCapable) + { + glEnable(GL_FRAMEBUFFER_SRGB); + + // Check to see if the enable was successful + if (glIsEnabled(GL_FRAMEBUFFER_SRGB) == GL_FALSE) + { + err() << "Warning: Failed to enable GL_FRAMEBUFFER_SRGB" << std::endl; + m_settings.sRgbCapable = false; + } + } + else + { + m_settings.sRgbCapable = false; + } } @@ -490,10 +527,11 @@ void GlContext::checkSettings(const ContextSettings& requestedSettings) int requestedVersion = requestedSettings.majorVersion * 10 + requestedSettings.minorVersion; if ((m_settings.attributeFlags != requestedSettings.attributeFlags) || - (version < requestedVersion) || + (version < requestedVersion) || (m_settings.stencilBits < requestedSettings.stencilBits) || (m_settings.antialiasingLevel < requestedSettings.antialiasingLevel) || - (m_settings.depthBits < requestedSettings.depthBits)) + (m_settings.depthBits < requestedSettings.depthBits) || + (!m_settings.sRgbCapable && requestedSettings.sRgbCapable)) { err() << "Warning: The created OpenGL context does not fully meet the settings that were requested" << std::endl; err() << "Requested: version = " << requestedSettings.majorVersion << "." << requestedSettings.minorVersion @@ -503,6 +541,7 @@ void GlContext::checkSettings(const ContextSettings& requestedSettings) << std::boolalpha << " ; core = " << ((requestedSettings.attributeFlags & ContextSettings::Core) != 0) << " ; debug = " << ((requestedSettings.attributeFlags & ContextSettings::Debug) != 0) + << " ; sRGB = " << requestedSettings.sRgbCapable << std::noboolalpha << std::endl; err() << "Created: version = " << m_settings.majorVersion << "." << m_settings.minorVersion << " ; depth bits = " << m_settings.depthBits @@ -511,6 +550,7 @@ void GlContext::checkSettings(const ContextSettings& requestedSettings) << std::boolalpha << " ; core = " << ((m_settings.attributeFlags & ContextSettings::Core) != 0) << " ; debug = " << ((m_settings.attributeFlags & ContextSettings::Debug) != 0) + << " ; sRGB = " << m_settings.sRgbCapable << std::noboolalpha << std::endl; } } diff --git a/src/SFML/Window/GlContext.hpp b/src/SFML/Window/GlContext.hpp index f9225cd..8c4ce01 100644 --- a/src/SFML/Window/GlContext.hpp +++ b/src/SFML/Window/GlContext.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -217,11 +217,12 @@ protected: /// \param stencilBits Stencil bits of the configuration to evaluate /// \param antialiasing Antialiasing level of the configuration to evaluate /// \param accelerated Whether the pixel format is hardware accelerated + /// \param sRgb Whether the pixel format is sRGB capable /// /// \return Score of the configuration /// //////////////////////////////////////////////////////////// - static int evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated); + static int evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated, bool sRgb); //////////////////////////////////////////////////////////// // Member data @@ -232,9 +233,10 @@ private: //////////////////////////////////////////////////////////// /// \brief Perform various initializations after the context construction + /// \param requestedSettings Requested settings during context creation /// //////////////////////////////////////////////////////////// - void initialize(); + void initialize(const ContextSettings& requestedSettings); //////////////////////////////////////////////////////////// /// \brief Check whether the context is compatible with the requested settings diff --git a/src/SFML/Window/GlResource.cpp b/src/SFML/Window/GlResource.cpp index 921874d..dfcbe7a 100644 --- a/src/SFML/Window/GlResource.cpp +++ b/src/SFML/Window/GlResource.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/InputImpl.hpp b/src/SFML/Window/InputImpl.hpp index df52a78..a0244e2 100644 --- a/src/SFML/Window/InputImpl.hpp +++ b/src/SFML/Window/InputImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Joystick.cpp b/src/SFML/Window/Joystick.cpp index 11cf289..c713696 100644 --- a/src/SFML/Window/Joystick.cpp +++ b/src/SFML/Window/Joystick.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/JoystickImpl.hpp b/src/SFML/Window/JoystickImpl.hpp index 6648b59..e7b6724 100644 --- a/src/SFML/Window/JoystickImpl.hpp +++ b/src/SFML/Window/JoystickImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/JoystickManager.cpp b/src/SFML/Window/JoystickManager.cpp index 99c100d..9038afa 100644 --- a/src/SFML/Window/JoystickManager.cpp +++ b/src/SFML/Window/JoystickManager.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/JoystickManager.hpp b/src/SFML/Window/JoystickManager.hpp index 229160b..7f7a22a 100644 --- a/src/SFML/Window/JoystickManager.hpp +++ b/src/SFML/Window/JoystickManager.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Keyboard.cpp b/src/SFML/Window/Keyboard.cpp index 6076122..b9ad152 100644 --- a/src/SFML/Window/Keyboard.cpp +++ b/src/SFML/Window/Keyboard.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Mouse.cpp b/src/SFML/Window/Mouse.cpp index 0f966bc..6b43c9f 100644 --- a/src/SFML/Window/Mouse.cpp +++ b/src/SFML/Window/Mouse.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.h b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h index 6921533..75c414f 100644 --- a/src/SFML/Window/OSX/AutoreleasePoolWrapper.h +++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -24,26 +24,14 @@ //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// -/// \brief Ensure at least one autorelease pool is available on this thread -/// -/// Increment a retain count for *this* thread. +/// \brief Ensure one autorelease pool is available on this thread /// //////////////////////////////////////////////////////////// -void retainPool(void); +void ensureThreadHasPool(void); -//////////////////////////////////////////////////////////// -/// \brief Drain the pool -/// -/// The pool retain count should be absolutely positive before calling this function on this thread. -/// -//////////////////////////////////////////////////////////// -void drainCurrentPool(void); //////////////////////////////////////////////////////////// -/// \brief Release the pool. -/// -/// Decrease the retain count for *this* thread. +/// \brief Drain the thread's pool but keep it alive /// //////////////////////////////////////////////////////////// -void releasePool(void); - +void drainThreadPool(void); diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm index 2afd8ab..f0ae7b4 100644 --- a/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm +++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -26,11 +26,8 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include <SFML/System/Err.hpp> -#include <SFML/System/NonCopyable.hpp> -#include <SFML/System/ThreadLocalPtr.hpp> - #include <cassert> +#include <pthread.h> #import <SFML/Window/OSX/AutoreleasePoolWrapper.h> #import <Foundation/Foundation.h> @@ -41,165 +38,68 @@ /// pool and making other pools invalid which can lead to a crash on 10.5 and an /// annoying message on 10.6 (*** attempt to pop an unknown autorelease pool). /// -/// Because NSAutoreleasePool cannot be retain we have to do it ourself. -/// We use an sf::ThreadLocalPtr to have one PoolWrapper in each thread. -/// -/// SPECIAL CONSIDERATION: -/// ====================== -/// This implies that if retainPool is called X times in a thread Y then -/// releasePool must be called X times too in the same thread Y. -/// //////////////////////////////////////////////////////////// -namespace sf -{ -namespace priv -{ -//////////////////////////////////////////////////////////// -/// \brief C++ Wrapper of Obj-C Autorelease Pool -/// -//////////////////////////////////////////////////////////// -class PoolWrapper : NonCopyable -{ -public: - - //////////////////////////////////////////////////////////// - /// \brief Default constructor - /// - //////////////////////////////////////////////////////////// - PoolWrapper(); - - //////////////////////////////////////////////////////////// - /// \brief Default destructor - /// - /// Make sure the pool is drained (if appropriate) - /// - //////////////////////////////////////////////////////////// - ~PoolWrapper(); - - //////////////////////////////////////////////////////////// - /// \brief Increment retain count and allocate memory if needed - /// - //////////////////////////////////////////////////////////// - void retain(); - - //////////////////////////////////////////////////////////// - /// \brief Decrement retain count and releasing memory if needed - /// - /// \return true if the pool wrapper can be released - /// - //////////////////////////////////////////////////////////// - bool release(); - - //////////////////////////////////////////////////////////// - /// \brief Drain the pool - /// - //////////////////////////////////////////////////////////// - void drain(); - -private: - - //////////////////////////////////////////////////////////// - // Member data - //////////////////////////////////////////////////////////// - int m_count; ///< How many times was the pool retained? - NSAutoreleasePool* m_pool; ///< Our dedicated pool -}; - - -//////////////////////////////////////////////////////////// -PoolWrapper::PoolWrapper() : -m_count(0), -m_pool(nil) -{ - /* Nothing else */ -} - //////////////////////////////////////////////////////////// -PoolWrapper::~PoolWrapper() -{ - // Make sure everything is drained - m_count = 0; - drain(); -} - - +// Private data //////////////////////////////////////////////////////////// -void PoolWrapper::retain() -{ - // Increase counter - ++m_count; - - // Allocate pool if required - if (m_pool == nil) - m_pool = [[NSAutoreleasePool alloc] init]; -} +static pthread_key_t poolKey; +static pthread_once_t initOnceToken = PTHREAD_ONCE_INIT; //////////////////////////////////////////////////////////// -bool PoolWrapper::release() -{ - // Decrease counter - --m_count; - - return m_count == 0; -} - -void PoolWrapper::drain() +/// \brief (local function) Drain one more time the pool +/// but this time don't create a new one. +/// +//////////////////////////////////////////////////////////// +static void destroyPool(void* data) { - [m_pool drain]; - m_pool = nil; - - if (m_count != 0) - m_pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = (NSAutoreleasePool*)data; + [pool drain]; } -} // namespace priv - -} // namespace sf - //////////////////////////////////////////////////////////// -// Private data +/// \brief (local function) Init the pthread key for the pool +/// //////////////////////////////////////////////////////////// -namespace +static void createPoolKey(void) { - // This per-thread variable holds the current autorelease pool for each thread - sf::ThreadLocalPtr<sf::priv::PoolWrapper> localPool; + pthread_key_create(&poolKey, destroyPool); } //////////////////////////////////////////////////////////// -void retainPool(void) +/// \brief (local function) Store a new pool for this thread +/// +//////////////////////////////////////////////////////////// +static void createNewPool(void) { - // First, Check that we have a valid PoolWrapper object in our local pool. - if (localPool == NULL) - localPool = new sf::priv::PoolWrapper(); - - // Then retains! - localPool->retain(); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + pthread_setspecific(poolKey, pool); } //////////////////////////////////////////////////////////// -void drainCurrentPool(void) +void ensureThreadHasPool(void) { - assert(localPool != NULL); - localPool->drain(); + pthread_once(&initOnceToken, createPoolKey); + if (pthread_getspecific(poolKey) == NULL) + { + createNewPool(); + } } //////////////////////////////////////////////////////////// -void releasePool(void) +void drainThreadPool(void) { - assert(localPool != NULL); + void* data = pthread_getspecific(poolKey); + assert(data != NULL); - // If we're done with the pool, let's release the memory - if (localPool->release()) - { - delete localPool; - localPool = NULL; - } + // Drain the pool but keep it alive by creating a new one + destroyPool(data); + createNewPool(); } diff --git a/src/SFML/Window/OSX/HIDInputManager.hpp b/src/SFML/Window/OSX/HIDInputManager.hpp index 01c5ccd..19e2568 100644 --- a/src/SFML/Window/OSX/HIDInputManager.hpp +++ b/src/SFML/Window/OSX/HIDInputManager.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/HIDInputManager.mm b/src/SFML/Window/OSX/HIDInputManager.mm index 37ef79e..c53bd53 100644 --- a/src/SFML/Window/OSX/HIDInputManager.mm +++ b/src/SFML/Window/OSX/HIDInputManager.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -763,7 +763,7 @@ Keyboard::Key HIDInputManager::nonLocalizedKeys(UniChar virtualKeycode) case 0x2c: return sf::Keyboard::Slash; case 0x2a: return sf::Keyboard::BackSlash; -#warning sf::Keyboard::Tilde might be in conflict with some other key. + // sf::Keyboard::Tilde might be in conflict with some other key. // 0x0a is for "Non-US Backslash" according to HID Calibrator, // a sample provided by Apple. case 0x0a: return sf::Keyboard::Tilde; @@ -855,7 +855,7 @@ Keyboard::Key HIDInputManager::nonLocalizedKeys(UniChar virtualKeycode) case NSPauseFunctionKey: return sf::Keyboard::Pause; -#warning keycode 0x1b is not bound to any key. + // keycode 0x1b is not bound to any key. // This key is ' on CH-FR, ) on FR and - on US layouts. // An unknown key. diff --git a/src/SFML/Window/OSX/HIDJoystickManager.cpp b/src/SFML/Window/OSX/HIDJoystickManager.cpp index 1724fe6..20b1e37 100644 --- a/src/SFML/Window/OSX/HIDJoystickManager.cpp +++ b/src/SFML/Window/OSX/HIDJoystickManager.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -133,7 +133,7 @@ void HIDJoystickManager::update() //////////////////////////////////////////////////////////// void HIDJoystickManager::pluggedIn(void* context, IOReturn, void*, IOHIDDeviceRef) { - HIDJoystickManager* manager = (HIDJoystickManager*)context; + HIDJoystickManager* manager = static_cast<HIDJoystickManager*>(context); manager->m_joystickCount++; } @@ -141,7 +141,7 @@ void HIDJoystickManager::pluggedIn(void* context, IOReturn, void*, IOHIDDeviceRe //////////////////////////////////////////////////////////// void HIDJoystickManager::pluggedOut(void* context, IOReturn, void*, IOHIDDeviceRef) { - HIDJoystickManager* manager = (HIDJoystickManager*)context; + HIDJoystickManager* manager = static_cast<HIDJoystickManager*>(context); manager->m_joystickCount--; } diff --git a/src/SFML/Window/OSX/HIDJoystickManager.hpp b/src/SFML/Window/OSX/HIDJoystickManager.hpp index a128df5..614e58b 100644 --- a/src/SFML/Window/OSX/HIDJoystickManager.hpp +++ b/src/SFML/Window/OSX/HIDJoystickManager.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/InputImpl.hpp b/src/SFML/Window/OSX/InputImpl.hpp index ef897b1..2263551 100644 --- a/src/SFML/Window/OSX/InputImpl.hpp +++ b/src/SFML/Window/OSX/InputImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/InputImpl.mm b/src/SFML/Window/OSX/InputImpl.mm index f0e8ee4..0bdade5 100644 --- a/src/SFML/Window/OSX/InputImpl.mm +++ b/src/SFML/Window/OSX/InputImpl.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -185,7 +185,7 @@ void InputImpl::setMousePosition(const Vector2i& position) CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, pos, - /*we don't care about this: */0); + /* we don't care about this: */ kCGMouseButtonLeft); CGEventPost(kCGHIDEventTap, event); CFRelease(event); // This is a workaround to deprecated CGSetLocalEventsSuppressionInterval. diff --git a/src/SFML/Window/OSX/JoystickImpl.cpp b/src/SFML/Window/OSX/JoystickImpl.cpp index 09d7614..19acb86 100644 --- a/src/SFML/Window/OSX/JoystickImpl.cpp +++ b/src/SFML/Window/OSX/JoystickImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/JoystickImpl.hpp b/src/SFML/Window/OSX/JoystickImpl.hpp index 5b08ba6..a71b82d 100644 --- a/src/SFML/Window/OSX/JoystickImpl.hpp +++ b/src/SFML/Window/OSX/JoystickImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/NSImage+raw.h b/src/SFML/Window/OSX/NSImage+raw.h new file mode 100644 index 0000000..745f49c --- /dev/null +++ b/src/SFML/Window/OSX/NSImage+raw.h @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Config.hpp> + +#import <AppKit/AppKit.h> + +//////////////////////////////////////////////////////////// +/// Extends NSImage with a convenience method to load images +/// from raw data. +/// +//////////////////////////////////////////////////////////// + +@interface NSImage (raw) + +//////////////////////////////////////////////////////////// +/// \brief Load an image from raw RGBA pixels +/// +/// \param pixels array of 4 * `size` bytes representing the image +/// \param size size of the image +/// +/// \return an instance of NSImage that needs to be released by the caller +/// +//////////////////////////////////////////////////////////// ++(NSImage*)imageWithRawData:(const sf::Uint8*)pixels andSize:(NSSize)size; + +@end diff --git a/src/SFML/Window/OSX/NSImage+raw.mm b/src/SFML/Window/OSX/NSImage+raw.mm new file mode 100644 index 0000000..571a286 --- /dev/null +++ b/src/SFML/Window/OSX/NSImage+raw.mm @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#import <SFML/Window/OSX/NSImage+raw.h> + +@implementation NSImage (raw) + ++(NSImage*)imageWithRawData:(const sf::Uint8*)pixels andSize:(NSSize)size +{ + // Create an empty image representation. + NSBitmapImageRep* bitmap = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:0 // if 0: only allocate memory + pixelsWide:size.width + pixelsHigh:size.height + bitsPerSample:8 // The number of bits used to specify + // one pixel in a single component of the data. + samplesPerPixel:4 // 3 if no alpha, 4 with it + hasAlpha:YES + isPlanar:NO // I don't know what it is but it works + colorSpaceName:NSCalibratedRGBColorSpace + bytesPerRow:0 // 0 == determine automatically + bitsPerPixel:0]; // 0 == determine automatically + + // Load data pixels. + for (unsigned int y = 0; y < size.height; ++y) + { + for (unsigned int x = 0; x < size.width; ++x, pixels += 4) + { + NSUInteger pixel[4] = { pixels[0], pixels[1], pixels[2], pixels[3] }; + [bitmap setPixel:pixel atX:x y:y]; + } + } + + // Create an image from the representation. + NSImage* image = [[NSImage alloc] initWithSize:size]; + [image addRepresentation:bitmap]; + + [bitmap release]; + + return image; +} + +@end diff --git a/src/SFML/Window/OSX/SFApplication.h b/src/SFML/Window/OSX/SFApplication.h index b388d80..454bf8c 100644 --- a/src/SFML/Window/OSX/SFApplication.h +++ b/src/SFML/Window/OSX/SFApplication.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFApplication.m b/src/SFML/Window/OSX/SFApplication.m index 6ba1f90..934e89f 100644 --- a/src/SFML/Window/OSX/SFApplication.m +++ b/src/SFML/Window/OSX/SFApplication.m @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFApplicationDelegate.h b/src/SFML/Window/OSX/SFApplicationDelegate.h index 4a99550..53033c9 100644 --- a/src/SFML/Window/OSX/SFApplicationDelegate.h +++ b/src/SFML/Window/OSX/SFApplicationDelegate.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFApplicationDelegate.m b/src/SFML/Window/OSX/SFApplicationDelegate.m index c15037c..9566c46 100644 --- a/src/SFML/Window/OSX/SFApplicationDelegate.m +++ b/src/SFML/Window/OSX/SFApplicationDelegate.m @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFContext.hpp b/src/SFML/Window/OSX/SFContext.hpp index 761c12e..3e2a979 100644 --- a/src/SFML/Window/OSX/SFContext.hpp +++ b/src/SFML/Window/OSX/SFContext.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFContext.mm b/src/SFML/Window/OSX/SFContext.mm index 810bcb4..0970007 100644 --- a/src/SFML/Window/OSX/SFContext.mm +++ b/src/SFML/Window/OSX/SFContext.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -46,7 +46,7 @@ m_view(0), m_window(0) { // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Create the context createContext(shared, @@ -62,7 +62,7 @@ m_view(0), m_window(0) { // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Create the context. createContext(shared, bitsPerPixel, settings); @@ -83,7 +83,7 @@ m_window(0) WindowImplCocoa::setUpProcess(); // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Create the context. createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings); @@ -108,8 +108,6 @@ SFContext::~SFContext() [m_view release]; // Might be nil but we don't care. [m_window release]; // Idem. - - releasePool(); } @@ -244,6 +242,9 @@ void SFContext::createContext(SFContext* shared, attrs.push_back((NSOpenGLPixelFormatAttribute)0); // end of array + // All OS X pixel formats are sRGB capable + m_settings.sRgbCapable = true; + // Create the pixel format. NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attrs[0]]; diff --git a/src/SFML/Window/OSX/SFKeyboardModifiersHelper.h b/src/SFML/Window/OSX/SFKeyboardModifiersHelper.h index 60bdb3f..39b18ec 100644 --- a/src/SFML/Window/OSX/SFKeyboardModifiersHelper.h +++ b/src/SFML/Window/OSX/SFKeyboardModifiersHelper.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm b/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm index 89c23b5..08594da 100644 --- a/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm +++ b/src/SFML/Window/OSX/SFKeyboardModifiersHelper.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFOpenGLView+keyboard.mm b/src/SFML/Window/OSX/SFOpenGLView+keyboard.mm new file mode 100644 index 0000000..4fbef01 --- /dev/null +++ b/src/SFML/Window/OSX/SFOpenGLView+keyboard.mm @@ -0,0 +1,220 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Window/OSX/WindowImplCocoa.hpp> +#include <SFML/Window/OSX/HIDInputManager.hpp> // For localizedKeys and nonLocalizedKeys + +#import <SFML/Window/OSX/SFKeyboardModifiersHelper.h> +#import <SFML/Window/OSX/SFOpenGLView.h> +#import <SFML/Window/OSX/SFOpenGLView+keyboard_priv.h> + +//////////////////////////////////////////////////////////// +/// In this file, we implement keyboard handling for SFOpenGLView +/// +//////////////////////////////////////////////////////////// + + +@implementation SFOpenGLView (keyboard) + + +//////////////////////////////////////////////////////// +-(BOOL)acceptsFirstResponder +{ + // Accepts key event. + return YES; +} + + +//////////////////////////////////////////////////////// +-(BOOL)canBecomeKeyView +{ + // Accepts key event. + return YES; +} + + +//////////////////////////////////////////////////////// +-(void)enableKeyRepeat +{ + m_useKeyRepeat = YES; +} + + +//////////////////////////////////////////////////////// +-(void)disableKeyRepeat +{ + m_useKeyRepeat = NO; +} + + +//////////////////////////////////////////////////////// +-(void)keyDown:(NSEvent*)theEvent +{ + // Transmit to non-SFML responder + [[self nextResponder] keyDown:theEvent]; + + if (m_requester == 0) + return; + + // Handle key down event + if (m_useKeyRepeat || ![theEvent isARepeat]) + { + sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent]; + + if (key.code != sf::Keyboard::Unknown) // The key is recognized. + m_requester->keyDown(key); + } + + + // Handle text entered event: + // Ignore event if we don't want repeated keystrokes + if (m_useKeyRepeat || ![theEvent isARepeat]) + { + // Ignore escape key and other non text keycode (See NSEvent.h) + // because they produce a sound alert. + if ([SFOpenGLView isValidTextUnicode:theEvent]) + { + // Send the event to the hidden text view for processing + [m_hiddenTextView interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; + } + + // Carefully handle backspace and delete.. + // Note: the event is intentionally sent to the hidden view + // even if we do something more specific below. This way + // key combination are correctly interpreted. + + unsigned short keycode = [theEvent keyCode]; + + // Backspace + if (keycode == 0x33) + { + // Send the correct Unicode value (i.e. 8) instead of 127 (which is 'delete') + m_requester->textEntered(8); + } + + // Delete + else if ((keycode == 0x75) || (keycode == NSDeleteFunctionKey)) + { + // Instead of the value 63272 we send 127. + m_requester->textEntered(127); + } + + // Otherwise, let's see what our hidden field has computed + else + { + NSString* string = [m_hiddenTextView string]; + + // Send each character to SFML event requester + for (NSUInteger index = 0; index < [string length]; ++index) + m_requester->textEntered([string characterAtIndex:index]); + + // Empty our hidden cache + [m_hiddenTextView setString:@""]; + } + } +} + + +//////////////////////////////////////////////////////// +-(void)sfKeyUp:(NSEvent*)theEvent +{ + // For some mystic reasons, key released events don't work the same way + // as key pressed events... We somewhat hijack the event chain of response + // in -[SFApplication sendEvent:] and resume this chain with the next + // responder. + // This is workaround to make sure key released events are fired in + // fullscreen window too. + + // Transmit to non-SFML responder + [[self nextResponder] keyUp:theEvent]; + + if (m_requester == 0) + return; + + sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent]; + + if (key.code != sf::Keyboard::Unknown) // The key is recognized. + m_requester->keyUp(key); +} + + +//////////////////////////////////////////////////////// +-(void)flagsChanged:(NSEvent*)theEvent +{ + // Transmit to non-SFML responder + [[self nextResponder] flagsChanged:theEvent]; + + if (m_requester == 0) + return; + + NSUInteger modifiers = [theEvent modifierFlags]; + handleModifiersChanged(modifiers, *m_requester); +} + + +//////////////////////////////////////////////////////// ++(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event +{ + // Key code + sf::Keyboard::Key key = sf::Keyboard::Unknown; + + // First we look if the key down is from a list of characters + // that depend on keyboard localization. + NSString* string = [event charactersIgnoringModifiers]; + if ([string length] > 0) + key = sf::priv::HIDInputManager::localizedKeys([string characterAtIndex:0]); + + // If the key is not a localized one, we try to find a corresponding code + // through virtual key code. + if (key == sf::Keyboard::Unknown) + key = sf::priv::HIDInputManager::nonLocalizedKeys([event keyCode]); + + return keyEventWithModifiers([event modifierFlags], key); +} + + +//////////////////////////////////////////////////////// ++(BOOL)isValidTextUnicode:(NSEvent*)event +{ + if ([event keyCode] == 0x35) // Escape + { + return false; + } + else if ([[event characters] length] > 0) + { + unichar code = [[event characters] characterAtIndex:0]; + return ((code < 0xF700) || (code > 0xF8FF)); + } + else + { + return true; + } +} + +@end + diff --git a/src/SFML/Window/OSX/SFOpenGLView+keyboard_priv.h b/src/SFML/Window/OSX/SFOpenGLView+keyboard_priv.h new file mode 100644 index 0000000..c3710f5 --- /dev/null +++ b/src/SFML/Window/OSX/SFOpenGLView+keyboard_priv.h @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Window/Mouse.hpp> + +#import <AppKit/AppKit.h> + + +//////////////////////////////////////////////////////////// +/// Here are defined a few private messages for keyboard +/// handling in SFOpenGLView. +/// +//////////////////////////////////////////////////////////// + + +@interface SFOpenGLView (keyboard_priv) + +//////////////////////////////////////////////////////////// +/// \brief Convert a key down/up NSEvent into an SFML key event +/// +/// The conversion is based on localizedKeys and nonLocalizedKeys functions. +/// +/// \param event a key event +/// +/// \return sf::Keyboard::Unknown as Code if the key is unknown +/// +//////////////////////////////////////////////////////////// ++(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event; + +//////////////////////////////////////////////////////////// +/// \brief Check if the event represent some Unicode text +/// +/// The event is assumed to be a key down event. +/// False is returned if the event is either escape or a non text Unicode. +/// +/// \param event a key down event +/// +/// \return true if event represents a Unicode character, false otherwise +/// +//////////////////////////////////////////////////////////// ++(BOOL)isValidTextUnicode:(NSEvent*)event; + +@end diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse.mm b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm new file mode 100644 index 0000000..6349081 --- /dev/null +++ b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm @@ -0,0 +1,402 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Window/OSX/WindowImplCocoa.hpp> +#include <cmath> + +#import <SFML/Window/OSX/SFOpenGLView.h> +#import <SFML/Window/OSX/SFOpenGLView+mouse_priv.h> + + +//////////////////////////////////////////////////////////// +/// In this file, we implement mouse handling for SFOpenGLView +/// +//////////////////////////////////////////////////////////// + +@implementation SFOpenGLView (mouse) + +//////////////////////////////////////////////////////// +-(BOOL)isMouseInside +{ + NSPoint relativeToWindow = [[self window] mouseLocationOutsideOfEventStream]; + NSPoint relativeToView = [self convertPoint:relativeToWindow fromView:nil]; + + return NSPointInRect(relativeToView, [self bounds]); +} + + +//////////////////////////////////////////////////////// +-(void)updateMouseState +{ + // Update in/out state + BOOL mouseWasIn = m_mouseIsIn; + m_mouseIsIn = [self isMouseInside]; + + // Send event if needed. + if (m_requester != 0) + { + if (mouseWasIn && !m_mouseIsIn) + m_requester->mouseMovedOut(); + else if (!mouseWasIn && m_mouseIsIn) + m_requester->mouseMovedIn(); + } +} + + +//////////////////////////////////////////////////////// +-(void)setCursorGrabbed:(BOOL)grabbed +{ + m_cursorGrabbed = grabbed; + + [self updateCursorGrabbed]; +} + + +//////////////////////////////////////////////////////// +-(void)mouseDown:(NSEvent*)theEvent +{ + [self handleMouseDown:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] mouseDown:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)rightMouseDown:(NSEvent*)theEvent +{ + [self handleMouseDown:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] rightMouseDown:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)otherMouseDown:(NSEvent*)theEvent +{ + [self handleMouseDown:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] otherMouseDown:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)handleMouseDown:(NSEvent*)theEvent +{ + sf::Mouse::Button button = [SFOpenGLView mouseButtonFromEvent:theEvent]; + + if (m_requester != 0) + { + NSPoint loc = [self cursorPositionFromEvent:theEvent]; + + if (button != sf::Mouse::ButtonCount) + m_requester->mouseDownAt(button, loc.x, loc.y); + } +} + + +//////////////////////////////////////////////////////// +-(void)mouseUp:(NSEvent*)theEvent +{ + [self handleMouseUp:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] mouseUp:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)rightMouseUp:(NSEvent*)theEvent +{ + [self handleMouseUp:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] rightMouseUp:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)otherMouseUp:(NSEvent*)theEvent +{ + [self handleMouseUp:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] otherMouseUp:theEvent]; +} + + +//////////////////////////////////////////////////////////// +-(void)handleMouseUp:(NSEvent*)theEvent +{ + sf::Mouse::Button button = [SFOpenGLView mouseButtonFromEvent:theEvent]; + + if (m_requester != 0) + { + NSPoint loc = [self cursorPositionFromEvent:theEvent]; + + if (button != sf::Mouse::ButtonCount) + m_requester->mouseUpAt(button, loc.x, loc.y); + } +} + + +//////////////////////////////////////////////////////// +-(void)mouseMoved:(NSEvent*)theEvent +{ + [self handleMouseMove:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] mouseMoved:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)rightMouseDragged:(NSEvent*)theEvent +{ + [self handleMouseMove:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] rightMouseDragged:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)mouseDragged:(NSEvent*)theEvent +{ + [self handleMouseMove:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] mouseDragged:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)otherMouseDragged:(NSEvent*)theEvent +{ + [self handleMouseMove:theEvent]; + + // Transmit to non-SFML responder + [[self nextResponder] otherMouseUp:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)handleMouseMove:(NSEvent*)theEvent +{ + NSPoint loc = [self cursorPositionFromEvent:theEvent]; + + // If the cursor is grabbed, cursorPositionFromEvent: will + // return its correct position but not move actually it + // so we do it now. + if ([self isCursorCurrentlyGrabbed]) + [self moveCursorTo:loc]; + + // Make sure the point is inside the view. + // (mouseEntered: and mouseExited: are not immediately called + // when the mouse is dragged. That would be too easy!) + [self updateMouseState]; + if ((m_requester != 0) && m_mouseIsIn) + m_requester->mouseMovedAt(loc.x, loc.y); +} + + +//////////////////////////////////////////////////////// +-(BOOL)isCursorCurrentlyGrabbed +{ + return [[self window] isKeyWindow] && (m_cursorGrabbed || m_fullscreen); +} + + +//////////////////////////////////////////////////////// +-(void)updateCursorGrabbed +{ + // Disable/enable normal movements of the cursor + // and project the cursor if needed. + if ([self isCursorCurrentlyGrabbed]) + { + CGAssociateMouseAndMouseCursorPosition(NO); + + // Similarly to handleMouseMove: but without event. + NSPoint loc = [self cursorPositionFromEvent:nil]; + [self moveCursorTo:loc]; + } + else + { + CGAssociateMouseAndMouseCursorPosition(YES); + } +} + + +//////////////////////////////////////////////////////// +-(void)moveCursorTo:(NSPoint)loc +{ + // Convert the point from SFML coord system to screen coord system. + NSPoint screenLocation = [self computeGlobalPositionOfRelativePoint:loc]; + + // This won't produce a move event, which is perfect if the cursor was grabbed + // as we move it manually based on delta values of the cursor. + CGDisplayMoveCursorToPoint([self displayId], NSPointToCGPoint(screenLocation)); +} + + +//////////////////////////////////////////////////////// +-(CGDirectDisplayID)displayId +{ + NSScreen* screen = [[self window] screen]; + NSNumber* displayId = [[screen deviceDescription] objectForKey:@"NSScreenNumber"]; + return [displayId intValue]; +} + + +//////////////////////////////////////////////////////// +-(void)scrollWheel:(NSEvent*)theEvent +{ + if (m_requester != 0) + { + NSPoint loc = [self cursorPositionFromEvent:theEvent]; + m_requester->mouseWheelScrolledAt([theEvent deltaX], [theEvent deltaY], loc.x, loc.y); + } + + // Transmit to non-SFML responder + [[self nextResponder] scrollWheel:theEvent]; +} + + +//////////////////////////////////////////////////////// +-(void)mouseEntered:(NSEvent*)theEvent +{ + (void)theEvent; + [self updateMouseState]; +} + + +//////////////////////////////////////////////////////// +-(void)mouseExited:(NSEvent*)theEvent +{ + (void)theEvent; + [self updateMouseState]; +} + + +//////////////////////////////////////////////////////// +-(NSPoint)cursorPositionFromEvent:(NSEvent*)eventOrNil +{ + NSPoint rawPos; + + // If no event given then get current mouse pos. + if (eventOrNil == nil) + rawPos = [[self window] mouseLocationOutsideOfEventStream]; + else + rawPos = [eventOrNil locationInWindow]; + + if ([self isCursorCurrentlyGrabbed]) + { + if (eventOrNil != nil) + { + // Special case when the mouse is grabbed: + // we need to take into account the delta since the cursor + // is dissociated from its position. + + // Ignore any non-move related event + if (([eventOrNil type] == NSMouseMoved) || + ([eventOrNil type] == NSLeftMouseDragged) || + ([eventOrNil type] == NSRightMouseDragged) || + ([eventOrNil type] == NSOtherMouseDragged)) + { + // Without this factor, the cursor flies around waaay too fast! + // But I don't know if it because of retina display or because + // some event are sent twice (and that in itself is another mystery). + CGFloat factor = 2; + + // Also, this factor is not the same when keeping track of how much + // we move the cursor (buffers) when projecting the cursor into the + // view when grabbing the cursor for the first time. + CGFloat factorBuffer = m_fullscreen ? 1 : 2; + + CGFloat deltaX = [eventOrNil deltaX]; + CGFloat deltaY = [eventOrNil deltaY]; + + // If the buffer for X is empty, move the cursor; + // otherwise decrement this buffer a bit. + if (m_deltaXBuffer <= 0) + rawPos.x += deltaX / factor; + else + m_deltaXBuffer -= std::abs(deltaX / factorBuffer); + + // Rinse and repeat for Y. + if (m_deltaYBuffer <= 0) + rawPos.y -= deltaY / factor; + else + m_deltaYBuffer -= std::abs(deltaY / factorBuffer); + } + } + + // We also make sure the new point is inside the view + NSSize size = [self frame].size; + NSPoint origin = [self frame].origin; + NSPoint oldPos = rawPos; + rawPos.x = std::min(std::max(origin.x, rawPos.x), origin.x + size.width - 1); + rawPos.y = std::min(std::max(origin.y + 1, rawPos.y), origin.y + size.height); + // Note: the `-1` and `+1` on the two lines above prevent the user to click + // on the left or below the window, repectively, and therefore prevent the + // application to lose focus by accident. The sign of this offset is determinded + // by the direction of the x and y axis. + + // Increase X and Y buffer with the distance of the projection + m_deltaXBuffer += std::abs(rawPos.x - oldPos.x); + m_deltaYBuffer += std::abs(rawPos.y - oldPos.y); + } + + NSPoint loc = [self convertPoint:rawPos fromView:nil]; + + // Don't forget to change to SFML coord system. + float h = [self frame].size.height; + loc.y = h - loc.y; + + return loc; +} + + +//////////////////////////////////////////////////////// ++(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event +{ + switch ([event buttonNumber]) + { + case 0: return sf::Mouse::Left; + case 1: return sf::Mouse::Right; + case 2: return sf::Mouse::Middle; + case 3: return sf::Mouse::XButton1; + case 4: return sf::Mouse::XButton2; + default: return sf::Mouse::ButtonCount; // Never happens! (hopefully) + } +} + + +@end diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h b/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h new file mode 100644 index 0000000..f9b2ab7 --- /dev/null +++ b/src/SFML/Window/OSX/SFOpenGLView+mouse_priv.h @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include <SFML/Window/Mouse.hpp> + +#import <AppKit/AppKit.h> + + +//////////////////////////////////////////////////////////// +/// Here are defined a few private messages for mouse +/// handling in SFOpenGLView. +/// +//////////////////////////////////////////////////////////// + + +@interface SFOpenGLView (mouse_priv) + +//////////////////////////////////////////////////////////// +/// \brief Update the mouse state (in or out) +/// +/// Fire an event if its state has changed. +/// +//////////////////////////////////////////////////////////// +-(void)updateMouseState; + +//////////////////////////////////////////////////////////// +/// \brief handle mouse down event +/// +//////////////////////////////////////////////////////////// +-(void)handleMouseDown:(NSEvent*)theEvent; + +//////////////////////////////////////////////////////////// +/// \brief handle mouse up event +/// +//////////////////////////////////////////////////////////// +-(void)handleMouseUp:(NSEvent*)theEvent; + +//////////////////////////////////////////////////////////// +/// \brief handle mouse move event +/// +//////////////////////////////////////////////////////////// +-(void)handleMouseMove:(NSEvent*)theEvent; + +//////////////////////////////////////////////////////////// +/// \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. +/// +//////////////////////////////////////////////////////////// +-(BOOL)isCursorCurrentlyGrabbed; + +//////////////////////////////////////////////////////////// +/// \brief (Dis)connect the cursor's movements from/to the system +/// and project the cursor into the view +/// +//////////////////////////////////////////////////////////// +-(void)updateCursorGrabbed; + +//////////////////////////////////////////////////////////// +/// \brief Move the cursor to the given location +/// +/// \param loc location expressed in SFML coordinate system +/// +//////////////////////////////////////////////////////////// +-(void)moveCursorTo:(NSPoint)loc; + +//////////////////////////////////////////////////////////// +/// \brief Get the display identifier on which the view is +/// +//////////////////////////////////////////////////////////// +-(CGDirectDisplayID)displayId; + +//////////////////////////////////////////////////////////// +/// \brief Convert the NSEvent mouse button type to SFML type +/// +/// \param event a mouse button event +/// +/// \return Left, Right, ..., or ButtonCount if the button is unknown +/// +//////////////////////////////////////////////////////////// ++(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event; + +@end diff --git a/src/SFML/Window/OSX/SFOpenGLView.h b/src/SFML/Window/OSX/SFOpenGLView.h index 6a0d0b0..41d0c76 100644 --- a/src/SFML/Window/OSX/SFOpenGLView.h +++ b/src/SFML/Window/OSX/SFOpenGLView.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -47,6 +47,24 @@ namespace sf { /// Modifiers keys (cmd, ctrl, alt, shift) are handled by this class /// but the actual logic is done in SFKeyboardModifiersHelper.(h|mm). /// +/// The interface is subdivided into several categories in order +/// to have multiple implementation files to divide this monolithic +/// implementation. However, all attributes are defined in the main +/// interface declaration right below. +/// +/// Note about deltaXBuffer and deltaYBuffer: when grabbing the cursor +/// for the first time, either by entering fullscreen or through +/// setCursorGrabbed:, the cursor might be projected into the view. +/// Doing this will result in a big delta (relative movement) in the +/// next move event (cursorPositionFromEvent:), because no move event +/// is generated, which in turn will give the impression that the user +/// want to move the cursor by the same distance it was projected. To +/// prevent the cursor to fly twice the distance we keep track of how +/// much the cursor was projected in deltaXBuffer and deltaYBuffer. In +/// cursorPositionFromEvent: we can then reduce/augment those buffers +/// to determine when a move event should result in an actual move of +/// the cursor (that was disconnected from the system). +/// //////////////////////////////////////////////////////////// @interface SFOpenGLView : NSOpenGLView { @@ -56,6 +74,9 @@ namespace sf { NSTrackingArea* m_trackingArea; ///< Mouse tracking area BOOL m_fullscreen; ///< Indicate whether the window is fullscreen or not CGFloat m_scaleFactor; ///< Display scale factor (e.g. 1x for classic display, 2x for retina) + BOOL m_cursorGrabbed; ///< Is the mouse cursor trapped? + CGFloat m_deltaXBuffer; ///< See note about cursor grabbing above + CGFloat m_deltaYBuffer; ///< See note about cursor grabbing above // Hidden text view used to convert key event to actual chars. // We use a silent responder to prevent sound alerts. @@ -106,6 +127,18 @@ namespace sf { -(NSPoint)computeGlobalPositionOfRelativePoint:(NSPoint)point; //////////////////////////////////////////////////////////// +/// \brief Get the display scale factor +/// +/// \return e.g. 1.0 for classic display, 2.0 for retina display +/// +//////////////////////////////////////////////////////////// +-(CGFloat)displayScaleFactor; + +@end + +@interface SFOpenGLView (keyboard) + +//////////////////////////////////////////////////////////// /// \brief Enable key repeat /// //////////////////////////////////////////////////////////// @@ -117,19 +150,17 @@ namespace sf { //////////////////////////////////////////////////////////// -(void)disableKeyRepeat; -//////////////////////////////////////////////////////////// -/// \brief Get the display scale factor -/// -/// \return e.g. 1.0 for classic display, 2.0 for retina display -/// -//////////////////////////////////////////////////////////// --(CGFloat)displayScaleFactor; +@end + +@interface SFOpenGLView (mouse) //////////////////////////////////////////////////////////// /// \brief Compute the position of the cursor /// /// \param eventOrNil if nil the cursor position is the current one /// +/// \return the mouse position in SFML coord system +/// //////////////////////////////////////////////////////////// -(NSPoint)cursorPositionFromEvent:(NSEvent*)eventOrNil; @@ -141,4 +172,22 @@ namespace sf { //////////////////////////////////////////////////////////// -(BOOL)isMouseInside; +//////////////////////////////////////////////////////////// +/// Clips or releases the mouse cursor +/// +/// Generate a MouseEntered event when it makes sense. +/// +/// \param grabbed YES to grab, NO to release +/// +//////////////////////////////////////////////////////////// +-(void)setCursorGrabbed:(BOOL)grabbed; + +//////////////////////////////////////////////////////////// +/// Update the cursor position according to the grabbing behaviour +/// +/// This function has to be called when the window's state change +/// +//////////////////////////////////////////////////////////// +-(void)updateCursorGrabbed; + @end diff --git a/src/SFML/Window/OSX/SFOpenGLView.mm b/src/SFML/Window/OSX/SFOpenGLView.mm index 137b7b0..80cd624 100644 --- a/src/SFML/Window/OSX/SFOpenGLView.mm +++ b/src/SFML/Window/OSX/SFOpenGLView.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -27,29 +27,14 @@ // Headers //////////////////////////////////////////////////////////// #include <SFML/Window/OSX/WindowImplCocoa.hpp> -#include <SFML/Window/OSX/HIDInputManager.hpp> // For localizedKeys and nonLocalizedKeys #include <SFML/System/Err.hpp> -#import <SFML/Window/OSX/SFKeyboardModifiersHelper.h> #import <SFML/Window/OSX/SFOpenGLView.h> +#import <SFML/Window/OSX/SFOpenGLView+mouse_priv.h> #import <SFML/Window/OSX/SFSilentResponder.h> //////////////////////////////////////////////////////////// -/// \brief Check if the event represent some Unicode text -/// -/// The event is assumed to be a key down event. -/// False is returned if the event is either escape or a non text Unicode. -/// -/// \param event a key down event -/// -/// \return true if event represents a Unicode character, false otherwise -/// -//////////////////////////////////////////////////////////// -BOOL isValidTextUnicode(NSEvent* event); - - -//////////////////////////////////////////////////////////// /// SFOpenGLView class: Privates Methods Declaration /// //////////////////////////////////////////////////////////// @@ -68,14 +53,6 @@ BOOL isValidTextUnicode(NSEvent* event); -(void)viewDidEndLiveResize; //////////////////////////////////////////////////////////// -/// \brief Update the mouse state (in or out) -/// -/// Fire an event if its state has changed. -/// -//////////////////////////////////////////////////////////// --(void)updateMouseState; - -//////////////////////////////////////////////////////////// /// \brief Callback for focus event /// //////////////////////////////////////////////////////////// @@ -99,28 +76,6 @@ BOOL isValidTextUnicode(NSEvent* event); //////////////////////////////////////////////////////////// -(void)exitFullscreen; -//////////////////////////////////////////////////////////// -/// \brief Convert the NSEvent mouse button type to SFML type -/// -/// \param event a mouse button event -/// -/// \return Left, Right, ..., or ButtonCount if the button is unknown -/// -//////////////////////////////////////////////////////////// --(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event; - -//////////////////////////////////////////////////////////// -/// \brief Convert a key down/up NSEvent into an SFML key event -/// -/// The conversion is based on localizedKeys and nonLocalizedKeys functions. -/// -/// \param event a key event -/// -/// \return sf::Keyboard::Unknown as Code if the key is unknown -/// -//////////////////////////////////////////////////////////// -+(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event; - @end @implementation SFOpenGLView @@ -153,6 +108,9 @@ BOOL isValidTextUnicode(NSEvent* event); m_fullscreen = isFullscreen; m_scaleFactor = 1.0; // Default value; it will be updated in finishInit + m_cursorGrabbed = NO; + m_deltaXBuffer = 0; + m_deltaYBuffer = 0; // Create a hidden text view for parsing key down event properly m_silentResponder = [[SFSilentResponder alloc] init]; @@ -171,6 +129,17 @@ BOOL isValidTextUnicode(NSEvent* event); //////////////////////////////////////////////////////// +-(void)update +{ + // In order to prevent an infinite recursion when the window/view is + // resized to zero-height/width, we ignore update event when resizing. + if (![self inLiveResize]) { + [super update]; + } +} + + +//////////////////////////////////////////////////////// -(void)finishInit { // Register for window focus events @@ -197,8 +166,9 @@ BOOL isValidTextUnicode(NSEvent* event); name:NSWindowDidChangeScreenProfileNotification object:[self window]]; - // Now that we have a window, set up correctly the scale factor + // Now that we have a window, set up correctly the scale factor and cursor grabbing [self updateScaleFactor]; + [self updateCursorGrabbed]; // update for fullscreen } @@ -241,20 +211,6 @@ BOOL isValidTextUnicode(NSEvent* event); //////////////////////////////////////////////////////// --(void)enableKeyRepeat -{ - m_useKeyRepeat = YES; -} - - -//////////////////////////////////////////////////////// --(void)disableKeyRepeat -{ - m_useKeyRepeat = NO; -} - - -//////////////////////////////////////////////////////// -(CGFloat)displayScaleFactor { return m_scaleFactor; @@ -293,6 +249,7 @@ BOOL isValidTextUnicode(NSEvent* event); // Update mouse internal state. [self updateMouseState]; + [self updateCursorGrabbed]; // Update the OGL view to fit the new size. [self update]; @@ -306,39 +263,13 @@ BOOL isValidTextUnicode(NSEvent* event); m_requester->windowResized(newSize.width, newSize.height); } - -//////////////////////////////////////////////////////// --(BOOL)isMouseInside -{ - NSPoint relativeToWindow = [[self window] mouseLocationOutsideOfEventStream]; - NSPoint relativeToView = [self convertPoint:relativeToWindow fromView:nil]; - - return NSPointInRect(relativeToView, [self bounds]); -} - - -//////////////////////////////////////////////////////// --(void)updateMouseState -{ - BOOL mouseWasIn = m_mouseIsIn; - m_mouseIsIn = [self isMouseInside]; - - if (m_requester == 0) - return; - - // Send event if needed. - if (mouseWasIn && !m_mouseIsIn) - m_requester->mouseMovedOut(); - else if (!mouseWasIn && m_mouseIsIn) - m_requester->mouseMovedIn(); -} - - //////////////////////////////////////////////////////// -(void)windowDidBecomeKey:(NSNotification*)notification { (void)notification; + [self updateCursorGrabbed]; + if (m_requester) m_requester->windowGainedFocus(); @@ -352,6 +283,8 @@ BOOL isValidTextUnicode(NSEvent* event); { (void)notification; + [self updateCursorGrabbed]; + if (m_requester) m_requester->windowLostFocus(); @@ -415,398 +348,4 @@ BOOL isValidTextUnicode(NSEvent* event); } -//////////////////////////////////////////////////////// --(BOOL)acceptsFirstResponder -{ - // Accepts key event. - return YES; -} - - -//////////////////////////////////////////////////////// --(BOOL)canBecomeKeyView -{ - // Accepts key event. - return YES; -} - - -#pragma mark -#pragma mark Mouse-event methods - - -//////////////////////////////////////////////////////// --(void)mouseDown:(NSEvent*)theEvent -{ - // Forward to... - [self otherMouseDown:theEvent]; - - // Transmit to non-SFML responder - [[self nextResponder] mouseDown:theEvent]; -} - - -//////////////////////////////////////////////////////// --(void)mouseUp:(NSEvent*)theEvent -{ - // Forward to... - [self otherMouseUp:theEvent]; - - // Transmit to non-SFML responder - [[self nextResponder] mouseUp:theEvent]; -} - - -//////////////////////////////////////////////////////// --(void)mouseMoved:(NSEvent*)theEvent -{ - // Forward to... - [self otherMouseDragged:theEvent]; - - // Transmit to non-SFML responder - [[self nextResponder] mouseMoved:theEvent]; -} - - -//////////////////////////////////////////////////////// --(void)scrollWheel:(NSEvent*)theEvent -{ - if (m_requester != 0) - { - NSPoint loc = [self cursorPositionFromEvent:theEvent]; - m_requester->mouseWheelScrolledAt([theEvent deltaX], [theEvent deltaY], loc.x, loc.y); - } - - // Transmit to non-SFML responder - [[self nextResponder] scrollWheel:theEvent]; -} - - -//////////////////////////////////////////////////////// --(void)mouseEntered:(NSEvent*)theEvent -{ - (void)theEvent; - [self updateMouseState]; -} - - -//////////////////////////////////////////////////////// --(void)mouseExited:(NSEvent*)theEvent -{ - (void)theEvent; - [self updateMouseState]; -} - - -//////////////////////////////////////////////////////// --(void)rightMouseDown:(NSEvent*)theEvent -{ - // Forward to... - [self otherMouseDown:theEvent]; - - // Transmit to non-SFML responder - [[self nextResponder] rightMouseDown:theEvent]; -} - - -//////////////////////////////////////////////////////// --(void)rightMouseUp:(NSEvent*)theEvent -{ - // Forward to... - [self otherMouseUp:theEvent]; - - // Transmit to non-SFML responder - [[self nextResponder] rightMouseUp:theEvent]; -} - - -//////////////////////////////////////////////////////// --(void)otherMouseDown:(NSEvent*)theEvent -{ - sf::Mouse::Button button = [self mouseButtonFromEvent:theEvent]; - - if (m_requester != 0) - { - NSPoint loc = [self cursorPositionFromEvent:theEvent]; - - if (button != sf::Mouse::ButtonCount) - m_requester->mouseDownAt(button, loc.x, loc.y); - } - - // If the event is not forwarded by mouseDown or rightMouseDown... - if ((button != sf::Mouse::Left) && (button != sf::Mouse::Right)) - { - // ... transmit to non-SFML responder - [[self nextResponder] otherMouseDown:theEvent]; - } -} - - -//////////////////////////////////////////////////////// --(void)otherMouseUp:(NSEvent*)theEvent -{ - sf::Mouse::Button button = [self mouseButtonFromEvent:theEvent]; - - if (m_requester != 0) - { - NSPoint loc = [self cursorPositionFromEvent:theEvent]; - - if (button != sf::Mouse::ButtonCount) - m_requester->mouseUpAt(button, loc.x, loc.y); - } - - // If the event is not forwarded by mouseUp or rightMouseUp... - if ((button != sf::Mouse::Left) && (button != sf::Mouse::Right)) - { - // ... transmit to non-SFML responder - [[self nextResponder] otherMouseUp:theEvent]; - } -} - - -//////////////////////////////////////////////////////// --(void)rightMouseDragged:(NSEvent*)theEvent -{ - // Forward to... - [self otherMouseDragged:theEvent]; - - // Transmit to non-SFML responder - [[self nextResponder] rightMouseDragged:theEvent]; -} - - -//////////////////////////////////////////////////////// --(void)mouseDragged:(NSEvent*)theEvent -{ - // Forward to... - [self otherMouseDragged:theEvent]; - - // Transmit to non-SFML responder - [[self nextResponder] mouseDragged:theEvent]; -} - - -//////////////////////////////////////////////////////// --(void)otherMouseDragged:(NSEvent*)theEvent -{ - if (m_requester != 0) - { - NSPoint loc = [self cursorPositionFromEvent:theEvent]; - - // Make sure the point is inside the view. - // (mouseEntered: and mouseExited: are not immediately called - // when the mouse is dragged. That would be too easy!) - [self updateMouseState]; - if (m_mouseIsIn) - m_requester->mouseMovedAt(loc.x, loc.y); - } - - // If the event is not forwarded by mouseDragged or rightMouseDragged... - sf::Mouse::Button button = [self mouseButtonFromEvent:theEvent]; - if ((button != sf::Mouse::Left) && (button != sf::Mouse::Right)) - { - // ... transmit to non-SFML responder - [[self nextResponder] otherMouseUp:theEvent]; - } -} - - -//////////////////////////////////////////////////////// --(NSPoint)cursorPositionFromEvent:(NSEvent*)eventOrNil -{ - NSPoint loc; - // If no event given then get current mouse pos. - if (eventOrNil == nil) - { - NSPoint rawPos = [[self window] mouseLocationOutsideOfEventStream]; - loc = [self convertPoint:rawPos fromView:nil]; - } - else - { - loc = [self convertPoint:[eventOrNil locationInWindow] fromView:nil]; - } - - // Don't forget to change to SFML coord system. - float h = [self frame].size.height; - loc.y = h - loc.y; - - return loc; -} - - -//////////////////////////////////////////////////////// --(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event -{ - switch ([event buttonNumber]) - { - case 0: return sf::Mouse::Left; - case 1: return sf::Mouse::Right; - case 2: return sf::Mouse::Middle; - case 3: return sf::Mouse::XButton1; - case 4: return sf::Mouse::XButton2; - default: return sf::Mouse::ButtonCount; // Never happens! (hopefully) - } -} - - -#pragma mark -#pragma mark Key-event methods - - -//////////////////////////////////////////////////////// --(void)keyDown:(NSEvent*)theEvent -{ - // Transmit to non-SFML responder - [[self nextResponder] keyDown:theEvent]; - - if (m_requester == 0) - return; - - // Handle key down event - if (m_useKeyRepeat || ![theEvent isARepeat]) - { - sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent]; - - if (key.code != sf::Keyboard::Unknown) // The key is recognized. - m_requester->keyDown(key); - } - - - // Handle text entered event: - // Ignore event if we don't want repeated keystrokes - if (m_useKeyRepeat || ![theEvent isARepeat]) - { - // Ignore escape key and other non text keycode (See NSEvent.h) - // because they produce a sound alert. - if (isValidTextUnicode(theEvent)) - { - // Send the event to the hidden text view for processing - [m_hiddenTextView interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; - } - - // Carefully handle backspace and delete.. - // Note: the event is intentionally sent to the hidden view - // even if we do something more specific below. This way - // key combination are correctly interpreted. - - unsigned short keycode = [theEvent keyCode]; - - // Backspace - if (keycode == 0x33) - { - // Send the correct Unicode value (i.e. 8) instead of 127 (which is 'delete') - m_requester->textEntered(8); - } - - // Delete - else if ((keycode == 0x75) || (keycode == NSDeleteFunctionKey)) - { - // Instead of the value 63272 we send 127. - m_requester->textEntered(127); - } - - // Otherwise, let's see what our hidden field has computed - else - { - NSString* string = [m_hiddenTextView string]; - - // Send each character to SFML event requester - for (NSUInteger index = 0; index < [string length]; ++index) - m_requester->textEntered([string characterAtIndex:index]); - - // Empty our hidden cache - [m_hiddenTextView setString:@""]; - } - } -} - - -//////////////////////////////////////////////////////// --(void)sfKeyUp:(NSEvent*)theEvent -{ - // For some mystic reasons, key released events don't work the same way - // as key pressed events... We somewhat hijack the event chain of response - // in -[SFApplication sendEvent:] and resume this chain with the next - // responder. - // This is workaround to make sure key released events are fired in - // fullscreen window too. - - // Transmit to non-SFML responder - [[self nextResponder] keyUp:theEvent]; - - if (m_requester == 0) - return; - - sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent]; - - if (key.code != sf::Keyboard::Unknown) // The key is recognized. - m_requester->keyUp(key); -} - - -//////////////////////////////////////////////////////// --(void)flagsChanged:(NSEvent*)theEvent -{ - // Transmit to non-SFML responder - [[self nextResponder] flagsChanged:theEvent]; - - if (m_requester == 0) - return; - - NSUInteger modifiers = [theEvent modifierFlags]; - handleModifiersChanged(modifiers, *m_requester); -} - - -//////////////////////////////////////////////////////// -+(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event -{ - // Key code - sf::Keyboard::Key key = sf::Keyboard::Unknown; - - // First we look if the key down is from a list of characters - // that depend on keyboard localization. - NSString* string = [event charactersIgnoringModifiers]; - if ([string length] > 0) - key = sf::priv::HIDInputManager::localizedKeys([string characterAtIndex:0]); - - // If the key is not a localized one, we try to find a corresponding code - // through virtual key code. - if (key == sf::Keyboard::Unknown) - key = sf::priv::HIDInputManager::nonLocalizedKeys([event keyCode]); - -//#ifdef SFML_DEBUG // Don't bother the final customers with annoying messages. -// if (key.code == sf::Keyboard::Unknown) { // The key is unknown. -// sf::err() << "This is an unknown key. Virtual key code is 0x" -// << std::hex -// << [event keyCode] -// << "." -// << std::endl; -// } -//#endif - - return keyEventWithModifiers([event modifierFlags], key); -} - @end - - -#pragma mark - C-like functions - -BOOL isValidTextUnicode(NSEvent* event) -{ - if ([event keyCode] == 0x35) // Escape - { - return false; - } - else if ([[event characters] length] > 0) - { - unichar code = [[event characters] characterAtIndex:0]; - return ((code < 0xF700) || (code > 0xF8FF)); - } - else - { - return true; - } -} - diff --git a/src/SFML/Window/OSX/SFSilentResponder.h b/src/SFML/Window/OSX/SFSilentResponder.h index 0f00dd3..0a92244 100644 --- a/src/SFML/Window/OSX/SFSilentResponder.h +++ b/src/SFML/Window/OSX/SFSilentResponder.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFSilentResponder.m b/src/SFML/Window/OSX/SFSilentResponder.m index f256a2f..e576d77 100644 --- a/src/SFML/Window/OSX/SFSilentResponder.m +++ b/src/SFML/Window/OSX/SFSilentResponder.m @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFViewController.h b/src/SFML/Window/OSX/SFViewController.h index b6d0a0a..3907538 100644 --- a/src/SFML/Window/OSX/SFViewController.h +++ b/src/SFML/Window/OSX/SFViewController.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFViewController.mm b/src/SFML/Window/OSX/SFViewController.mm index 8e35f79..7d736e3 100644 --- a/src/SFML/Window/OSX/SFViewController.mm +++ b/src/SFML/Window/OSX/SFViewController.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -121,6 +121,13 @@ } +//////////////////////////////////////////////////////// +-(void)setCursorGrabbed:(BOOL)grabbed +{ + [m_oglView setCursorGrabbed:grabbed]; +} + + //////////////////////////////////////////////////////////// -(NSPoint)position { diff --git a/src/SFML/Window/OSX/SFWindow.h b/src/SFML/Window/OSX/SFWindow.h index 36ebc92..af0e10a 100644 --- a/src/SFML/Window/OSX/SFWindow.h +++ b/src/SFML/Window/OSX/SFWindow.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFWindow.m b/src/SFML/Window/OSX/SFWindow.m index 7a4ee75..2e8c14b 100644 --- a/src/SFML/Window/OSX/SFWindow.m +++ b/src/SFML/Window/OSX/SFWindow.m @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/SFWindowController.h b/src/SFML/Window/OSX/SFWindowController.h index 4435ad0..331336b 100644 --- a/src/SFML/Window/OSX/SFWindowController.h +++ b/src/SFML/Window/OSX/SFWindowController.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -49,12 +49,19 @@ namespace sf { /// Used when SFML handle everything and when a NSWindow* is given /// as handle to WindowImpl. /// +/// When grabbing the cursor, if the window is resizeable, m_restoreResize is +/// set to YES and the window is marked as not resizeable. This is to prevent +/// accidental resize by the user. When the cursor is released, the window +/// style is restored. +/// //////////////////////////////////////////////////////////// @interface SFWindowController : NSResponder <WindowImplDelegateProtocol, NSWindowDelegate> { NSWindow* m_window; ///< Underlying Cocoa window to be controlled SFOpenGLView* m_oglView; ///< OpenGL view for rendering sf::priv::WindowImplCocoa* m_requester; ///< Requester + BOOL m_fullscreen; ///< Indicate whether the window is fullscreen or not + BOOL m_restoreResize; ///< See note above } //////////////////////////////////////////////////////////// diff --git a/src/SFML/Window/OSX/SFWindowController.mm b/src/SFML/Window/OSX/SFWindowController.mm index 1d2a915..a6e52ed 100644 --- a/src/SFML/Window/OSX/SFWindowController.mm +++ b/src/SFML/Window/OSX/SFWindowController.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -32,7 +32,10 @@ #include <SFML/Window/OSX/WindowImplCocoa.hpp> #include <SFML/System/Err.hpp> #include <ApplicationServices/ApplicationServices.h> +#include <algorithm> +#import <SFML/Window/OSX/NSImage+raw.h> +#import <SFML/Window/OSX/Scaling.h> #import <SFML/Window/OSX/SFApplication.h> #import <SFML/Window/OSX/SFOpenGLView.h> #import <SFML/Window/OSX/SFWindow.h> @@ -94,6 +97,8 @@ m_window = nil; m_oglView = nil; m_requester = 0; + m_fullscreen = NO; // assuming this is the case... too hard to handle anyway. + m_restoreResize = NO; // Retain the window for our own use. m_window = [window retain]; @@ -144,8 +149,10 @@ m_window = nil; m_oglView = nil; m_requester = 0; + m_fullscreen = (style & sf::Style::Fullscreen); + m_restoreResize = NO; - if (style & sf::Style::Fullscreen) + if (m_fullscreen) [self setupFullscreenViewWithMode:mode]; else [self setupWindowWithMode:mode andStyle:style]; @@ -161,6 +168,7 @@ { // Create a screen-sized window on the main display sf::VideoMode desktop = sf::VideoMode::getDesktopMode(); + sf::priv::scaleInWidthHeight(desktop, nil); NSRect windowRect = NSMakeRect(0, 0, desktop.width, desktop.height); m_window = [[SFWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask @@ -201,9 +209,11 @@ } // Create our OpenGL view size and the view - CGFloat x = (desktop.width - mode.width) / 2.0; - CGFloat y = (desktop.height - mode.height) / 2.0; - NSRect oglRect = NSMakeRect(x, y, mode.width, mode.height); + CGFloat width = std::min(mode.width, desktop.width); + CGFloat height = std::min(mode.height, desktop.height); + CGFloat x = (desktop.width - width) / 2.0; + CGFloat y = (desktop.height - height) / 2.0; + NSRect oglRect = NSMakeRect(x, y, width, height); m_oglView = [[SFOpenGLView alloc] initWithFrame:oglRect fullscreen:YES]; @@ -338,41 +348,66 @@ } +//////////////////////////////////////////////////////// +-(void)setCursorGrabbed:(BOOL)grabbed +{ + // Remove or restore resizeable style if needed + BOOL resizeable = [m_window styleMask] & NSResizableWindowMask; + if (grabbed && resizeable) + { + m_restoreResize = YES; + NSUInteger newStyle = [m_window styleMask] & ~NSResizableWindowMask; + [m_window setStyleMask:newStyle]; + } + else if (!grabbed && m_restoreResize) + { + m_restoreResize = NO; + NSUInteger newStyle = [m_window styleMask] | NSResizableWindowMask; + [m_window setStyleMask:newStyle]; + } + + // Forward to our view + [m_oglView setCursorGrabbed:grabbed]; +} + + //////////////////////////////////////////////////////////// -(NSPoint)position { - // First, get the top left corner of the view in its own base system - const NSPoint origin = [m_oglView frame].origin; - const NSSize size = [m_oglView frame].size; - const NSPoint topLeftCornerOfView = NSMakePoint(origin.x, origin.y + size.height); - const NSPoint positionInView = [m_oglView convertPointToBacking:topLeftCornerOfView]; + // Note: since 10.7 the conversion API works with NSRect + // instead of NSPoint. Therefore we use a NSRect but ignore + // its width and height. - // Then, convert it to window base system - const NSPoint positionInWindow = [m_oglView convertPoint:positionInView toView:nil]; - // here nil denotes the window containing the view + // Position of the bottom-left corner in the different coordinate systems: + NSRect corner = [m_oglView frame]; // bottom left; size is ignored + NSRect view = [m_oglView convertRectToBacking:corner]; + NSRect window = [m_oglView convertRect:view toView:nil]; + NSRect screen = [[m_oglView window] convertRectToScreen:window]; - // Next, convert it to the screen base system - const NSPoint positionInScreen = [[m_oglView window] convertBaseToScreen:positionInWindow]; + // Get the top-left corner in screen coordinates + CGFloat x = screen.origin.x; + CGFloat y = screen.origin.y + [m_oglView frame].size.height; - // Finally, flip for SFML window coordinate system - // Don't forget to discard the title bar ! - const NSPoint positionInSFML = NSMakePoint(positionInScreen.x, - ([self screenHeight] - [self titlebarHeight]) - positionInScreen.y); + // Flip y-axis (titlebar was already taken into account above) + y = [self screenHeight] - y; - return positionInSFML; + return NSMakePoint(x, y); } -////////////////////////////////////////////////////////. +//////////////////////////////////////////////////////// -(void)setWindowPositionToX:(int)x Y:(int)y { NSPoint point = NSMakePoint(x, y); - // Flip for SFML window coordinate system. - point.y = [self screenHeight] - point.y; + // Flip for SFML window coordinate system and take titlebar into account + point.y = [self screenHeight] - point.y + [self titlebarHeight]; // Place the window. [m_window setFrameTopLeftPoint:point]; + + // In case the cursor was grabbed we need to update its position + [m_oglView updateCursorGrabbed]; } @@ -386,37 +421,57 @@ //////////////////////////////////////////////////////// -(void)resizeTo:(unsigned int)width by:(unsigned int)height { - // Before resizing, remove resizable mask to be able to resize - // beyond the desktop boundaries. - NSUInteger styleMask = [m_window styleMask]; + if (m_fullscreen) + { + // Special case when fullscreen: only resize the opengl view + // and make sure the requested size is not bigger than the window. + sf::VideoMode desktop = sf::VideoMode::getDesktopMode(); + sf::priv::scaleInWidthHeight(desktop, nil); - [m_window setStyleMask:styleMask ^ NSResizableWindowMask]; + width = std::min(width, desktop.width); + height = std::min(height, desktop.height); - // Add titlebar height. - height += [self titlebarHeight]; + CGFloat x = (desktop.width - width) / 2.0; + CGFloat y = (desktop.height - height) / 2.0; + NSRect oglRect = NSMakeRect(x, y, width, height); - // Corner case: don't set the window height bigger than the screen height - // or the view will be resized _later_ without generating a resize event. - NSRect screenFrame = [[NSScreen mainScreen] visibleFrame]; - CGFloat maxVisibleHeight = screenFrame.size.height; - if (height > maxVisibleHeight) + [m_oglView setFrame:oglRect]; + [m_oglView setNeedsDisplay:YES]; + } + else { - height = maxVisibleHeight; + // Before resizing, remove resizable mask to be able to resize + // beyond the desktop boundaries. + NSUInteger styleMask = [m_window styleMask]; - // The size is not the requested one, we fire an event - if (m_requester != 0) - m_requester->windowResized(width, height - [self titlebarHeight]); - } + [m_window setStyleMask:styleMask ^ NSResizableWindowMask]; + + // Add titlebar height. + height += [self titlebarHeight]; - NSRect frame = NSMakeRect([m_window frame].origin.x, - [m_window frame].origin.y, - width, - height); + // Corner case: don't set the window height bigger than the screen height + // or the view will be resized _later_ without generating a resize event. + NSRect screenFrame = [[NSScreen mainScreen] visibleFrame]; + CGFloat maxVisibleHeight = screenFrame.size.height; + if (height > maxVisibleHeight) + { + height = maxVisibleHeight; - [m_window setFrame:frame display:YES]; + // The size is not the requested one, we fire an event + if (m_requester != 0) + m_requester->windowResized(width, height - [self titlebarHeight]); + } - // And restore the mask - [m_window setStyleMask:styleMask]; + NSRect frame = NSMakeRect([m_window frame].origin.x, + [m_window frame].origin.y, + width, + height); + + [m_window setFrame:frame display:YES]; + + // And restore the mask + [m_window setStyleMask:styleMask]; + } } @@ -487,40 +542,13 @@ by:(unsigned int)height with:(const sf::Uint8*)pixels { - // Create an empty image representation. - NSBitmapImageRep* bitmap = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:0 // if 0: only allocate memory - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 // The number of bits used to specify - // one pixel in a single component of the data. - samplesPerPixel:4 // 3 if no alpha, 4 with it - hasAlpha:YES - isPlanar:NO // I don't know what it is but it works - colorSpaceName:NSCalibratedRGBColorSpace - bytesPerRow:0 // 0 == determine automatically - bitsPerPixel:0]; // 0 == determine automatically - - // Load data pixels. - for (unsigned int y = 0; y < height; ++y) - { - for (unsigned int x = 0; x < width; ++x, pixels+=4) - { - NSUInteger pixel[4] = { pixels[0], pixels[1], pixels[2], pixels[3] }; - [bitmap setPixel:pixel atX:x y:y]; - } - } - - // Create an image from the representation. - NSImage* icon = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; - [icon addRepresentation:bitmap]; + // Load image and set app icon. + NSImage* icon = [NSImage imageWithRawData:pixels + andSize:NSMakeSize(width, height)]; - // Set app icon. [[SFApplication sharedApplication] setApplicationIconImage:icon]; - // Free up. [icon release]; - [bitmap release]; } @@ -591,3 +619,4 @@ } @end + diff --git a/src/SFML/Window/OSX/Scaling.h b/src/SFML/Window/OSX/Scaling.h new file mode 100644 index 0000000..ee5d29b --- /dev/null +++ b/src/SFML/Window/OSX/Scaling.h @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#import <SFML/Window/OSX/WindowImplDelegateProtocol.h> + +#import <AppKit/AppKit.h> + +namespace sf +{ +namespace priv +{ + +//////////////////////////////////////////////////////////// +/// \brief Get the scale factor of the main screen +/// +//////////////////////////////////////////////////////////// +inline CGFloat getDefaultScaleFactor() +{ + return [[NSScreen mainScreen] backingScaleFactor]; +} + +//////////////////////////////////////////////////////////// +/// \brief Scale SFML coordinates to backing coordinates +/// +/// \param in SFML coordinates to be converted +/// \param delegate an object implementing WindowImplDelegateProtocol, or nil for default scale +/// +//////////////////////////////////////////////////////////// +template <class T> +void scaleIn(T& in, id<WindowImplDelegateProtocol> delegate) +{ + in /= delegate ? [delegate displayScaleFactor] : getDefaultScaleFactor(); +} + +template <class T> +void scaleInWidthHeight(T& in, id<WindowImplDelegateProtocol> delegate) +{ + scaleIn(in.width, delegate); + scaleIn(in.height, delegate); +} + +template <class T> +void scaleInXY(T& in, id<WindowImplDelegateProtocol> delegate) +{ + scaleIn(in.x, delegate); + scaleIn(in.y, delegate); +} + +//////////////////////////////////////////////////////////// +/// \brief Scale backing coordinates to SFML coordinates +/// +/// \param out backing coordinates to be converted +/// \param delegate an object implementing WindowImplDelegateProtocol, or nil for default scale +/// +//////////////////////////////////////////////////////////// +template <class T> +void scaleOut(T& out, id<WindowImplDelegateProtocol> delegate) +{ + out *= delegate ? [delegate displayScaleFactor] : getDefaultScaleFactor(); +} + +template <class T> +void scaleOutWidthHeight(T& out, id<WindowImplDelegateProtocol> delegate) +{ + scaleOut(out.width, delegate); + scaleOut(out.height, delegate); +} + +template <class T> +void scaleOutXY(T& out, id<WindowImplDelegateProtocol> delegate) +{ + scaleOut(out.x, delegate); + scaleOut(out.y, delegate); +} + +} // namespace priv +} // namespace sf + diff --git a/src/SFML/Window/OSX/SensorImpl.cpp b/src/SFML/Window/OSX/SensorImpl.cpp index 144c6d7..fb8fce1 100644 --- a/src/SFML/Window/OSX/SensorImpl.cpp +++ b/src/SFML/Window/OSX/SensorImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/OSX/SensorImpl.hpp b/src/SFML/Window/OSX/SensorImpl.hpp index 68b810e..c630c39 100644 --- a/src/SFML/Window/OSX/SensorImpl.hpp +++ b/src/SFML/Window/OSX/SensorImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/OSX/VideoModeImpl.cpp b/src/SFML/Window/OSX/VideoModeImpl.cpp index d83d17d..94d8edd 100644 --- a/src/SFML/Window/OSX/VideoModeImpl.cpp +++ b/src/SFML/Window/OSX/VideoModeImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -50,6 +50,8 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes() return modes; } + VideoMode desktop = getDesktopMode(); + // Loop on each mode and convert it into a sf::VideoMode object. const CFIndex modesCount = CFArrayGetCount(cgmodes); for (CFIndex i = 0; i < modesCount; i++) @@ -58,6 +60,10 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes() VideoMode mode = convertCGModeToSFMode(cgmode); + // Skip if bigger than desktop as we currently don't perform hard resolution switch + if ((mode.width > desktop.width) || (mode.height > desktop.height)) + continue; + // If not yet listed we add it to our modes array. if (std::find(modes.begin(), modes.end(), mode) == modes.end()) modes.push_back(mode); @@ -73,12 +79,21 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes() //////////////////////////////////////////////////////////// VideoMode VideoModeImpl::getDesktopMode() { + VideoMode mode; // RVO + + // Rely exclusively on mode and convertCGModeToSFMode + // instead of display id and CGDisplayPixelsHigh/Wide. + CGDirectDisplayID display = CGMainDisplayID(); - return VideoMode(CGDisplayPixelsWide(display), - CGDisplayPixelsHigh(display), - displayBitsPerPixel(display)); + CGDisplayModeRef cgmode = CGDisplayCopyDisplayMode(display); + + mode = convertCGModeToSFMode(cgmode); + + CGDisplayModeRelease(cgmode); + + return mode; } } // namespace priv - } // namespace sf + diff --git a/src/SFML/Window/OSX/WindowImplCocoa.hpp b/src/SFML/Window/OSX/WindowImplCocoa.hpp index 486bf78..1036f72 100644 --- a/src/SFML/Window/OSX/WindowImplCocoa.hpp +++ b/src/SFML/Window/OSX/WindowImplCocoa.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -314,6 +314,14 @@ public: virtual void setMouseCursorVisible(bool visible); //////////////////////////////////////////////////////////// + /// \brief Grab or release the mouse cursor + /// + /// \param grabbed True to grab, false to release + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursorGrabbed(bool grabbed); + + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// /// \param enabled True to enable, false to disable diff --git a/src/SFML/Window/OSX/WindowImplCocoa.mm b/src/SFML/Window/OSX/WindowImplCocoa.mm index 927d5b4..78be5af 100644 --- a/src/SFML/Window/OSX/WindowImplCocoa.mm +++ b/src/SFML/Window/OSX/WindowImplCocoa.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -28,10 +28,10 @@ //////////////////////////////////////////////////////////// #include <SFML/Window/OSX/WindowImplCocoa.hpp> #include <SFML/System/Err.hpp> -#include <SFML/System/String.hpp> #import <SFML/Window/OSX/AutoreleasePoolWrapper.h> #import <SFML/Window/OSX/cpp_objc_conversion.h> +#import <SFML/Window/OSX/Scaling.h> #import <SFML/Window/OSX/SFApplication.h> #import <SFML/Window/OSX/SFApplicationDelegate.h> #import <SFML/Window/OSX/SFKeyboardModifiersHelper.h> @@ -44,76 +44,6 @@ namespace priv { //////////////////////////////////////////////////////////// -/// \brief Get the scale factor of the main screen -/// -//////////////////////////////////////////////////////////// -CGFloat getDefaultScaleFactor() -{ - return [[NSScreen mainScreen] backingScaleFactor]; -} - -//////////////////////////////////////////////////////////// -/// \brief Scale SFML coordinates to backing coordinates -/// -/// Use -[NSScreen backingScaleFactor] to find out if the user -/// has a retina display or not. -/// -/// \param in SFML coordinates to be converted -/// \param delegate a object implementing WindowImplDelegateProtocol, or nil for default scale -/// -//////////////////////////////////////////////////////////// -template <class T> -void scaleIn(T& in, id<WindowImplDelegateProtocol> delegate) -{ - in /= delegate ? [delegate displayScaleFactor] : getDefaultScaleFactor(); -} - -template <class T> -void scaleInWidthHeight(T& in, id<WindowImplDelegateProtocol> delegate) -{ - scaleIn(in.width, delegate); - scaleIn(in.height, delegate); -} - -template <class T> -void scaleInXY(T& in, id<WindowImplDelegateProtocol> delegate) -{ - scaleIn(in.x, delegate); - scaleIn(in.y, delegate); -} - -//////////////////////////////////////////////////////////// -/// \brief Scale backing coordinates to SFML coordinates -/// -/// Use -[NSScreen backingScaleFactor] to find out if the user -/// has a retina display or not. -/// -/// \param out backing coordinates to be converted -/// \param delegate a object implementing WindowImplDelegateProtocol, or nil for default scale -/// -//////////////////////////////////////////////////////////// -template <class T> -void scaleOut(T& out, id<WindowImplDelegateProtocol> delegate) -{ - out *= delegate ? [delegate displayScaleFactor] : getDefaultScaleFactor(); -} - -template <class T> -void scaleOutWidthHeight(T& out, id<WindowImplDelegateProtocol> delegate) -{ - scaleOut(out.width, delegate); - scaleOut(out.height, delegate); -} - -template <class T> -void scaleOutXY(T& out, id<WindowImplDelegateProtocol> delegate) -{ - scaleOut(out.x, delegate); - scaleOut(out.y, delegate); -} - - -//////////////////////////////////////////////////////////// /// According to Apple's documentation, each invocation of /// unhide must be balanced by an invocation of hide in /// order for the cursor display to be correct. @@ -155,7 +85,7 @@ WindowImplCocoa::WindowImplCocoa(WindowHandle handle) : m_showCursor(true) { // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Treat the handle as it real type id nsHandle = (id)handle; @@ -200,7 +130,7 @@ m_showCursor(true) setUpProcess(); // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Use backing size scaleInWidthHeight(mode, nil); @@ -226,11 +156,9 @@ WindowImplCocoa::~WindowImplCocoa() if ([windows count] > 0) [[windows objectAtIndex:0] makeKeyAndOrderFront:nil]; - drainCurrentPool(); // Make sure everything was freed + drainThreadPool(); // Make sure everything was freed // This solve some issue when sf::Window::Create is called for the // second time (nothing was render until the function was called again) - - releasePool(); } @@ -467,7 +395,7 @@ void WindowImplCocoa::textEntered(unichar charcode) void WindowImplCocoa::processEvents() { [m_delegate processEvent]; - drainCurrentPool(); // Reduce memory footprint + drainThreadPool(); // Reduce memory footprint } #pragma mark @@ -559,6 +487,13 @@ void WindowImplCocoa::setMouseCursorVisible(bool visible) //////////////////////////////////////////////////////////// +void WindowImplCocoa::setMouseCursorGrabbed(bool grabbed) +{ + [m_delegate setCursorGrabbed:grabbed]; +} + + +//////////////////////////////////////////////////////////// void WindowImplCocoa::setKeyRepeatEnabled(bool enabled) { if (enabled) @@ -585,3 +520,4 @@ bool WindowImplCocoa::hasFocus() const } // namespace priv } // namespace sf + diff --git a/src/SFML/Window/OSX/WindowImplDelegateProtocol.h b/src/SFML/Window/OSX/WindowImplDelegateProtocol.h index 0c4595c..4e0c327 100644 --- a/src/SFML/Window/OSX/WindowImplDelegateProtocol.h +++ b/src/SFML/Window/OSX/WindowImplDelegateProtocol.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -97,6 +97,14 @@ namespace sf { -(BOOL)isMouseInside; //////////////////////////////////////////////////////////// +/// \brief Grab or release the mouse cursor +/// +/// \param grabbed YES to grab, NO to release +/// +//////////////////////////////////////////////////////////// +-(void)setCursorGrabbed:(BOOL)grabbed; + +//////////////////////////////////////////////////////////// /// \brief Get window position /// /// \return Top left corner of the window or view diff --git a/src/SFML/Window/OSX/cg_sf_conversion.hpp b/src/SFML/Window/OSX/cg_sf_conversion.hpp index c0083f8..8b3845e 100644 --- a/src/SFML/Window/OSX/cg_sf_conversion.hpp +++ b/src/SFML/Window/OSX/cg_sf_conversion.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/cg_sf_conversion.cpp b/src/SFML/Window/OSX/cg_sf_conversion.mm index 60318cd..32495c3 100644 --- a/src/SFML/Window/OSX/cg_sf_conversion.cpp +++ b/src/SFML/Window/OSX/cg_sf_conversion.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. @@ -29,6 +29,8 @@ #include <SFML/Window/OSX/cg_sf_conversion.hpp> #include <SFML/System/Err.hpp> +#import <SFML/Window/OSX/Scaling.h> + namespace sf { namespace priv @@ -74,51 +76,22 @@ size_t displayBitsPerPixel(CGDirectDisplayID displayId) //////////////////////////////////////////////////////////// VideoMode convertCGModeToSFMode(CGDisplayModeRef cgmode) { - return VideoMode(CGDisplayModeGetWidth(cgmode), - CGDisplayModeGetHeight(cgmode), - modeBitsPerPixel(cgmode)); -} - - -//////////////////////////////////////////////////////////// -CGDisplayModeRef convertSFModeToCGMode(VideoMode sfmode) -{ - // Starting with 10.6 we should query the display all the modes and - // search for the best one. - - // Will return NULL if sfmode is not in VideoMode::GetFullscreenModes. - CGDisplayModeRef cgbestMode = NULL; - - // Retrieve all modes available for main screen only. - CFArrayRef cgmodes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL); - - if (cgmodes == NULL) // Should not happen but anyway... - { - sf::err() << "Couldn't get VideoMode for main display."; - return NULL; - } - - // Loop on each mode and convert it into a sf::VideoMode object. - const CFIndex modesCount = CFArrayGetCount(cgmodes); - for (CFIndex i = 0; i < modesCount; i++) - { - CGDisplayModeRef cgmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(cgmodes, i); - - VideoMode mode = convertCGModeToSFMode(cgmode); - - if (mode == sfmode) - cgbestMode = cgmode; - } - - // Clean up memory. - CFRelease(cgmodes); - - if (cgbestMode == NULL) - sf::err() << "Couldn't convert the given sf:VideoMode into a CGDisplayMode." - << std::endl; - - return cgbestMode; + // The main documentation says the sizes returned by + // CGDisplayModeGetWidth and CGDisplayModeGetHeight + // are expressed in pixels. However, some additional + // documentation [1] states they actually return + // values in points starting with 10.8. + // + // We therefore needs to use the scaling factor to + // convert the dimensions properly. + // + // [1]: "APIs for Supporting High Resolution" > "Additions and Changes for OS X v10.8" + // https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/APIs/APIs.html#//apple_ref/doc/uid/TP40012302-CH5-SW27 + VideoMode mode(CGDisplayModeGetWidth(cgmode), CGDisplayModeGetHeight(cgmode), modeBitsPerPixel(cgmode)); + scaleOutWidthHeight(mode, nil); + return mode; } } // namespace priv } // namespace sf + diff --git a/src/SFML/Window/OSX/cpp_objc_conversion.h b/src/SFML/Window/OSX/cpp_objc_conversion.h index 42f1557..9683a6e 100644 --- a/src/SFML/Window/OSX/cpp_objc_conversion.h +++ b/src/SFML/Window/OSX/cpp_objc_conversion.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/OSX/cpp_objc_conversion.mm b/src/SFML/Window/OSX/cpp_objc_conversion.mm index ea7c84b..539a41e 100644 --- a/src/SFML/Window/OSX/cpp_objc_conversion.mm +++ b/src/SFML/Window/OSX/cpp_objc_conversion.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Marco Antognini (antognini.marco@gmail.com), +// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com), // Laurent Gomila (laurent@sfml-dev.org) // // This software is provided 'as-is', without any express or implied warranty. diff --git a/src/SFML/Window/Sensor.cpp b/src/SFML/Window/Sensor.cpp index 64b9fff..a2ddb2b 100644 --- a/src/SFML/Window/Sensor.cpp +++ b/src/SFML/Window/Sensor.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/SensorImpl.hpp b/src/SFML/Window/SensorImpl.hpp index 39ca794..25b44d2 100644 --- a/src/SFML/Window/SensorImpl.hpp +++ b/src/SFML/Window/SensorImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/SensorManager.cpp b/src/SFML/Window/SensorManager.cpp index dd3e7a0..319767d 100644 --- a/src/SFML/Window/SensorManager.cpp +++ b/src/SFML/Window/SensorManager.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/SensorManager.hpp b/src/SFML/Window/SensorManager.hpp index 2d9f9c1..a0faa87 100644 --- a/src/SFML/Window/SensorManager.hpp +++ b/src/SFML/Window/SensorManager.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Touch.cpp b/src/SFML/Window/Touch.cpp index 4ff400e..b2d9615 100644 --- a/src/SFML/Window/Touch.cpp +++ b/src/SFML/Window/Touch.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp index c57ae0f..a078b97 100644 --- a/src/SFML/Window/Unix/Display.cpp +++ b/src/SFML/Window/Unix/Display.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp index 2b33c96..2743678 100644 --- a/src/SFML/Window/Unix/Display.hpp +++ b/src/SFML/Window/Unix/Display.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index c89c9d3..7251db2 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -31,6 +31,7 @@ #include <SFML/System/Mutex.hpp> #include <SFML/System/Lock.hpp> #include <SFML/System/Err.hpp> +#include <vector> #if !defined(GLX_DEBUGGING) && defined(SFML_DEBUG) // Enable this to print messages to err() everytime GLX produces errors @@ -53,8 +54,8 @@ namespace public: GlxErrorHandler(::Display* display) : - m_display(display), - m_lock (glxErrorMutex) + m_lock (glxErrorMutex), + m_display(display) { glxErrorOccurred = false; m_previousHandler = XSetErrorHandler(HandleXError); @@ -95,101 +96,73 @@ void ensureExtensionsInit(::Display* display, int screen) //////////////////////////////////////////////////////////// GlxContext::GlxContext(GlxContext* shared) : +m_display (NULL), m_window (0), m_context (NULL), -m_ownsWindow(true) +m_pbuffer (0), +m_ownsWindow(false) { - // Open a connection with the X server - m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); - xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display)); + // Save the creation settings + m_settings = ContextSettings(); - // Choose the visual according to the context settings - XVisualInfo visualInfo = selectBestVisual(m_display, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings()); + // Make sure that extensions are initialized if this is not the shared context + // The shared context is the context used to initialize the extensions + if (shared && shared->m_display) + ensureExtensionsInit(shared->m_display, DefaultScreen(shared->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<uint8_t>(visualInfo.depth), - m_window, - screen->root, - 0, 0, - 1, 1, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - visualInfo.visualid, - XCB_CW_COLORMAP, - value_list - ); + // Create the rendering surface (window or pbuffer if supported) + createSurface(shared, 1, 1, VideoMode::getDesktopMode().bitsPerPixel); // Create the context - createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings()); + createContext(shared); } //////////////////////////////////////////////////////////// GlxContext::GlxContext(GlxContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) : +m_display (NULL), m_window (0), m_context (NULL), +m_pbuffer (0), m_ownsWindow(false) { - // Open a connection with the X server - // (important: must be the same display as the owner window) - m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); + // Save the creation settings + m_settings = settings; - // Get the owner window and its device context - m_window = static_cast< ::Window>(owner->getSystemHandle()); + // Make sure that extensions are initialized if this is not the shared context + // The shared context is the context used to initialize the extensions + if (shared && shared->m_display) + ensureExtensionsInit(shared->m_display, DefaultScreen(shared->m_display)); + + // Create the rendering surface from the owner window + createSurface(static_cast< ::Window>(owner->getSystemHandle())); // Create the context - if (m_window) - createContext(shared, bitsPerPixel, settings); + createContext(shared); } //////////////////////////////////////////////////////////// GlxContext::GlxContext(GlxContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) : +m_display (NULL), m_window (0), m_context (NULL), -m_ownsWindow(true) +m_pbuffer (0), +m_ownsWindow(false) { - // Open a connection with the X server - m_display = OpenDisplay(); - m_connection = XGetXCBConnection(m_display); - xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display)); + // Save the creation settings + m_settings = settings; - // Choose the visual according to the context settings - XVisualInfo visualInfo = selectBestVisual(m_display, VideoMode::getDesktopMode().bitsPerPixel, settings); + // Make sure that extensions are initialized if this is not the shared context + // The shared context is the context used to initialize the extensions + if (shared && shared->m_display) + ensureExtensionsInit(shared->m_display, DefaultScreen(shared->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 the hidden window - m_window = xcb_generate_id(m_connection); - xcb_create_window( - m_connection, - static_cast<uint8_t>(visualInfo.depth), - m_window, - screen->root, - 0, 0, - width, height, - 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - visualInfo.visualid, - XCB_CW_COLORMAP, - value_list - ); + // Create the rendering surface (window or pbuffer if supported) + createSurface(shared, width, height, VideoMode::getDesktopMode().bitsPerPixel); // Create the context - createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings); + createContext(shared); } @@ -213,6 +186,11 @@ GlxContext::~GlxContext() #endif } + if (m_pbuffer) + { + glXDestroyPbuffer(m_display, m_pbuffer); + } + // Destroy the window if we own it if (m_window && m_ownsWindow) { @@ -242,7 +220,16 @@ bool GlxContext::makeCurrent() GlxErrorHandler handler(m_display); #endif - bool result = glXMakeCurrent(m_display, m_window, m_context); + bool result = false; + + 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); + } #if defined(GLX_DEBUGGING) if (glxErrorOccurred) @@ -260,7 +247,9 @@ void GlxContext::display() GlxErrorHandler handler(m_display); #endif - if (m_window) + if (m_pbuffer) + glXSwapBuffers(m_display, m_pbuffer); + else if (m_window) glXSwapBuffers(m_display, m_window); #if defined(GLX_DEBUGGING) @@ -284,7 +273,7 @@ void GlxContext::setVerticalSyncEnabled(bool enabled) // which would require us to link in an additional library if (sfglx_ext_EXT_swap_control == sfglx_LOAD_SUCCEEDED) { - glXSwapIntervalEXT(m_display, glXGetCurrentDrawable(), enabled ? 1 : 0); + glXSwapIntervalEXT(m_display, m_pbuffer ? m_pbuffer : m_window, enabled ? 1 : 0); } else if (sfglx_ext_MESA_swap_control == sfglx_LOAD_SUCCEEDED) { @@ -321,7 +310,7 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe { // Evaluate all the returned visuals, and pick the best one int bestScore = 0x7FFFFFFF; - XVisualInfo bestVisual; + XVisualInfo bestVisual = XVisualInfo(); for (int i = 0; i < count; ++i) { // Check mandatory attributes @@ -331,7 +320,7 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe continue; // Extract the components of the current visual - int red, green, blue, alpha, depth, stencil, multiSampling, samples; + int red, green, blue, alpha, depth, stencil, multiSampling, samples, sRgb; glXGetConfig(display, &visuals[i], GLX_RED_SIZE, &red); glXGetConfig(display, &visuals[i], GLX_GREEN_SIZE, &green); glXGetConfig(display, &visuals[i], GLX_BLUE_SIZE, &blue); @@ -350,12 +339,21 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe samples = 0; } + if ((sfglx_ext_EXT_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED) || (sfglx_ext_ARB_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED)) + { + glXGetConfig(display, &visuals[i], GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &sRgb); + } + else + { + sRgb = 0; + } + // TODO: Replace this with proper acceleration detection bool accelerated = true; // Evaluate the visual int color = red + green + blue + alpha; - int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0, accelerated); + int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0, accelerated, sRgb == True); // If it's better than the current best, make it the new best if (score < bestScore) @@ -379,12 +377,45 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe } } + //////////////////////////////////////////////////////////// -void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) +void GlxContext::updateSettingsFromVisualInfo(XVisualInfo* visualInfo) { - // Save the creation settings - m_settings = settings; + // Update the creation settings from the chosen format + int depth, stencil, multiSampling, samples, sRgb; + glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth); + glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil); + + if (sfglx_ext_ARB_multisample == sfglx_LOAD_SUCCEEDED) + { + glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); + glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples); + } + else + { + multiSampling = 0; + samples = 0; + } + if ((sfglx_ext_EXT_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED) || (sfglx_ext_ARB_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED)) + { + glXGetConfig(m_display, visualInfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &sRgb); + } + else + { + sRgb = 0; + } + + m_settings.depthBits = static_cast<unsigned int>(depth); + m_settings.stencilBits = static_cast<unsigned int>(stencil); + m_settings.antialiasingLevel = multiSampling ? samples : 0; + m_settings.sRgbCapable = (sRgb == True); +} + + +//////////////////////////////////////////////////////////// +void GlxContext::updateSettingsFromWindow() +{ // Retrieve the attributes of the target window XWindowAttributes windowAttributes; if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0) @@ -400,6 +431,180 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co int nbVisuals = 0; XVisualInfo* visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); + if (!visualInfo) + return; + + updateSettingsFromVisualInfo(visualInfo); + + XFree(visualInfo); +} + + +//////////////////////////////////////////////////////////// +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); + + // Check if the shared context already exists and pbuffers are supported + if (shared && (sfglx_ext_SGIX_pbuffer == sfglx_LOAD_SUCCEEDED)) + { + // There are no GLX versions prior to 1.0 + int major = 0; + int minor = 0; + + glXQueryVersion(m_display, &major, &minor); + + // Check if glXCreatePbuffer is available (requires GLX 1.3 or greater) + bool hasCreatePbuffer = ((major > 1) || (minor >= 3)); + + if (hasCreatePbuffer) + { + // Get a GLXFBConfig that matches the visual + GLXFBConfig* config = NULL; + + // We don't supply attributes to match against, since + // the visual we are matching against was already + // deemed suitable in selectBestVisual() + int nbConfigs = 0; + GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), NULL, &nbConfigs); + + for (int i = 0; configs && (i < nbConfigs); ++i) + { + XVisualInfo* visual = glXGetVisualFromFBConfig(m_display, configs[i]); + + if (!visual) + continue; + + if (visual->visualid == visualInfo.visualid) + { + config = &configs[i]; + break; + } + } + + if (config) + { + int attributes[] = + { + GLX_PBUFFER_WIDTH, static_cast<int>(width), + GLX_PBUFFER_HEIGHT, static_cast<int>(height), + 0, 0 + }; + + m_pbuffer = glXCreatePbuffer(m_display, *config, attributes); + + updateSettingsFromVisualInfo(&visualInfo); + + XFree(configs); + + return; + } + + if (configs) + XFree(configs); + } + } + + // 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)); + + // 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<uint8_t>(visualInfo.depth), + m_window, + screen->root, + 0, 0, + width, height, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + visualInfo.visualid, + XCB_CW_COLORMAP, + value_list + ); + + m_ownsWindow = true; + + updateSettingsFromWindow(); +} + + +//////////////////////////////////////////////////////////// +void GlxContext::createSurface(::Window window) +{ + m_display = OpenDisplay(); + m_connection = XGetXCBConnection(m_display); + + // A window already exists, so just use it + m_window = window; + + updateSettingsFromWindow(); +} + + +//////////////////////////////////////////////////////////// +void GlxContext::createContext(GlxContext* shared) +{ + // Get a working copy of the context settings + ContextSettings settings = m_settings; + + XVisualInfo* visualInfo = NULL; + + if (m_pbuffer) + { + unsigned int fbConfigId = 0; + + glXQueryDrawable(m_display, m_pbuffer, GLX_FBCONFIG_ID, &fbConfigId); + + int attributes[] = + { + GLX_FBCONFIG_ID, static_cast<int>(fbConfigId), + 0, 0 + }; + + int count = 0; + GLXFBConfig* fbconfig = glXChooseFBConfig(m_display, DefaultScreen(m_display), attributes, &count); + + if (count == 1) + visualInfo = glXGetVisualFromFBConfig(m_display, *fbconfig); + + if (fbconfig) + XFree(fbconfig); + } + else + { + // Retrieve the attributes of the target window + XWindowAttributes windowAttributes; + if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0) + { + err() << "Failed to get the window attributes" << std::endl; + return; + } + + // Get its visuals + XVisualInfo tpl; + tpl.screen = DefaultScreen(m_display); + tpl.visualid = XVisualIDFromVisual(windowAttributes.visual); + int nbVisuals = 0; + visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); + } + + if (!visualInfo) + { + err() << "Failed to get visual info" << std::endl; + return; + } + // Get the context to share display lists with GLXContext toShare = shared ? shared->m_context : NULL; @@ -410,26 +615,13 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co if (!glXQueryVersion(m_display, &major, &minor)) err() << "Failed to query GLX version, limited to legacy context creation" << std::endl; - // Make sure that extensions are initialized if this is not the shared context - // The shared context is the context used to initialize the extensions - if (shared) - ensureExtensionsInit(m_display, DefaultScreen(m_display)); - // Check if glXCreateContextAttribsARB is available (requires GLX 1.3 or greater) bool hasCreateContextArb = (sfglx_ext_ARB_create_context == sfglx_LOAD_SUCCEEDED) && ((major > 1) || (minor >= 3)); - // Check if we need to use glXCreateContextAttribsARB - bool needCreateContextArb = false; - - if (m_settings.attributeFlags) - needCreateContextArb = true; - else if (m_settings.majorVersion >= 3) - needCreateContextArb = true; - - // Create the OpenGL context -- first try using glXCreateContextAttribsARB if we need to - if (hasCreateContextArb && needCreateContextArb) + // Create the OpenGL context -- first try using glXCreateContextAttribsARB + if (hasCreateContextArb) { - // Get a GLXFBConfig that matches the the window's visual, for glXCreateContextAttribsARB + // Get a GLXFBConfig that matches the window's visual, for glXCreateContextAttribsARB GLXFBConfig* config = NULL; // We don't supply attributes to match against, since @@ -457,27 +649,27 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co while (config && !m_context && m_settings.majorVersion) { + std::vector<int> attributes; + + // Check if the user requested a specific context version (anything > 1.1) + if ((m_settings.majorVersion > 1) || ((m_settings.majorVersion == 1) && (m_settings.minorVersion > 1))) + { + attributes.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB); + attributes.push_back(m_settings.majorVersion); + attributes.push_back(GLX_CONTEXT_MINOR_VERSION_ARB); + attributes.push_back(m_settings.minorVersion); + } + // Check if setting the profile is supported if (sfglx_ext_ARB_create_context_profile == sfglx_LOAD_SUCCEEDED) { int profile = (m_settings.attributeFlags & ContextSettings::Core) ? GLX_CONTEXT_CORE_PROFILE_BIT_ARB : GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; int debug = (m_settings.attributeFlags & ContextSettings::Debug) ? GLX_CONTEXT_DEBUG_BIT_ARB : 0; - // Create the context - int attributes[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(m_settings.majorVersion), - GLX_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(m_settings.minorVersion), - GLX_CONTEXT_PROFILE_MASK_ARB, profile, - GLX_CONTEXT_FLAGS_ARB, debug, - 0, 0 - }; - - // RAII GLX error handler (we simply ignore errors here) - // On an error, glXCreateContextAttribsARB will return 0 anyway - GlxErrorHandler handler(m_display); - - m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, attributes); + attributes.push_back(GLX_CONTEXT_PROFILE_MASK_ARB); + attributes.push_back(profile); + attributes.push_back(GLX_CONTEXT_FLAGS_ARB); + attributes.push_back(debug); } else { @@ -486,21 +678,18 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co << "disabling comptibility and debug" << std::endl; m_settings.attributeFlags = ContextSettings::Default; + } - // Create the context - int attributes[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(m_settings.majorVersion), - GLX_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(m_settings.minorVersion), - 0, 0 - }; + // Append the terminating 0 + attributes.push_back(0); + attributes.push_back(0); - // RAII GLX error handler (we simply ignore errors here) - // On an error, glXCreateContextAttribsARB will return 0 anyway - GlxErrorHandler handler(m_display); + // RAII GLX error handler (we simply ignore errors here) + // On an error, glXCreateContextAttribsARB will return 0 anyway + GlxErrorHandler handler(m_display); - m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, attributes); - } + // Create the context + m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, &attributes[0]); if (!m_context) { @@ -555,31 +744,7 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co } if (!m_context) - { err() << "Failed to create an OpenGL context for this window" << std::endl; - } - else - { - // Update the creation settings from the chosen format - int depth, stencil, multiSampling, samples; - glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth); - glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil); - - if (sfglx_ext_ARB_multisample == sfglx_LOAD_SUCCEEDED) - { - glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); - glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples); - } - else - { - multiSampling = 0; - samples = 0; - } - - m_settings.depthBits = static_cast<unsigned int>(depth); - m_settings.stencilBits = static_cast<unsigned int>(stencil); - m_settings.antialiasingLevel = multiSampling ? samples : 0; - } // Free the visual info XFree(visualInfo); diff --git a/src/SFML/Window/Unix/GlxContext.hpp b/src/SFML/Window/Unix/GlxContext.hpp index e1ad899..4a9444f 100644 --- a/src/SFML/Window/Unix/GlxContext.hpp +++ b/src/SFML/Window/Unix/GlxContext.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -133,14 +133,45 @@ public: private: //////////////////////////////////////////////////////////// - /// \brief Create the context + /// \brief Update the context visual settings from XVisualInfo + /// + /// \param visualInfo XVisualInfo to update settings from + /// + //////////////////////////////////////////////////////////// + void updateSettingsFromVisualInfo(XVisualInfo* visualInfo); + + //////////////////////////////////////////////////////////// + /// \brief Update the context visual settings from the window + /// + //////////////////////////////////////////////////////////// + void updateSettingsFromWindow(); + + //////////////////////////////////////////////////////////// + /// \brief Create the context's drawing surface /// /// \param shared Context to share the new one with (can be NULL) + /// \param width Back buffer width, in pixels + /// \param height Back buffer height, in pixels /// \param bitsPerPixel Pixel depth, in bits per pixel - /// \param settings Creation parameters /// //////////////////////////////////////////////////////////// - void createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings); + void createSurface(GlxContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel); + + //////////////////////////////////////////////////////////// + /// \brief Create the context's drawing surface from an existing window + /// + /// \param window Window ID of the owning window + /// + //////////////////////////////////////////////////////////// + void createSurface(::Window window); + + //////////////////////////////////////////////////////////// + /// \brief Create the context + /// + /// \param shared Context to share the new one with (can be NULL) + /// + //////////////////////////////////////////////////////////// + void createContext(GlxContext* shared); //////////////////////////////////////////////////////////// // Member data @@ -149,6 +180,7 @@ private: ::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/GlxExtensions.cpp b/src/SFML/Window/Unix/GlxExtensions.cpp index 029095c..e418e2e 100644 --- a/src/SFML/Window/Unix/GlxExtensions.cpp +++ b/src/SFML/Window/Unix/GlxExtensions.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -30,6 +30,7 @@ #include <cstdlib> #include <cstring> #include <cstddef> +#include <string> static sf::GlFunctionPointer IntGetProcAddress(const char* name) { @@ -39,17 +40,21 @@ static sf::GlFunctionPointer IntGetProcAddress(const char* name) int sfglx_ext_EXT_swap_control = sfglx_LOAD_FAILED; int sfglx_ext_MESA_swap_control = sfglx_LOAD_FAILED; int sfglx_ext_SGI_swap_control = sfglx_LOAD_FAILED; +int sfglx_ext_EXT_framebuffer_sRGB = sfglx_LOAD_FAILED; +int sfglx_ext_ARB_framebuffer_sRGB = sfglx_LOAD_FAILED; int sfglx_ext_ARB_multisample = sfglx_LOAD_FAILED; +int sfglx_ext_SGIX_pbuffer = sfglx_LOAD_FAILED; int sfglx_ext_ARB_create_context = sfglx_LOAD_FAILED; int sfglx_ext_ARB_create_context_profile = sfglx_LOAD_FAILED; -void (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalEXT)(Display *, GLXDrawable, int) = NULL; +void (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalEXT)(Display*, GLXDrawable, int) = NULL; static int Load_EXT_swap_control(void) { int numFailed = 0; - sf_ptrc_glXSwapIntervalEXT = (void (CODEGEN_FUNCPTR *)(Display *, GLXDrawable, int))IntGetProcAddress("glXSwapIntervalEXT"); - if(!sf_ptrc_glXSwapIntervalEXT) numFailed++; + sf_ptrc_glXSwapIntervalEXT = reinterpret_cast<void (CODEGEN_FUNCPTR*)(Display*, GLXDrawable, int)>(IntGetProcAddress("glXSwapIntervalEXT")); + if (!sf_ptrc_glXSwapIntervalEXT) + numFailed++; return numFailed; } @@ -58,8 +63,9 @@ int (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalMESA)(int) = NULL; static int Load_MESA_swap_control(void) { int numFailed = 0; - sf_ptrc_glXSwapIntervalMESA = (int (CODEGEN_FUNCPTR *)(int))IntGetProcAddress("glXSwapIntervalMESA"); - if(!sf_ptrc_glXSwapIntervalMESA) numFailed++; + sf_ptrc_glXSwapIntervalMESA = reinterpret_cast<int (CODEGEN_FUNCPTR*)(int)>(IntGetProcAddress("glXSwapIntervalMESA")); + if (!sf_ptrc_glXSwapIntervalMESA) + numFailed++; return numFailed; } @@ -68,74 +74,110 @@ int (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalSGI)(int) = NULL; static int Load_SGI_swap_control(void) { int numFailed = 0; - sf_ptrc_glXSwapIntervalSGI = (int (CODEGEN_FUNCPTR *)(int))IntGetProcAddress("glXSwapIntervalSGI"); - if(!sf_ptrc_glXSwapIntervalSGI) numFailed++; + sf_ptrc_glXSwapIntervalSGI = reinterpret_cast<int (CODEGEN_FUNCPTR *)(int)>(IntGetProcAddress("glXSwapIntervalSGI")); + if (!sf_ptrc_glXSwapIntervalSGI) + numFailed++; return numFailed; } -GLXContext (CODEGEN_FUNCPTR *sf_ptrc_glXCreateContextAttribsARB)(Display *, GLXFBConfig, GLXContext, Bool, const int *) = NULL; +GLXPbufferSGIX (CODEGEN_FUNCPTR *sf_ptrc_glXCreateGLXPbufferSGIX)(Display*, GLXFBConfigSGIX, unsigned int, unsigned int, int*) = NULL; +void (CODEGEN_FUNCPTR *sf_ptrc_glXDestroyGLXPbufferSGIX)(Display*, GLXPbufferSGIX) = NULL; +void (CODEGEN_FUNCPTR *sf_ptrc_glXGetSelectedEventSGIX)(Display*, GLXDrawable, unsigned long*) = NULL; +int (CODEGEN_FUNCPTR *sf_ptrc_glXQueryGLXPbufferSGIX)(Display*, GLXPbufferSGIX, int, unsigned int*) = NULL; +void (CODEGEN_FUNCPTR *sf_ptrc_glXSelectEventSGIX)(Display*, GLXDrawable, unsigned long) = NULL; + +static int Load_SGIX_pbuffer(void) +{ + int numFailed = 0; + sf_ptrc_glXCreateGLXPbufferSGIX = reinterpret_cast<GLXPbufferSGIX (CODEGEN_FUNCPTR*)(Display*, GLXFBConfigSGIX, unsigned int, unsigned int, int*)>(IntGetProcAddress("glXCreateGLXPbufferSGIX")); + if (!sf_ptrc_glXCreateGLXPbufferSGIX) + numFailed++; + sf_ptrc_glXDestroyGLXPbufferSGIX = reinterpret_cast<void (CODEGEN_FUNCPTR*)(Display*, GLXPbufferSGIX)>(IntGetProcAddress("glXDestroyGLXPbufferSGIX")); + if (!sf_ptrc_glXDestroyGLXPbufferSGIX) + numFailed++; + sf_ptrc_glXGetSelectedEventSGIX = reinterpret_cast<void (CODEGEN_FUNCPTR*)(Display*, GLXDrawable, unsigned long*)>(IntGetProcAddress("glXGetSelectedEventSGIX")); + if (!sf_ptrc_glXGetSelectedEventSGIX) + numFailed++; + sf_ptrc_glXQueryGLXPbufferSGIX = reinterpret_cast<int (CODEGEN_FUNCPTR*)(Display*, GLXPbufferSGIX, int, unsigned int*)>(IntGetProcAddress("glXQueryGLXPbufferSGIX")); + if (!sf_ptrc_glXQueryGLXPbufferSGIX) + numFailed++; + sf_ptrc_glXSelectEventSGIX = reinterpret_cast<void (CODEGEN_FUNCPTR*)(Display*, GLXDrawable, unsigned long)>(IntGetProcAddress("glXSelectEventSGIX")); + if (!sf_ptrc_glXSelectEventSGIX) + numFailed++; + return numFailed; +} + +GLXContext (CODEGEN_FUNCPTR *sf_ptrc_glXCreateContextAttribsARB)(Display*, GLXFBConfig, GLXContext, Bool, const int*) = NULL; static int Load_ARB_create_context(void) { int numFailed = 0; - sf_ptrc_glXCreateContextAttribsARB = (GLXContext (CODEGEN_FUNCPTR *)(Display *, GLXFBConfig, GLXContext, Bool, const int *))IntGetProcAddress("glXCreateContextAttribsARB"); - if(!sf_ptrc_glXCreateContextAttribsARB) numFailed++; + sf_ptrc_glXCreateContextAttribsARB = reinterpret_cast<GLXContext (CODEGEN_FUNCPTR*)(Display*, GLXFBConfig, GLXContext, Bool, const int*)>(IntGetProcAddress("glXCreateContextAttribsARB")); + if (!sf_ptrc_glXCreateContextAttribsARB) + numFailed++; return numFailed; } typedef int (*PFN_LOADFUNCPOINTERS)(void); typedef struct sfglx_StrToExtMap_s { - const char *extensionName; - int *extensionVariable; + const char* extensionName; + int* extensionVariable; PFN_LOADFUNCPOINTERS LoadExtension; } sfglx_StrToExtMap; -static sfglx_StrToExtMap ExtensionMap[6] = { +static sfglx_StrToExtMap ExtensionMap[9] = { {"GLX_EXT_swap_control", &sfglx_ext_EXT_swap_control, Load_EXT_swap_control}, {"GLX_MESA_swap_control", &sfglx_ext_MESA_swap_control, Load_MESA_swap_control}, {"GLX_SGI_swap_control", &sfglx_ext_SGI_swap_control, Load_SGI_swap_control}, + {"GLX_EXT_framebuffer_sRGB", &sfglx_ext_EXT_framebuffer_sRGB, NULL}, + {"GLX_ARB_framebuffer_sRGB", &sfglx_ext_ARB_framebuffer_sRGB, NULL}, {"GLX_ARB_multisample", &sfglx_ext_ARB_multisample, NULL}, + {"GLX_SGIX_pbuffer", &sfglx_ext_SGIX_pbuffer, Load_SGIX_pbuffer}, {"GLX_ARB_create_context", &sfglx_ext_ARB_create_context, Load_ARB_create_context}, - {"GLX_ARB_create_context_profile", &sfglx_ext_ARB_create_context_profile, NULL}, + {"GLX_ARB_create_context_profile", &sfglx_ext_ARB_create_context_profile, NULL} }; -static int g_extensionMapSize = 6; +static int g_extensionMapSize = 9; + -static sfglx_StrToExtMap *FindExtEntry(const char *extensionName) +static sfglx_StrToExtMap* FindExtEntry(const char* extensionName) { - int loop; - sfglx_StrToExtMap *currLoc = ExtensionMap; - for(loop = 0; loop < g_extensionMapSize; ++loop, ++currLoc) + sfglx_StrToExtMap* currLoc = ExtensionMap; + for (int loop = 0; loop < g_extensionMapSize; ++loop, ++currLoc) { - if(strcmp(extensionName, currLoc->extensionName) == 0) + if (std::strcmp(extensionName, currLoc->extensionName) == 0) return currLoc; } return NULL; } + static void ClearExtensionVars(void) { sfglx_ext_EXT_swap_control = sfglx_LOAD_FAILED; sfglx_ext_MESA_swap_control = sfglx_LOAD_FAILED; sfglx_ext_SGI_swap_control = sfglx_LOAD_FAILED; + sfglx_ext_EXT_framebuffer_sRGB = sfglx_LOAD_FAILED; + sfglx_ext_ARB_framebuffer_sRGB = sfglx_LOAD_FAILED; sfglx_ext_ARB_multisample = sfglx_LOAD_FAILED; + sfglx_ext_SGIX_pbuffer = sfglx_LOAD_FAILED; sfglx_ext_ARB_create_context = sfglx_LOAD_FAILED; sfglx_ext_ARB_create_context_profile = sfglx_LOAD_FAILED; } -static void LoadExtByName(const char *extensionName) +static void LoadExtByName(const char* extensionName) { - sfglx_StrToExtMap *entry = NULL; + sfglx_StrToExtMap* entry = NULL; entry = FindExtEntry(extensionName); - if(entry) + if (entry) { - if(entry->LoadExtension) + if (entry->LoadExtension) { int numFailed = entry->LoadExtension(); - if(numFailed == 0) + if (numFailed == 0) { *(entry->extensionVariable) = sfglx_LOAD_SUCCEEDED; } @@ -152,46 +194,25 @@ static void LoadExtByName(const char *extensionName) } -static void ProcExtsFromExtString(const char *strExtList) +static void ProcExtsFromExtString(const char* strExtList) { - size_t iExtListLen = strlen(strExtList); - const char *strExtListEnd = strExtList + iExtListLen; - const char *strCurrPos = strExtList; - char strWorkBuff[256]; - - while(*strCurrPos) + do { - /*Get the extension at our position.*/ - int iStrLen = 0; - const char *strEndStr = strchr(strCurrPos, ' '); - int iStop = 0; - if(strEndStr == NULL) - { - strEndStr = strExtListEnd; - iStop = 1; - } - - iStrLen = (int)((ptrdiff_t)strEndStr - (ptrdiff_t)strCurrPos); - - if(iStrLen > 255) - return; + const char* begin = strExtList; - strncpy(strWorkBuff, strCurrPos, iStrLen); - strWorkBuff[iStrLen] = '\0'; + while ((*strExtList != ' ') && *strExtList) + strExtList++; - LoadExtByName(strWorkBuff); - - strCurrPos = strEndStr + 1; - if(iStop) break; - } + LoadExtByName(std::string(begin, strExtList).c_str()); + } while (*strExtList++); } -int sfglx_LoadFunctions(Display *display, int screen) + +int sfglx_LoadFunctions(Display* display, int screen) { ClearExtensionVars(); - ProcExtsFromExtString((const char *)glXQueryExtensionsString(display, screen)); + ProcExtsFromExtString(reinterpret_cast<const char*>(glXQueryExtensionsString(display, screen))); return sfglx_LOAD_SUCCEEDED; } - diff --git a/src/SFML/Window/Unix/GlxExtensions.hpp b/src/SFML/Window/Unix/GlxExtensions.hpp index 9e9a749..44c9165 100644 --- a/src/SFML/Window/Unix/GlxExtensions.hpp +++ b/src/SFML/Window/Unix/GlxExtensions.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -36,7 +36,7 @@ #include <GL/glx.h> #ifdef CODEGEN_FUNCPTR #undef CODEGEN_FUNCPTR -#endif /*CODEGEN_FUNCPTR*/ +#endif // CODEGEN_FUNCPTR #define CODEGEN_FUNCPTR #ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS @@ -58,21 +58,21 @@ typedef double GLdouble; typedef double GLclampd; #define GLvoid void -#endif /*GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS*/ +#endif // GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS #ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS #define GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS -#endif /*GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS*/ +#endif // GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS #ifndef GLEXT_64_TYPES_DEFINED -/* This code block is duplicated in glext.h, so must be protected */ +// This code block is duplicated in glext.h, so must be protected #define GLEXT_64_TYPES_DEFINED -/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ -/* (as used in the GLX_OML_sync_control extension). */ +// Define int32_t, int64_t, and uint64_t types for UST/MSC +// (as used in the GLX_OML_sync_control extension). #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #include <inttypes.h> #elif defined(__sun__) || defined(__digital__) @@ -84,8 +84,8 @@ typedef unsigned long int uint64_t; #else typedef long long int int64_t; typedef unsigned long long int uint64_t; -#endif /* __arch64__ */ -#endif /* __STDC__ */ +#endif // __arch64__ +#endif // __STDC__ #elif defined( __VMS ) || defined(__sgi) #include <inttypes.h> #elif defined(__SCO__) || defined(__USLC__) @@ -101,7 +101,7 @@ typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else -/* Fallback if nothing above works */ +// Fallback if nothing above works #include <inttypes.h> #endif #endif @@ -118,42 +118,75 @@ typedef unsigned __int64 uint64_t; typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; typedef XID GLXPbufferSGIX; typedef struct { - char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + char pipeName[80]; // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] int networkId; } GLXHyperpipeNetworkSGIX; typedef struct { - char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + char pipeName[80]; // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] int channel; unsigned int participationType; int timeSlice; } GLXHyperpipeConfigSGIX; typedef struct { - char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + char pipeName[80]; // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] int srcXOrigin, srcYOrigin, srcWidth, srcHeight; int destXOrigin, destYOrigin, destWidth, destHeight; } GLXPipeRect; typedef struct { - char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + char pipeName[80]; // Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] int XOrigin, YOrigin, maxHeight, maxWidth; } GLXPipeRectLimits; #ifdef __cplusplus extern "C" { -#endif /*__cplusplus*/ +#endif // __cplusplus extern int sfglx_ext_EXT_swap_control; extern int sfglx_ext_MESA_swap_control; extern int sfglx_ext_SGI_swap_control; +extern int sfglx_ext_EXT_framebuffer_sRGB; +extern int sfglx_ext_ARB_framebuffer_sRGB; extern int sfglx_ext_ARB_multisample; +extern int sfglx_ext_SGIX_pbuffer; extern int sfglx_ext_ARB_create_context; extern int sfglx_ext_ARB_create_context_profile; #define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 #define GLX_SWAP_INTERVAL_EXT 0x20F1 +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2 + +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 + #define GLX_SAMPLES_ARB 100001 #define GLX_SAMPLE_BUFFERS_ARB 100000 +#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080 +#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010 +#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004 +#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008 +#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000 +#define GLX_DAMAGED_SGIX 0x8020 +#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020 +#define GLX_EVENT_MASK_SGIX 0x801F +#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001 +#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002 +#define GLX_HEIGHT_SGIX 0x801E +#define GLX_LARGEST_PBUFFER_SGIX 0x801C +#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017 +#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018 +#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016 +#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A +#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019 +#define GLX_PBUFFER_BIT_SGIX 0x00000004 +#define GLX_PBUFFER_SGIX 0x8023 +#define GLX_PRESERVED_CONTENTS_SGIX 0x801B +#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100 +#define GLX_SAVED_SGIX 0x8021 +#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040 +#define GLX_WIDTH_SGIX 0x801D +#define GLX_WINDOW_SGIX 0x8022 + #define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define GLX_CONTEXT_FLAGS_ARB 0x2094 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 @@ -168,7 +201,7 @@ extern int sfglx_ext_ARB_create_context_profile; #define GLX_EXT_swap_control 1 extern void (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalEXT)(Display *, GLXDrawable, int); #define glXSwapIntervalEXT sf_ptrc_glXSwapIntervalEXT -#endif /*GLX_EXT_swap_control*/ +#endif // GLX_EXT_swap_control // Declare entry point even if GLX header already provides glXSwapIntervalMESA // We won't make use of an alias here @@ -178,13 +211,27 @@ extern int (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalMESA)(int); #define GLX_SGI_swap_control 1 extern int (CODEGEN_FUNCPTR *sf_ptrc_glXSwapIntervalSGI)(int); #define glXSwapIntervalSGI sf_ptrc_glXSwapIntervalSGI -#endif /*GLX_SGI_swap_control*/ +#endif // GLX_SGI_swap_control + +#ifndef GLX_SGIX_pbuffer +#define GLX_SGIX_pbuffer 1 +extern GLXPbufferSGIX (CODEGEN_FUNCPTR *sf_ptrc_glXCreateGLXPbufferSGIX)(Display*, GLXFBConfigSGIX, unsigned int, unsigned int, int*); +#define glXCreateGLXPbufferSGIX sf_ptrc_glXCreateGLXPbufferSGIX +extern void (CODEGEN_FUNCPTR *sf_ptrc_glXDestroyGLXPbufferSGIX)(Display*, GLXPbufferSGIX); +#define glXDestroyGLXPbufferSGIX sf_ptrc_glXDestroyGLXPbufferSGIX +extern void (CODEGEN_FUNCPTR *sf_ptrc_glXGetSelectedEventSGIX)(Display*, GLXDrawable, unsigned long*); +#define glXGetSelectedEventSGIX sf_ptrc_glXGetSelectedEventSGIX +extern int (CODEGEN_FUNCPTR *sf_ptrc_glXQueryGLXPbufferSGIX)(Display*, GLXPbufferSGIX, int, unsigned int*); +#define glXQueryGLXPbufferSGIX sf_ptrc_glXQueryGLXPbufferSGIX +extern void (CODEGEN_FUNCPTR *sf_ptrc_glXSelectEventSGIX)(Display*, GLXDrawable, unsigned long); +#define glXSelectEventSGIX sf_ptrc_glXSelectEventSGIX +#endif // GLX_SGIX_pbuffer #ifndef GLX_ARB_create_context #define GLX_ARB_create_context 1 -extern GLXContext (CODEGEN_FUNCPTR *sf_ptrc_glXCreateContextAttribsARB)(Display *, GLXFBConfig, GLXContext, Bool, const int *); +extern GLXContext (CODEGEN_FUNCPTR *sf_ptrc_glXCreateContextAttribsARB)(Display*, GLXFBConfig, GLXContext, Bool, const int*); #define glXCreateContextAttribsARB sf_ptrc_glXCreateContextAttribsARB -#endif /*GLX_ARB_create_context*/ +#endif // GLX_ARB_create_context enum sfglx_LoadStatus @@ -198,6 +245,6 @@ int sfglx_LoadFunctions(Display *display, int screen); #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif // __cplusplus -#endif /* SF_POINTER_C_GENERATED_HEADER_GLXWIN_HPP */ +#endif // SF_POINTER_C_GENERATED_HEADER_GLXWIN_HPP diff --git a/src/SFML/Window/Unix/GlxExtensions.txt b/src/SFML/Window/Unix/GlxExtensions.txt index b6b06fa..9c8a641 100644 --- a/src/SFML/Window/Unix/GlxExtensions.txt +++ b/src/SFML/Window/Unix/GlxExtensions.txt @@ -1,11 +1,14 @@ // Created with: -// https://bitbucket.org/Anteru/glloadgen-reloaded -// Commit 20f19482b7a844d20b9785c3e3fd1f16419f6e0a +// https://bitbucket.org/KhronosGroup/glloadgen +// Commit d143d66ac90d538ed06f806188714861b8e8e2f9 // lua LoadGen.lua -style=pointer_c -spec=glX -indent=space -prefix=sf -extfile=GlxExtensions.txt GlxExtensions EXT_swap_control // MESA_swap_control SGI_swap_control +EXT_framebuffer_sRGB +ARB_framebuffer_sRGB GLX_ARB_multisample +GLX_SGIX_pbuffer GLX_ARB_create_context -GLX_ARB_create_context_profile
\ No newline at end of file +GLX_ARB_create_context_profile diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp index 53d92be..ad62cd5 100644 --- a/src/SFML/Window/Unix/InputImpl.cpp +++ b/src/SFML/Window/Unix/InputImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/InputImpl.hpp b/src/SFML/Window/Unix/InputImpl.hpp index 9425c3d..f61647d 100644 --- a/src/SFML/Window/Unix/InputImpl.hpp +++ b/src/SFML/Window/Unix/InputImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/JoystickImpl.cpp b/src/SFML/Window/Unix/JoystickImpl.cpp index d60075d..903d588 100644 --- a/src/SFML/Window/Unix/JoystickImpl.cpp +++ b/src/SFML/Window/Unix/JoystickImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -440,6 +440,14 @@ namespace sf namespace priv { //////////////////////////////////////////////////////////// +JoystickImpl::JoystickImpl() : +m_file(-1) +{ + std::fill(m_mapping, m_mapping + ABS_MAX + 1, 0); +} + + +//////////////////////////////////////////////////////////// void JoystickImpl::initialize() { udevContext = udev_new(); @@ -650,19 +658,23 @@ JoystickState JoystickImpl::JoystickImpl::update() case JS_EVENT_AXIS: { float value = joyState.value * 100.f / 32767.f; - switch (m_mapping[joyState.number]) + + if (joyState.number < ABS_MAX + 1) { - case ABS_X: m_state.axes[Joystick::X] = value; break; - case ABS_Y: m_state.axes[Joystick::Y] = value; break; - case ABS_Z: - case ABS_THROTTLE: m_state.axes[Joystick::Z] = value; break; - case ABS_RZ: - case ABS_RUDDER: m_state.axes[Joystick::R] = value; break; - case ABS_RX: m_state.axes[Joystick::U] = value; break; - case ABS_RY: m_state.axes[Joystick::V] = value; break; - case ABS_HAT0X: m_state.axes[Joystick::PovX] = value; break; - case ABS_HAT0Y: m_state.axes[Joystick::PovY] = value; break; - default: break; + switch (m_mapping[joyState.number]) + { + case ABS_X: m_state.axes[Joystick::X] = value; break; + case ABS_Y: m_state.axes[Joystick::Y] = value; break; + case ABS_Z: + case ABS_THROTTLE: m_state.axes[Joystick::Z] = value; break; + case ABS_RZ: + case ABS_RUDDER: m_state.axes[Joystick::R] = value; break; + case ABS_RX: m_state.axes[Joystick::U] = value; break; + case ABS_RY: m_state.axes[Joystick::V] = value; break; + case ABS_HAT0X: m_state.axes[Joystick::PovX] = value; break; + case ABS_HAT0Y: m_state.axes[Joystick::PovY] = value; break; + default: break; + } } break; } diff --git a/src/SFML/Window/Unix/JoystickImpl.hpp b/src/SFML/Window/Unix/JoystickImpl.hpp index 34fce2e..e454b03 100644 --- a/src/SFML/Window/Unix/JoystickImpl.hpp +++ b/src/SFML/Window/Unix/JoystickImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -45,6 +45,12 @@ class JoystickImpl public: //////////////////////////////////////////////////////////// + /// \brief Constructor + /// + //////////////////////////////////////////////////////////// + JoystickImpl(); + + //////////////////////////////////////////////////////////// /// \brief Perform the global initialization of the joystick module /// //////////////////////////////////////////////////////////// diff --git a/src/SFML/Window/Unix/ScopedXcbPtr.hpp b/src/SFML/Window/Unix/ScopedXcbPtr.hpp index 6c98065..f610d81 100644 --- a/src/SFML/Window/Unix/ScopedXcbPtr.hpp +++ b/src/SFML/Window/Unix/ScopedXcbPtr.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/ScopedXcbPtr.inl b/src/SFML/Window/Unix/ScopedXcbPtr.inl index 6683a1e..5869d91 100644 --- a/src/SFML/Window/Unix/ScopedXcbPtr.inl +++ b/src/SFML/Window/Unix/ScopedXcbPtr.inl @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/SensorImpl.cpp b/src/SFML/Window/Unix/SensorImpl.cpp index 144c6d7..fb8fce1 100644 --- a/src/SFML/Window/Unix/SensorImpl.cpp +++ b/src/SFML/Window/Unix/SensorImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/SensorImpl.hpp b/src/SFML/Window/Unix/SensorImpl.hpp index 49ced87..7006377 100644 --- a/src/SFML/Window/Unix/SensorImpl.hpp +++ b/src/SFML/Window/Unix/SensorImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp index 9ee812f..f95d323 100644 --- a/src/SFML/Window/Unix/VideoModeImpl.cpp +++ b/src/SFML/Window/Unix/VideoModeImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 7aaf4e4..88176bf 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -34,6 +34,7 @@ #include <SFML/System/Err.hpp> #include <SFML/System/Mutex.hpp> #include <SFML/System/Lock.hpp> +#include <SFML/System/Sleep.hpp> #include <xcb/xcb_image.h> #include <xcb/randr.h> #include <X11/Xlibint.h> @@ -69,7 +70,10 @@ namespace 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_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | + XCB_EVENT_MASK_VISIBILITY_CHANGE; + + static const unsigned int maxTrialsCount = 5; // Filter the events received by windows (only allow those matching a specific window) Bool checkEvent(::Display*, XEvent* event, XPointer userData) @@ -358,6 +362,7 @@ namespace priv //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(WindowHandle handle) : m_window (0), +m_screen (NULL), m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (true), @@ -365,7 +370,9 @@ m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), m_useSizeHints (false), -m_fullscreen (false) +m_fullscreen (false), +m_cursorGrabbed (false), +m_windowMapped (false) { // Open a connection with the X server m_display = OpenDisplay(); @@ -411,6 +418,7 @@ m_fullscreen (false) //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) : m_window (0), +m_screen (NULL), m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (false), @@ -418,7 +426,9 @@ m_hiddenCursor (0), m_keyRepeat (true), m_previousSize (-1, -1), m_useSizeHints (false), -m_fullscreen ((style & Style::Fullscreen) != 0) +m_fullscreen ((style & Style::Fullscreen) != 0), +m_cursorGrabbed (m_fullscreen), +m_windowMapped (false) { // Open a connection with the X server m_display = OpenDisplay(); @@ -732,7 +742,7 @@ void WindowImplX11::setTitle(const String& title) err() << "Failed to set _NET_WM_NAME property" << std::endl; } - if (utf8StringType && netWmName) + if (utf8StringType && netWmIconName) { if (!changeWindowProperty(netWmIconName, utf8StringType, 8, utf8String.length(), utf8String.c_str())) err() << "Failed to set _NET_WM_ICON_NAME property" << std::endl; @@ -909,6 +919,13 @@ void WindowImplX11::setVisible(bool visible) if (error) err() << "Failed to change window visibility" << std::endl; + + xcb_flush(m_connection); + + // Before continuing, make sure the WM has + // internally marked the window as viewable + while (!m_windowMapped) + processEvents(); } else { @@ -922,9 +939,14 @@ void WindowImplX11::setVisible(bool visible) if (error) err() << "Failed to change window visibility" << std::endl; - } - xcb_flush(m_connection); + xcb_flush(m_connection); + + // Before continuing, make sure the WM has + // internally marked the window as unviewable + while (m_windowMapped) + processEvents(); + } } @@ -951,6 +973,71 @@ void WindowImplX11::setMouseCursorVisible(bool visible) //////////////////////////////////////////////////////////// +void WindowImplX11::setMouseCursorGrabbed(bool grabbed) +{ + // This has no effect in fullscreen mode + if (m_fullscreen || (m_cursorGrabbed == grabbed)) + return; + + if (grabbed) + { + // Try multiple times to grab the cursor + for (unsigned int trial = 0; trial < maxTrialsCount; ++trial) + { + sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL); + + sf::priv::ScopedXcbPtr<xcb_grab_pointer_reply_t> 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)) + { + m_cursorGrabbed = true; + break; + } + + // The cursor grab failed, trying again after a small sleep + sf::sleep(sf::milliseconds(50)); + } + + if (!m_cursorGrabbed) + err() << "Failed to grab mouse cursor" << std::endl; + } + else + { + ScopedXcbPtr<xcb_generic_error_t> 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; + } + } +} + + +//////////////////////////////////////////////////////////// void WindowImplX11::setKeyRepeatEnabled(bool enabled) { m_keyRepeat = enabled; @@ -1604,7 +1691,7 @@ void WindowImplX11::cleanup() //////////////////////////////////////////////////////////// -bool WindowImplX11::processEvent(XEvent windowEvent) +bool WindowImplX11::processEvent(XEvent& windowEvent) { // This function implements a workaround to properly discard // repeated key events when necessary. The problem is that the @@ -1659,6 +1746,44 @@ bool WindowImplX11::processEvent(XEvent windowEvent) if (m_inputContext) XSetICFocus(m_inputContext); + // Grab cursor + if (m_cursorGrabbed) + { + // Try multiple times to grab the cursor + for (unsigned int trial = 0; trial < maxTrialsCount; ++trial) + { + sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL); + + sf::priv::ScopedXcbPtr<xcb_grab_pointer_reply_t> 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)) + { + m_cursorGrabbed = true; + break; + } + + // The cursor grab failed, trying again after a small sleep + sf::sleep(sf::milliseconds(50)); + } + + if (!m_cursorGrabbed) + err() << "Failed to grab mouse cursor" << std::endl; + } + Event event; event.type = Event::GainedFocus; pushEvent(event); @@ -1701,6 +1826,21 @@ bool WindowImplX11::processEvent(XEvent windowEvent) if (m_inputContext) XUnsetICFocus(m_inputContext); + // Release cursor + if (m_cursorGrabbed) + { + ScopedXcbPtr<xcb_generic_error_t> 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; + } + Event event; event.type = Event::LostFocus; pushEvent(event); @@ -1757,17 +1897,23 @@ bool WindowImplX11::processEvent(XEvent windowEvent) // Key down event case KeyPress: { - // Get the keysym of the key that has been pressed - static XComposeStatus keyboard; - char buffer[32]; - KeySym symbol; - XLookupString(&windowEvent.xkey, buffer, sizeof(buffer), &symbol, &keyboard); + Keyboard::Key key = Keyboard::Unknown; + + // Try each KeySym index (modifier group) until we get a match + for (int i = 0; i < 4; ++i) + { + // Get the SFML keyboard code from the keysym of the key that has been pressed + key = keysymToSF(XLookupKeysym(&windowEvent.xkey, i)); + + if (key != Keyboard::Unknown) + break; + } // Fill the event parameters // TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping Event event; event.type = Event::KeyPressed; - event.key.code = keysymToSF(symbol); + event.key.code = key; event.key.alt = windowEvent.xkey.state & Mod1Mask; event.key.control = windowEvent.xkey.state & ControlMask; event.key.shift = windowEvent.xkey.state & ShiftMask; @@ -1826,15 +1972,22 @@ bool WindowImplX11::processEvent(XEvent windowEvent) // Key up event case KeyRelease: { - // Get the keysym of the key that has been pressed - char buffer[32]; - KeySym symbol; - XLookupString(&windowEvent.xkey, buffer, 32, &symbol, NULL); + Keyboard::Key key = Keyboard::Unknown; + + // Try each KeySym index (modifier group) until we get a match + for (int i = 0; i < 4; ++i) + { + // Get the SFML keyboard code from the keysym of the key that has been released + key = keysymToSF(XLookupKeysym(&windowEvent.xkey, i)); + + if (key != Keyboard::Unknown) + break; + } // Fill the event parameters Event event; event.type = Event::KeyReleased; - event.key.code = keysymToSF(symbol); + event.key.code = key; event.key.alt = windowEvent.xkey.state & Mod1Mask; event.key.control = windowEvent.xkey.state & ControlMask; event.key.shift = windowEvent.xkey.state & ShiftMask; @@ -1962,16 +2115,33 @@ bool WindowImplX11::processEvent(XEvent windowEvent) break; } - // Parent window changed - case ReparentNotify: + // Window unmapped + case UnmapNotify: { - // Catch reparent events to properly apply fullscreen on - // some "strange" window managers (like Awesome) which - // seem to make use of temporary parents during mapping - if (m_fullscreen) - switchToFullscreen(); + if (windowEvent.xunmap.window == m_window) + m_windowMapped = false; + + break; + } + + // Window visibility change + case VisibilityNotify: + { + // We prefer using VisibilityNotify over MapNotify because + // some window managers like awesome don't internally flag a + // window as viewable even after it is mapped but before it + // is visible leading to certain function calls failing with + // an unviewable error if called before VisibilityNotify arrives + + // Empirical testing on most widely used window managers shows + // that mapping a window will always lead to a VisibilityNotify + // event that is not VisibilityFullyObscured + if (windowEvent.xvisibility.window == m_window) + { + if (windowEvent.xvisibility.state != VisibilityFullyObscured) + m_windowMapped = true; + } - XSync(m_display, True); // Discard remaining events break; } } diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index a717bfb..ea6f741 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -148,6 +148,14 @@ public: virtual void setMouseCursorVisible(bool visible); //////////////////////////////////////////////////////////// + /// \brief Grab or release the mouse cursor + /// + /// \param grabbed True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursorGrabbed(bool grabbed); + + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// /// \param enabled True to enable, false to disable @@ -301,7 +309,7 @@ private: /// \return True if the event was processed, false if it was discarded /// //////////////////////////////////////////////////////////// - bool processEvent(XEvent windowEvent); + bool processEvent(XEvent& windowEvent); //////////////////////////////////////////////////////////// // Member data @@ -318,7 +326,9 @@ private: 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 window in fullscreen? + 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? }; } // namespace priv diff --git a/src/SFML/Window/VideoMode.cpp b/src/SFML/Window/VideoMode.cpp index 8f3861d..2202d77 100644 --- a/src/SFML/Window/VideoMode.cpp +++ b/src/SFML/Window/VideoMode.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/VideoModeImpl.hpp b/src/SFML/Window/VideoModeImpl.hpp index cc992f9..f1a1b03 100644 --- a/src/SFML/Window/VideoModeImpl.hpp +++ b/src/SFML/Window/VideoModeImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Win32/InputImpl.cpp b/src/SFML/Window/Win32/InputImpl.cpp index 6b1a472..8be35ec 100644 --- a/src/SFML/Window/Win32/InputImpl.cpp +++ b/src/SFML/Window/Win32/InputImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Win32/InputImpl.hpp b/src/SFML/Window/Win32/InputImpl.hpp index 9f455f4..598ef62 100644 --- a/src/SFML/Window/Win32/InputImpl.hpp +++ b/src/SFML/Window/Win32/InputImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Win32/JoystickImpl.cpp b/src/SFML/Window/Win32/JoystickImpl.cpp index ab40d5f..50cc819 100644 --- a/src/SFML/Window/Win32/JoystickImpl.cpp +++ b/src/SFML/Window/Win32/JoystickImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Win32/JoystickImpl.hpp b/src/SFML/Window/Win32/JoystickImpl.hpp index ab0a724..591b0e8 100644 --- a/src/SFML/Window/Win32/JoystickImpl.hpp +++ b/src/SFML/Window/Win32/JoystickImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Win32/SensorImpl.cpp b/src/SFML/Window/Win32/SensorImpl.cpp index 144c6d7..fb8fce1 100644 --- a/src/SFML/Window/Win32/SensorImpl.cpp +++ b/src/SFML/Window/Win32/SensorImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Win32/SensorImpl.hpp b/src/SFML/Window/Win32/SensorImpl.hpp index 666e5d2..8bea45b 100644 --- a/src/SFML/Window/Win32/SensorImpl.hpp +++ b/src/SFML/Window/Win32/SensorImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Win32/VideoModeImpl.cpp b/src/SFML/Window/Win32/VideoModeImpl.cpp index 4b34a0f..90f522f 100644 --- a/src/SFML/Window/Win32/VideoModeImpl.cpp +++ b/src/SFML/Window/Win32/VideoModeImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/Win32/WglContext.cpp b/src/SFML/Window/Win32/WglContext.cpp index c4e8b93..486946f 100644 --- a/src/SFML/Window/Win32/WglContext.cpp +++ b/src/SFML/Window/Win32/WglContext.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -26,12 +26,13 @@ // Headers //////////////////////////////////////////////////////////// #include <SFML/Window/WindowImpl.hpp> // included first to avoid a warning about macro redefinition +#include <SFML/OpenGL.hpp> // included second to avoid an error in WglExtensions.hpp #include <SFML/Window/Win32/WglContext.hpp> -#include <SFML/Window/Win32/WglExtensions.hpp> #include <SFML/System/Lock.hpp> #include <SFML/System/Mutex.hpp> #include <SFML/System/Err.hpp> #include <sstream> +#include <vector> namespace sf @@ -69,62 +70,75 @@ String getErrorString(DWORD errorCode) //////////////////////////////////////////////////////////// WglContext::WglContext(WglContext* shared) : m_window (NULL), +m_pbuffer (NULL), m_deviceContext(NULL), m_context (NULL), -m_ownsWindow (true) +m_ownsWindow (false) { - // Creating a dummy window is mandatory: we could create a memory DC but then - // its pixel format wouldn't match the regular contexts' format, and thus - // wglShareLists would always fail. Too bad... + // Save the creation settings + m_settings = ContextSettings(); + + // Make sure that extensions are initialized if this is not the shared context + // The shared context is the context used to initialize the extensions + if (shared && shared->m_deviceContext) + ensureExtensionsInit(shared->m_deviceContext); - // Create a dummy window (disabled and hidden) - m_window = CreateWindowA("STATIC", "", WS_POPUP | WS_DISABLED, 0, 0, 1, 1, NULL, NULL, GetModuleHandle(NULL), NULL); - ShowWindow(m_window, SW_HIDE); - m_deviceContext = GetDC(m_window); + // Create the rendering surface (window or pbuffer if supported) + createSurface(shared, 1, 1, VideoMode::getDesktopMode().bitsPerPixel); // Create the context if (m_deviceContext) - createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings()); + createContext(shared); } //////////////////////////////////////////////////////////// WglContext::WglContext(WglContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) : m_window (NULL), +m_pbuffer (NULL), m_deviceContext(NULL), m_context (NULL), m_ownsWindow (false) { - // Get the owner window and its device context - m_window = owner->getSystemHandle(); - m_deviceContext = GetDC(m_window); + // Save the creation settings + m_settings = settings; + + // Make sure that extensions are initialized if this is not the shared context + // The shared context is the context used to initialize the extensions + if (shared && shared->m_deviceContext) + ensureExtensionsInit(shared->m_deviceContext); + + // Create the rendering surface from the owner window + createSurface(owner->getSystemHandle(), bitsPerPixel); // Create the context if (m_deviceContext) - createContext(shared, bitsPerPixel, settings); + createContext(shared); } //////////////////////////////////////////////////////////// WglContext::WglContext(WglContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) : m_window (NULL), +m_pbuffer (NULL), m_deviceContext(NULL), m_context (NULL), -m_ownsWindow (true) +m_ownsWindow (false) { - // The target of the context is a hidden window. - // We can't create a memory DC (the resulting context wouldn't be compatible - // with other contexts), and we don't add the extra complexity of P-Buffers; - // we can still support them in the future if this solution is not good enough. + // Save the creation settings + m_settings = settings; + + // Make sure that extensions are initialized if this is not the shared context + // The shared context is the context used to initialize the extensions + if (shared && shared->m_deviceContext) + ensureExtensionsInit(shared->m_deviceContext); - // Create the hidden window - m_window = CreateWindowA("STATIC", "", WS_POPUP | WS_DISABLED, 0, 0, width, height, NULL, NULL, GetModuleHandle(NULL), NULL); - ShowWindow(m_window, SW_HIDE); - m_deviceContext = GetDC(m_window); + // Create the rendering surface (window or pbuffer if supported) + createSurface(shared, width, height, VideoMode::getDesktopMode().bitsPerPixel); // Create the context if (m_deviceContext) - createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings); + createContext(shared); } @@ -141,7 +155,17 @@ WglContext::~WglContext() // Destroy the device context if (m_deviceContext) - ReleaseDC(m_window, m_deviceContext); + { + if (m_pbuffer) + { + wglReleasePbufferDCARB(m_pbuffer, m_deviceContext); + wglDestroyPbufferARB(m_pbuffer); + } + else + { + ReleaseDC(m_window, m_deviceContext); + } + } // Destroy the window if we own it if (m_window && m_ownsWindow) @@ -217,7 +241,7 @@ void WglContext::setVerticalSyncEnabled(bool enabled) //////////////////////////////////////////////////////////// -int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings) +int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings, bool pbuffer) { // Let's find a suitable pixel format -- first try with wglChoosePixelFormatARB int bestFormat = 0; @@ -279,9 +303,40 @@ int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPix } } + int sRgbCapableValue = 0; + if ((sfwgl_ext_ARB_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED) || (sfwgl_ext_EXT_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED)) + { + const int sRgbCapableAttribute = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; + + if (!wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 1, &sRgbCapableAttribute, &sRgbCapableValue)) + { + err() << "Failed to retrieve pixel format sRGB capability information: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + break; + } + } + + if (pbuffer) + { + const int pbufferAttributes[] = + { + WGL_DRAW_TO_PBUFFER_ARB + }; + + int pbufferValue = 0; + + if (!wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 1, pbufferAttributes, &pbufferValue)) + { + err() << "Failed to retrieve pixel format pbuffer information: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + break; + } + + if (pbufferValue != GL_TRUE) + continue; + } + // Evaluate the current configuration int color = values[0] + values[1] + values[2] + values[3]; - int score = evaluateFormat(bitsPerPixel, settings, color, values[4], values[5], sampleValues[0] ? sampleValues[1] : 0, values[6] == WGL_FULL_ACCELERATION_ARB); + int score = evaluateFormat(bitsPerPixel, settings, color, values[4], values[5], sampleValues[0] ? sampleValues[1] : 0, values[6] == WGL_FULL_ACCELERATION_ARB, sRgbCapableValue == TRUE); // Keep it if it's better than the current best if (score < bestScore) @@ -293,6 +348,10 @@ int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPix } } + // ChoosePixelFormat doesn't support pbuffers + if (pbuffer) + return bestFormat; + // Find a pixel format with ChoosePixelFormat, if wglChoosePixelFormatARB is not supported if (bestFormat == 0) { @@ -318,17 +377,9 @@ int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPix //////////////////////////////////////////////////////////// -void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) +void WglContext::setDevicePixelFormat(unsigned int bitsPerPixel) { - // Save the creation settings - m_settings = settings; - - // Make sure that extensions are initialized if this is not the shared context - // The shared context is the context used to initialize the extensions - if (shared) - ensureExtensionsInit(m_deviceContext); - - int bestFormat = selectBestPixelFormat(m_deviceContext, bitsPerPixel, settings); + int bestFormat = selectBestPixelFormat(m_deviceContext, bitsPerPixel, m_settings); if (bestFormat == 0) { @@ -343,12 +394,38 @@ void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, co actualFormat.nVersion = 1; DescribePixelFormat(m_deviceContext, bestFormat, sizeof(actualFormat), &actualFormat); + // Set the chosen pixel format + if (!SetPixelFormat(m_deviceContext, bestFormat, &actualFormat)) + { + err() << "Failed to set pixel format for device context: " << getErrorString(GetLastError()).toAnsiString() << std::endl + << "Cannot create OpenGL context" << std::endl; + return; + } +} + + +//////////////////////////////////////////////////////////// +void WglContext::updateSettingsFromPixelFormat() +{ + int format = GetPixelFormat(m_deviceContext); + + PIXELFORMATDESCRIPTOR actualFormat; + actualFormat.nSize = sizeof(actualFormat); + actualFormat.nVersion = 1; + DescribePixelFormat(m_deviceContext, format, sizeof(actualFormat), &actualFormat); + + if (format == 0) + { + err() << "Failed to get selected pixel format" << std::endl; + return; + } + if (sfwgl_ext_ARB_pixel_format == sfwgl_LOAD_SUCCEEDED) { const int attributes[] = {WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB}; int values[2]; - if (wglGetPixelFormatAttribivARB(m_deviceContext, bestFormat, PFD_MAIN_PLANE, 2, attributes, values)) + if (wglGetPixelFormatAttribivARB(m_deviceContext, format, PFD_MAIN_PLANE, 2, attributes, values)) { m_settings.depthBits = values[0]; m_settings.stencilBits = values[1]; @@ -365,7 +442,7 @@ void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, co const int sampleAttributes[] = {WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB}; int sampleValues[2]; - if (wglGetPixelFormatAttribivARB(m_deviceContext, bestFormat, PFD_MAIN_PLANE, 2, sampleAttributes, sampleValues)) + if (wglGetPixelFormatAttribivARB(m_deviceContext, format, PFD_MAIN_PLANE, 2, sampleAttributes, sampleValues)) { m_settings.antialiasingLevel = sampleValues[0] ? sampleValues[1] : 0; } @@ -379,6 +456,26 @@ void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, co { m_settings.antialiasingLevel = 0; } + + if ((sfwgl_ext_ARB_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED) || (sfwgl_ext_EXT_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED)) + { + const int sRgbCapableAttribute = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; + int sRgbCapableValue = 0; + + if (wglGetPixelFormatAttribivARB(m_deviceContext, format, PFD_MAIN_PLANE, 1, &sRgbCapableAttribute, &sRgbCapableValue)) + { + m_settings.sRgbCapable = (sRgbCapableValue == TRUE); + } + else + { + err() << "Failed to retrieve pixel format sRGB capability information: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + m_settings.sRgbCapable = false; + } + } + else + { + m_settings.sRgbCapable = false; + } } else { @@ -386,15 +483,79 @@ void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, co m_settings.stencilBits = actualFormat.cStencilBits; m_settings.antialiasingLevel = 0; } +} - // Set the chosen pixel format - if (!SetPixelFormat(m_deviceContext, bestFormat, &actualFormat)) + +//////////////////////////////////////////////////////////// +void WglContext::createSurface(WglContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel) +{ + // Check if the shared context already exists and pbuffers are supported + if (shared && shared->m_deviceContext && (sfwgl_ext_ARB_pbuffer == sfwgl_LOAD_SUCCEEDED)) { - err() << "Failed to set pixel format for device context: " << getErrorString(GetLastError()).toAnsiString() << std::endl - << "Cannot create OpenGL context" << std::endl; - return; + int bestFormat = selectBestPixelFormat(shared->m_deviceContext, bitsPerPixel, m_settings, true); + + if (bestFormat > 0) + { + int attributes[] = {0, 0}; + + m_pbuffer = wglCreatePbufferARB(shared->m_deviceContext, bestFormat, width, height, attributes); + + if (m_pbuffer) + { + m_window = shared->m_window; + m_deviceContext = wglGetPbufferDCARB(m_pbuffer); + + if (!m_deviceContext) + { + wglDestroyPbufferARB(m_pbuffer); + m_pbuffer = NULL; + } + } + } + } + + // If pbuffers are not available we use a hidden window as the off-screen surface to draw to + if (!m_deviceContext) + { + // We can't create a memory DC, the resulting context wouldn't be compatible + // with other contexts and thus wglShareLists would always fail + + // Create the hidden window + m_window = CreateWindowA("STATIC", "", WS_POPUP | WS_DISABLED, 0, 0, width, height, NULL, NULL, GetModuleHandle(NULL), NULL); + ShowWindow(m_window, SW_HIDE); + m_deviceContext = GetDC(m_window); + + m_ownsWindow = true; + + // Set the pixel format of the device context + setDevicePixelFormat(bitsPerPixel); } + // Update context settings from the selected pixel format + updateSettingsFromPixelFormat(); +} + + +//////////////////////////////////////////////////////////// +void WglContext::createSurface(HWND window, unsigned int bitsPerPixel) +{ + m_window = window; + m_deviceContext = GetDC(window); + + // Set the pixel format of the device context + setDevicePixelFormat(bitsPerPixel); + + // Update context settings from the selected pixel format + updateSettingsFromPixelFormat(); +} + + +//////////////////////////////////////////////////////////// +void WglContext::createContext(WglContext* shared) +{ + // Get a working copy of the context settings + ContextSettings settings = m_settings; + // Get the context to share display lists with HGLRC sharedContext = shared ? shared->m_context : NULL; @@ -403,21 +564,27 @@ void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, co { if (sfwgl_ext_ARB_create_context == sfwgl_LOAD_SUCCEEDED) { + std::vector<int> attributes; + + // Check if the user requested a specific context version (anything > 1.1) + if ((m_settings.majorVersion > 1) || ((m_settings.majorVersion == 1) && (m_settings.minorVersion > 1))) + { + attributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB); + attributes.push_back(m_settings.majorVersion); + attributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB); + attributes.push_back(m_settings.minorVersion); + } + // Check if setting the profile is supported if (sfwgl_ext_ARB_create_context_profile == sfwgl_LOAD_SUCCEEDED) { int profile = (m_settings.attributeFlags & ContextSettings::Core) ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; int debug = (m_settings.attributeFlags & ContextSettings::Debug) ? WGL_CONTEXT_DEBUG_BIT_ARB : 0; - int attributes[] = - { - WGL_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(m_settings.majorVersion), - WGL_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(m_settings.minorVersion), - WGL_CONTEXT_PROFILE_MASK_ARB, profile, - WGL_CONTEXT_FLAGS_ARB, debug, - 0, 0 - }; - m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, attributes); + attributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB); + attributes.push_back(profile); + attributes.push_back(WGL_CONTEXT_FLAGS_ARB); + attributes.push_back(debug); } else { @@ -426,15 +593,14 @@ void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, co << "disabling comptibility and debug" << std::endl; m_settings.attributeFlags = ContextSettings::Default; - - int attributes[] = - { - WGL_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(m_settings.majorVersion), - WGL_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(m_settings.minorVersion), - 0, 0 - }; - m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, attributes); } + + // Append the terminating 0 + attributes.push_back(0); + attributes.push_back(0); + + // Create the context + m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]); } else { diff --git a/src/SFML/Window/Win32/WglContext.hpp b/src/SFML/Window/Win32/WglContext.hpp index 45070f6..ceecc2d 100644 --- a/src/SFML/Window/Win32/WglContext.hpp +++ b/src/SFML/Window/Win32/WglContext.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -29,8 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include <SFML/Window/GlContext.hpp> -#include <SFML/OpenGL.hpp> -#include <windows.h> +#include <SFML/Window/Win32/WglExtensions.hpp> namespace sf @@ -124,31 +123,65 @@ public: /// \param deviceContext Device context /// \param bitsPerPixel Pixel depth, in bits per pixel /// \param settings Requested context settings + /// \param pbuffer Whether the pixel format should support pbuffers /// /// \return The best pixel format /// //////////////////////////////////////////////////////////// - static int selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings); + static int selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings, bool pbuffer = false); private: //////////////////////////////////////////////////////////// + /// \brief Set the pixel format of the device context + /// + /// \param bitsPerPixel Pixel depth, in bits per pixel + /// + //////////////////////////////////////////////////////////// + void setDevicePixelFormat(unsigned int bitsPerPixel); + + //////////////////////////////////////////////////////////// + /// \brief Update the context settings from the selected pixel format + /// + //////////////////////////////////////////////////////////// + void updateSettingsFromPixelFormat(); + + //////////////////////////////////////////////////////////// + /// \brief Create the context's drawing surface + /// + /// \param shared Shared context (can be NULL) + /// \param width Back buffer width, in pixels + /// \param height Back buffer height, in pixels + /// \param bitsPerPixel Pixel depth, in bits per pixel + /// + //////////////////////////////////////////////////////////// + void createSurface(WglContext* shared, unsigned int width, unsigned int height, unsigned int bitsPerPixel); + + //////////////////////////////////////////////////////////// + /// \brief Create the context's drawing surface from an existing window + /// + /// \param window Window handle of the owning window + /// \param bitsPerPixel Pixel depth, in bits per pixel + /// + //////////////////////////////////////////////////////////// + void createSurface(HWND window, unsigned int bitsPerPixel); + + //////////////////////////////////////////////////////////// /// \brief Create the context /// - /// \param shared Context to share the new one with (can be NULL) - /// \param bitsPerPixel Pixel depth, in bits per pixel - /// \param settings Creation parameters + /// \param shared Context to share the new one with (can be NULL) /// //////////////////////////////////////////////////////////// - void createContext(WglContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings); + void createContext(WglContext* shared); //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - HWND m_window; ///< Window to which the context is attached - HDC m_deviceContext; ///< Device context associated to the context - HGLRC m_context; ///< OpenGL context - bool m_ownsWindow; ///< Do we own the target window? + HWND m_window; ///< Window to which the context is attached + HPBUFFERARB m_pbuffer; ///< Handle to a pbuffer if one was created + HDC m_deviceContext; ///< Device context associated to the context + HGLRC m_context; ///< OpenGL context + bool m_ownsWindow; ///< Do we own the target window? }; } // namespace priv diff --git a/src/SFML/Window/Win32/WglExtensions.cpp b/src/SFML/Window/Win32/WglExtensions.cpp index 0d82b74..16cf473 100644 --- a/src/SFML/Window/Win32/WglExtensions.cpp +++ b/src/SFML/Window/Win32/WglExtensions.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -30,6 +30,7 @@ #include <cstdlib> #include <cstring> #include <cstddef> +#include <string> static sf::GlFunctionPointer IntGetProcAddress(const char* name) { @@ -37,8 +38,11 @@ static sf::GlFunctionPointer IntGetProcAddress(const char* name) } int sfwgl_ext_EXT_swap_control = sfwgl_LOAD_FAILED; +int sfwgl_ext_EXT_framebuffer_sRGB = sfwgl_LOAD_FAILED; +int sfwgl_ext_ARB_framebuffer_sRGB = sfwgl_LOAD_FAILED; int sfwgl_ext_ARB_multisample = sfwgl_LOAD_FAILED; int sfwgl_ext_ARB_pixel_format = sfwgl_LOAD_FAILED; +int sfwgl_ext_ARB_pbuffer = sfwgl_LOAD_FAILED; int sfwgl_ext_ARB_create_context = sfwgl_LOAD_FAILED; int sfwgl_ext_ARB_create_context_profile = sfwgl_LOAD_FAILED; @@ -48,93 +52,133 @@ BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglSwapIntervalEXT)(int) = NULL; static int Load_EXT_swap_control(void) { int numFailed = 0; - sf_ptrc_wglGetSwapIntervalEXT = (int (CODEGEN_FUNCPTR *)(void))IntGetProcAddress("wglGetSwapIntervalEXT"); - if(!sf_ptrc_wglGetSwapIntervalEXT) numFailed++; - sf_ptrc_wglSwapIntervalEXT = (BOOL (CODEGEN_FUNCPTR *)(int))IntGetProcAddress("wglSwapIntervalEXT"); - if(!sf_ptrc_wglSwapIntervalEXT) numFailed++; + sf_ptrc_wglGetSwapIntervalEXT = reinterpret_cast<int (CODEGEN_FUNCPTR*)(void)>(IntGetProcAddress("wglGetSwapIntervalEXT")); + if (!sf_ptrc_wglGetSwapIntervalEXT) + numFailed++; + sf_ptrc_wglSwapIntervalEXT = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(int)>(IntGetProcAddress("wglSwapIntervalEXT")); + if (!sf_ptrc_wglSwapIntervalEXT) + numFailed++; return numFailed; } -BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglChoosePixelFormatARB)(HDC, const int *, const FLOAT *, UINT, int *, UINT *) = NULL; -BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribfvARB)(HDC, int, int, UINT, const int *, FLOAT *) = NULL; -BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribivARB)(HDC, int, int, UINT, const int *, int *) = NULL; +BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglChoosePixelFormatARB)(HDC, const int*, const FLOAT*, UINT, int*, UINT*) = NULL; +BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribfvARB)(HDC, int, int, UINT, const int*, FLOAT*) = NULL; +BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribivARB)(HDC, int, int, UINT, const int*, int*) = NULL; static int Load_ARB_pixel_format(void) { int numFailed = 0; - sf_ptrc_wglChoosePixelFormatARB = (BOOL (CODEGEN_FUNCPTR *)(HDC, const int *, const FLOAT *, UINT, int *, UINT *))IntGetProcAddress("wglChoosePixelFormatARB"); - if(!sf_ptrc_wglChoosePixelFormatARB) numFailed++; - sf_ptrc_wglGetPixelFormatAttribfvARB = (BOOL (CODEGEN_FUNCPTR *)(HDC, int, int, UINT, const int *, FLOAT *))IntGetProcAddress("wglGetPixelFormatAttribfvARB"); - if(!sf_ptrc_wglGetPixelFormatAttribfvARB) numFailed++; - sf_ptrc_wglGetPixelFormatAttribivARB = (BOOL (CODEGEN_FUNCPTR *)(HDC, int, int, UINT, const int *, int *))IntGetProcAddress("wglGetPixelFormatAttribivARB"); - if(!sf_ptrc_wglGetPixelFormatAttribivARB) numFailed++; + sf_ptrc_wglChoosePixelFormatARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(HDC, const int*, const FLOAT*, UINT, int*, UINT*)>(IntGetProcAddress("wglChoosePixelFormatARB")); + if (!sf_ptrc_wglChoosePixelFormatARB) + numFailed++; + sf_ptrc_wglGetPixelFormatAttribfvARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR *)(HDC, int, int, UINT, const int*, FLOAT*)>(IntGetProcAddress("wglGetPixelFormatAttribfvARB")); + if (!sf_ptrc_wglGetPixelFormatAttribfvARB) + numFailed++; + sf_ptrc_wglGetPixelFormatAttribivARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(HDC, int, int, UINT, const int*, int*)>(IntGetProcAddress("wglGetPixelFormatAttribivARB")); + if (!sf_ptrc_wglGetPixelFormatAttribivARB) + numFailed++; return numFailed; } -HGLRC (CODEGEN_FUNCPTR *sf_ptrc_wglCreateContextAttribsARB)(HDC, HGLRC, const int *) = NULL; +HPBUFFERARB (CODEGEN_FUNCPTR *sf_ptrc_wglCreatePbufferARB)(HDC, int, int, int, const int*) = NULL; +BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglDestroyPbufferARB)(HPBUFFERARB) = NULL; +HDC (CODEGEN_FUNCPTR *sf_ptrc_wglGetPbufferDCARB)(HPBUFFERARB) = NULL; +BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglQueryPbufferARB)(HPBUFFERARB, int, int*) = NULL; +int (CODEGEN_FUNCPTR *sf_ptrc_wglReleasePbufferDCARB)(HPBUFFERARB, HDC) = NULL; + +static int Load_ARB_pbuffer() +{ + int numFailed = 0; + sf_ptrc_wglCreatePbufferARB = reinterpret_cast<HPBUFFERARB (CODEGEN_FUNCPTR*)(HDC, int, int, int, const int*)>(IntGetProcAddress("wglCreatePbufferARB")); + if (!sf_ptrc_wglCreatePbufferARB) + numFailed++; + sf_ptrc_wglDestroyPbufferARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(HPBUFFERARB)>(IntGetProcAddress("wglDestroyPbufferARB")); + if (!sf_ptrc_wglDestroyPbufferARB) + numFailed++; + sf_ptrc_wglGetPbufferDCARB = reinterpret_cast<HDC (CODEGEN_FUNCPTR*)(HPBUFFERARB)>(IntGetProcAddress("wglGetPbufferDCARB")); + if (!sf_ptrc_wglGetPbufferDCARB) + numFailed++; + sf_ptrc_wglQueryPbufferARB = reinterpret_cast<BOOL (CODEGEN_FUNCPTR*)(HPBUFFERARB, int, int*)>(IntGetProcAddress("wglQueryPbufferARB")); + if (!sf_ptrc_wglQueryPbufferARB) + numFailed++; + sf_ptrc_wglReleasePbufferDCARB = reinterpret_cast<int (CODEGEN_FUNCPTR*)(HPBUFFERARB, HDC)>(IntGetProcAddress("wglReleasePbufferDCARB")); + if (!sf_ptrc_wglReleasePbufferDCARB) + numFailed++; + return numFailed; +} + +HGLRC (CODEGEN_FUNCPTR *sf_ptrc_wglCreateContextAttribsARB)(HDC, HGLRC, const int*) = NULL; static int Load_ARB_create_context(void) { int numFailed = 0; - sf_ptrc_wglCreateContextAttribsARB = (HGLRC (CODEGEN_FUNCPTR *)(HDC, HGLRC, const int *))IntGetProcAddress("wglCreateContextAttribsARB"); - if(!sf_ptrc_wglCreateContextAttribsARB) numFailed++; + sf_ptrc_wglCreateContextAttribsARB = reinterpret_cast<HGLRC (CODEGEN_FUNCPTR*)(HDC, HGLRC, const int*)>(IntGetProcAddress("wglCreateContextAttribsARB")); + if (!sf_ptrc_wglCreateContextAttribsARB) + numFailed++; return numFailed; } -static const char * (CODEGEN_FUNCPTR *sf_ptrc_wglGetExtensionsStringARB)(HDC) = NULL; +static const char* (CODEGEN_FUNCPTR *sf_ptrc_wglGetExtensionsStringARB)(HDC) = NULL; typedef int (*PFN_LOADFUNCPOINTERS)(void); typedef struct sfwgl_StrToExtMap_s { - const char *extensionName; - int *extensionVariable; + const char* extensionName; + int* extensionVariable; PFN_LOADFUNCPOINTERS LoadExtension; } sfwgl_StrToExtMap; -static sfwgl_StrToExtMap ExtensionMap[5] = { +static sfwgl_StrToExtMap ExtensionMap[8] = { {"WGL_EXT_swap_control", &sfwgl_ext_EXT_swap_control, Load_EXT_swap_control}, + {"WGL_EXT_framebuffer_sRGB", &sfwgl_ext_EXT_framebuffer_sRGB, NULL}, + {"WGL_ARB_framebuffer_sRGB", &sfwgl_ext_ARB_framebuffer_sRGB, NULL}, {"WGL_ARB_multisample", &sfwgl_ext_ARB_multisample, NULL}, {"WGL_ARB_pixel_format", &sfwgl_ext_ARB_pixel_format, Load_ARB_pixel_format}, + {"WGL_ARB_pbuffer", &sfwgl_ext_ARB_pbuffer, Load_ARB_pbuffer}, {"WGL_ARB_create_context", &sfwgl_ext_ARB_create_context, Load_ARB_create_context}, - {"WGL_ARB_create_context_profile", &sfwgl_ext_ARB_create_context_profile, NULL}, + {"WGL_ARB_create_context_profile", &sfwgl_ext_ARB_create_context_profile, NULL} }; -static int g_extensionMapSize = 5; +static int g_extensionMapSize = 8; -static sfwgl_StrToExtMap *FindExtEntry(const char *extensionName) + +static sfwgl_StrToExtMap* FindExtEntry(const char* extensionName) { - int loop; - sfwgl_StrToExtMap *currLoc = ExtensionMap; - for(loop = 0; loop < g_extensionMapSize; ++loop, ++currLoc) + sfwgl_StrToExtMap* currLoc = ExtensionMap; + for (int loop = 0; loop < g_extensionMapSize; ++loop, ++currLoc) { - if(strcmp(extensionName, currLoc->extensionName) == 0) + if (std::strcmp(extensionName, currLoc->extensionName) == 0) return currLoc; } return NULL; } + static void ClearExtensionVars(void) { sfwgl_ext_EXT_swap_control = sfwgl_LOAD_FAILED; + sfwgl_ext_EXT_framebuffer_sRGB = sfwgl_LOAD_FAILED; + sfwgl_ext_ARB_framebuffer_sRGB = sfwgl_LOAD_FAILED; sfwgl_ext_ARB_multisample = sfwgl_LOAD_FAILED; sfwgl_ext_ARB_pixel_format = sfwgl_LOAD_FAILED; + sfwgl_ext_ARB_pbuffer = sfwgl_LOAD_FAILED; sfwgl_ext_ARB_create_context = sfwgl_LOAD_FAILED; sfwgl_ext_ARB_create_context_profile = sfwgl_LOAD_FAILED; } -static void LoadExtByName(const char *extensionName) +static void LoadExtByName(const char* extensionName) { - sfwgl_StrToExtMap *entry = NULL; + sfwgl_StrToExtMap* entry = NULL; entry = FindExtEntry(extensionName); - if(entry) + if (entry) { - if(entry->LoadExtension) + if (entry->LoadExtension) { int numFailed = entry->LoadExtension(); - if(numFailed == 0) + if (numFailed == 0) { *(entry->extensionVariable) = sfwgl_LOAD_SUCCEEDED; } @@ -151,48 +195,29 @@ static void LoadExtByName(const char *extensionName) } -static void ProcExtsFromExtString(const char *strExtList) +static void ProcExtsFromExtString(const char* strExtList) { - size_t iExtListLen = strlen(strExtList); - const char *strExtListEnd = strExtList + iExtListLen; - const char *strCurrPos = strExtList; - char strWorkBuff[256]; - - while(*strCurrPos) + do { - /*Get the extension at our position.*/ - int iStrLen = 0; - const char *strEndStr = strchr(strCurrPos, ' '); - int iStop = 0; - if(strEndStr == NULL) - { - strEndStr = strExtListEnd; - iStop = 1; - } - - iStrLen = (int)((ptrdiff_t)strEndStr - (ptrdiff_t)strCurrPos); + const char* begin = strExtList; - if(iStrLen > 255) - return; + while ((*strExtList != ' ') && *strExtList) + strExtList++; - strncpy(strWorkBuff, strCurrPos, iStrLen); - strWorkBuff[iStrLen] = '\0'; - - LoadExtByName(strWorkBuff); - - strCurrPos = strEndStr + 1; - if(iStop) break; - } + LoadExtByName(std::string(begin, strExtList).c_str()); + } while (*strExtList++); } + int sfwgl_LoadFunctions(HDC hdc) { ClearExtensionVars(); - sf_ptrc_wglGetExtensionsStringARB = (const char * (CODEGEN_FUNCPTR *)(HDC))IntGetProcAddress("wglGetExtensionsStringARB"); - if(!sf_ptrc_wglGetExtensionsStringARB) return sfwgl_LOAD_FAILED; + sf_ptrc_wglGetExtensionsStringARB = reinterpret_cast<const char* (CODEGEN_FUNCPTR*)(HDC)>(IntGetProcAddress("wglGetExtensionsStringARB")); + if (!sf_ptrc_wglGetExtensionsStringARB) + return sfwgl_LOAD_FAILED; - ProcExtsFromExtString((const char *)sf_ptrc_wglGetExtensionsStringARB(hdc)); + ProcExtsFromExtString(reinterpret_cast<const char*>(sf_ptrc_wglGetExtensionsStringARB(hdc))); return sfwgl_LOAD_SUCCEEDED; } diff --git a/src/SFML/Window/Win32/WglExtensions.hpp b/src/SFML/Window/Win32/WglExtensions.hpp index 1b389c0..30d5253 100644 --- a/src/SFML/Window/Win32/WglExtensions.hpp +++ b/src/SFML/Window/Win32/WglExtensions.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -41,7 +41,7 @@ #ifdef CODEGEN_FUNCPTR #undef CODEGEN_FUNCPTR -#endif /*CODEGEN_FUNCPTR*/ +#endif // CODEGEN_FUNCPTR #define CODEGEN_FUNCPTR WINAPI #ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS @@ -63,14 +63,14 @@ typedef double GLdouble; typedef double GLclampd; #define GLvoid void -#endif /*GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS*/ +#endif // GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS #ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS #define GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS -#endif /*GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS*/ +#endif // GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS struct _GPU_DEVICE { @@ -90,14 +90,21 @@ typedef struct _GPU_DEVICE *PGPU_DEVICE; #ifdef __cplusplus extern "C" { -#endif /*__cplusplus*/ +#endif // __cplusplus extern int sfwgl_ext_EXT_swap_control; +extern int sfwgl_ext_EXT_framebuffer_sRGB; +extern int sfwgl_ext_ARB_framebuffer_sRGB; extern int sfwgl_ext_ARB_multisample; extern int sfwgl_ext_ARB_pixel_format; +extern int sfwgl_ext_ARB_pbuffer; extern int sfwgl_ext_ARB_create_context; extern int sfwgl_ext_ARB_create_context_profile; +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 + +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 + #define WGL_SAMPLES_ARB 0x2042 #define WGL_SAMPLE_BUFFERS_ARB 0x2041 @@ -151,6 +158,15 @@ extern int sfwgl_ext_ARB_create_context_profile; #define WGL_TYPE_COLORINDEX_ARB 0x202C #define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_DRAW_TO_PBUFFER_ARB 0x202D +#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 +#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E +#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F +#define WGL_PBUFFER_HEIGHT_ARB 0x2035 +#define WGL_PBUFFER_LARGEST_ARB 0x2033 +#define WGL_PBUFFER_LOST_ARB 0x2036 +#define WGL_PBUFFER_WIDTH_ARB 0x2034 + #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 @@ -170,24 +186,38 @@ extern int (CODEGEN_FUNCPTR *sf_ptrc_wglGetSwapIntervalEXT)(void); #define wglGetSwapIntervalEXT sf_ptrc_wglGetSwapIntervalEXT extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglSwapIntervalEXT)(int); #define wglSwapIntervalEXT sf_ptrc_wglSwapIntervalEXT -#endif /*WGL_EXT_swap_control*/ +#endif // WGL_EXT_swap_control #ifndef WGL_ARB_pixel_format #define WGL_ARB_pixel_format 1 -extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglChoosePixelFormatARB)(HDC, const int *, const FLOAT *, UINT, int *, UINT *); +extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglChoosePixelFormatARB)(HDC, const int*, const FLOAT*, UINT, int*, UINT*); #define wglChoosePixelFormatARB sf_ptrc_wglChoosePixelFormatARB -extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribfvARB)(HDC, int, int, UINT, const int *, FLOAT *); +extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribfvARB)(HDC, int, int, UINT, const int*, FLOAT*); #define wglGetPixelFormatAttribfvARB sf_ptrc_wglGetPixelFormatAttribfvARB -extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribivARB)(HDC, int, int, UINT, const int *, int *); +extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglGetPixelFormatAttribivARB)(HDC, int, int, UINT, const int*, int*); #define wglGetPixelFormatAttribivARB sf_ptrc_wglGetPixelFormatAttribivARB -#endif /*WGL_ARB_pixel_format*/ +#endif // WGL_ARB_pixel_format + +#ifndef WGL_ARB_pbuffer +#define WGL_ARB_pbuffer 1 +extern HPBUFFERARB (CODEGEN_FUNCPTR *sf_ptrc_wglCreatePbufferARB)(HDC, int, int, int, const int*); +#define wglCreatePbufferARB sf_ptrc_wglCreatePbufferARB +extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglDestroyPbufferARB)(HPBUFFERARB); +#define wglDestroyPbufferARB sf_ptrc_wglDestroyPbufferARB +extern HDC (CODEGEN_FUNCPTR *sf_ptrc_wglGetPbufferDCARB)(HPBUFFERARB); +#define wglGetPbufferDCARB sf_ptrc_wglGetPbufferDCARB +extern BOOL (CODEGEN_FUNCPTR *sf_ptrc_wglQueryPbufferARB)(HPBUFFERARB, int, int*); +#define wglQueryPbufferARB sf_ptrc_wglQueryPbufferARB +extern int (CODEGEN_FUNCPTR *sf_ptrc_wglReleasePbufferDCARB)(HPBUFFERARB, HDC); +#define wglReleasePbufferDCARB sf_ptrc_wglReleasePbufferDCARB +#endif // WGL_ARB_pbuffer #ifndef WGL_ARB_create_context #define WGL_ARB_create_context 1 -extern HGLRC (CODEGEN_FUNCPTR *sf_ptrc_wglCreateContextAttribsARB)(HDC, HGLRC, const int *); +extern HGLRC (CODEGEN_FUNCPTR *sf_ptrc_wglCreateContextAttribsARB)(HDC, HGLRC, const int*); #define wglCreateContextAttribsARB sf_ptrc_wglCreateContextAttribsARB -#endif /*WGL_ARB_create_context*/ +#endif // WGL_ARB_create_context enum sfwgl_LoadStatus @@ -201,6 +231,6 @@ int sfwgl_LoadFunctions(HDC hdc); #ifdef __cplusplus } -#endif /*__cplusplus*/ +#endif // __cplusplus -#endif /* SF_POINTER_C_GENERATED_HEADER_WINDOWSGL_HPP */ +#endif // SF_POINTER_C_GENERATED_HEADER_WINDOWSGL_HPP diff --git a/src/SFML/Window/Win32/WglExtensions.txt b/src/SFML/Window/Win32/WglExtensions.txt index 99610a6..667c853 100644 --- a/src/SFML/Window/Win32/WglExtensions.txt +++ b/src/SFML/Window/Win32/WglExtensions.txt @@ -1,10 +1,13 @@ // Created with: -// https://bitbucket.org/Anteru/glloadgen-reloaded -// Commit 20f19482b7a844d20b9785c3e3fd1f16419f6e0a +// https://bitbucket.org/KhronosGroup/glloadgen +// Commit d143d66ac90d538ed06f806188714861b8e8e2f9 // lua LoadGen.lua -style=pointer_c -spec=wgl -indent=space -prefix=sf -extfile=WglExtensions.txt WglExtensions EXT_swap_control +EXT_framebuffer_sRGB +ARB_framebuffer_sRGB WGL_ARB_multisample WGL_ARB_pixel_format +WGL_ARB_pbuffer WGL_ARB_create_context WGL_ARB_create_context_profile
\ No newline at end of file diff --git a/src/SFML/Window/Win32/WindowImplWin32.cpp b/src/SFML/Window/Win32/WindowImplWin32.cpp index 8bf86ab..cc999f9 100644 --- a/src/SFML/Window/Win32/WindowImplWin32.cpp +++ b/src/SFML/Window/Win32/WindowImplWin32.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -132,7 +132,9 @@ m_keyRepeatEnabled(true), m_lastSize (0, 0), m_resizing (false), m_surrogate (0), -m_mouseInside (false) +m_mouseInside (false), +m_fullscreen (false), +m_cursorGrabbed (false) { // Set that this process is DPI aware and can handle DPI scaling setProcessDpiAware(); @@ -156,7 +158,9 @@ m_keyRepeatEnabled(true), m_lastSize (mode.width, mode.height), m_resizing (false), m_surrogate (0), -m_mouseInside (false) +m_mouseInside (false), +m_fullscreen (style & Style::Fullscreen), +m_cursorGrabbed (m_fullscreen) { // Set that this process is DPI aware and can handle DPI scaling setProcessDpiAware(); @@ -187,8 +191,7 @@ m_mouseInside (false) } // In windowed mode, adjust width and height so that window will have the requested client area - bool fullscreen = (style & Style::Fullscreen) != 0; - if (!fullscreen) + if (!m_fullscreen) { RECT rectangle = {0, 0, width, height}; AdjustWindowRect(&rectangle, win32Style, false); @@ -204,7 +207,7 @@ m_mouseInside (false) setSize(Vector2u(mode.width, mode.height)); // Switch to fullscreen if requested - if (fullscreen) + if (m_fullscreen) switchToFullscreen(mode); // Increment window count @@ -277,6 +280,9 @@ Vector2i WindowImplWin32::getPosition() const void WindowImplWin32::setPosition(const Vector2i& position) { SetWindowPos(m_handle, NULL, position.x, position.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + + if(m_cursorGrabbed) + grabCursor(true); } @@ -364,6 +370,14 @@ void WindowImplWin32::setMouseCursorVisible(bool visible) //////////////////////////////////////////////////////////// +void WindowImplWin32::setMouseCursorGrabbed(bool grabbed) +{ + m_cursorGrabbed = grabbed; + grabCursor(m_cursorGrabbed); +} + + +//////////////////////////////////////////////////////////// void WindowImplWin32::setKeyRepeatEnabled(bool enabled) { m_keyRepeatEnabled = enabled; @@ -486,6 +500,23 @@ void WindowImplWin32::setTracking(bool track) //////////////////////////////////////////////////////////// +void WindowImplWin32::grabCursor(bool grabbed) +{ + if (grabbed) + { + RECT rect; + GetClientRect(m_handle, &rect); + MapWindowPoints(m_handle, NULL, reinterpret_cast<LPPOINT>(&rect), 2); + ClipCursor(&rect); + } + else + { + ClipCursor(NULL); + } +} + + +//////////////////////////////////////////////////////////// void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) { // Don't process any message until window is created @@ -536,6 +567,9 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) event.size.width = m_lastSize.x; event.size.height = m_lastSize.y; pushEvent(event); + + // Restore/update cursor grabbing + grabCursor(m_cursorGrabbed); } break; } @@ -544,6 +578,7 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) case WM_ENTERSIZEMOVE: { m_resizing = true; + grabCursor(false); break; } @@ -565,6 +600,9 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) event.size.height = m_lastSize.y; pushEvent(event); } + + // Restore/update cursor grabbing + grabCursor(m_cursorGrabbed); break; } @@ -582,6 +620,9 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) // Gain focus event case WM_SETFOCUS: { + // Restore cursor grabbing + grabCursor(m_cursorGrabbed); + Event event; event.type = Event::GainedFocus; pushEvent(event); @@ -591,6 +632,9 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) // Lost focus event case WM_KILLFOCUS: { + // Ungrab the cursor + grabCursor(false); + Event event; event.type = Event::LostFocus; pushEvent(event); diff --git a/src/SFML/Window/Win32/WindowImplWin32.hpp b/src/SFML/Window/Win32/WindowImplWin32.hpp index fb5fe0f..d7ef4e0 100644 --- a/src/SFML/Window/Win32/WindowImplWin32.hpp +++ b/src/SFML/Window/Win32/WindowImplWin32.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -146,6 +146,14 @@ public: virtual void setMouseCursorVisible(bool visible); //////////////////////////////////////////////////////////// + /// \brief Grab or release the mouse cursor + /// + /// \param grabbed True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursorGrabbed(bool grabbed); + + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// /// \param enabled True to enable, false to disable @@ -217,6 +225,19 @@ private: void setTracking(bool track); //////////////////////////////////////////////////////////// + /// \brief Grab or release the mouse cursor + /// + /// This is not to be confused with setMouseCursorGrabbed. + /// Here m_cursorGrabbed is not modified; it is used, + /// for example, to release the cursor when switching to + /// another application. + /// + /// \param grabbed True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + void grabCursor(bool grabbed); + + //////////////////////////////////////////////////////////// /// \brief Convert a Win32 virtual key code to a SFML key code /// /// \param key Virtual key code to convert @@ -252,6 +273,8 @@ private: bool m_resizing; ///< Is the window being resized? Uint16 m_surrogate; ///< First half of the surrogate pair, in case we're receiving a Unicode character in two events bool m_mouseInside; ///< Mouse is inside the window? + bool m_fullscreen; ///< Is the window fullscreen? + bool m_cursorGrabbed; ///< Is the mouse cursor trapped? }; } // namespace priv diff --git a/src/SFML/Window/Window.cpp b/src/SFML/Window/Window.cpp index a091325..70cb418 100644 --- a/src/SFML/Window/Window.cpp +++ b/src/SFML/Window/Window.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -289,6 +289,14 @@ void Window::setMouseCursorVisible(bool visible) //////////////////////////////////////////////////////////// +void Window::setMouseCursorGrabbed(bool grabbed) +{ + if (m_impl) + m_impl->setMouseCursorGrabbed(grabbed); +} + + +//////////////////////////////////////////////////////////// void Window::setKeyRepeatEnabled(bool enabled) { if (m_impl) diff --git a/src/SFML/Window/WindowImpl.cpp b/src/SFML/Window/WindowImpl.cpp index 679aaed..e7133e1 100644 --- a/src/SFML/Window/WindowImpl.cpp +++ b/src/SFML/Window/WindowImpl.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/WindowImpl.hpp b/src/SFML/Window/WindowImpl.hpp index 1e07a0f..1243506 100644 --- a/src/SFML/Window/WindowImpl.hpp +++ b/src/SFML/Window/WindowImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -187,6 +187,14 @@ public: virtual void setMouseCursorVisible(bool visible) = 0; //////////////////////////////////////////////////////////// + /// \brief Grab or release the mouse cursor and keeps it from leaving + /// + /// \param grabbed True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursorGrabbed(bool grabbed) = 0; + + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// /// \param enabled True to enable, false to disable diff --git a/src/SFML/Window/iOS/EaglContext.hpp b/src/SFML/Window/iOS/EaglContext.hpp index 1ad457f..a3c48ea 100644 --- a/src/SFML/Window/iOS/EaglContext.hpp +++ b/src/SFML/Window/iOS/EaglContext.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/EaglContext.mm b/src/SFML/Window/iOS/EaglContext.mm index 380c139..e033718 100644 --- a/src/SFML/Window/iOS/EaglContext.mm +++ b/src/SFML/Window/iOS/EaglContext.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/InputImpl.hpp b/src/SFML/Window/iOS/InputImpl.hpp index 43733cb..8c89dcb 100644 --- a/src/SFML/Window/iOS/InputImpl.hpp +++ b/src/SFML/Window/iOS/InputImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/InputImpl.mm b/src/SFML/Window/iOS/InputImpl.mm index b8dd103..c6cccaa 100644 --- a/src/SFML/Window/iOS/InputImpl.mm +++ b/src/SFML/Window/iOS/InputImpl.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/JoystickImpl.hpp b/src/SFML/Window/iOS/JoystickImpl.hpp index 59f31f2..47f8517 100644 --- a/src/SFML/Window/iOS/JoystickImpl.hpp +++ b/src/SFML/Window/iOS/JoystickImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/JoystickImpl.mm b/src/SFML/Window/iOS/JoystickImpl.mm index 6821e03..240c700 100644 --- a/src/SFML/Window/iOS/JoystickImpl.mm +++ b/src/SFML/Window/iOS/JoystickImpl.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/ObjCType.hpp b/src/SFML/Window/iOS/ObjCType.hpp index 5b111d5..17cb1b4 100644 --- a/src/SFML/Window/iOS/ObjCType.hpp +++ b/src/SFML/Window/iOS/ObjCType.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SFAppDelegate.hpp b/src/SFML/Window/iOS/SFAppDelegate.hpp index cd20bfc..012e02e 100644 --- a/src/SFML/Window/iOS/SFAppDelegate.hpp +++ b/src/SFML/Window/iOS/SFAppDelegate.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SFAppDelegate.mm b/src/SFML/Window/iOS/SFAppDelegate.mm index 5908b4e..3284b9a 100644 --- a/src/SFML/Window/iOS/SFAppDelegate.mm +++ b/src/SFML/Window/iOS/SFAppDelegate.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SFMain.hpp b/src/SFML/Window/iOS/SFMain.hpp index f52857b..bcd3153 100644 --- a/src/SFML/Window/iOS/SFMain.hpp +++ b/src/SFML/Window/iOS/SFMain.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SFMain.mm b/src/SFML/Window/iOS/SFMain.mm index 0e9d481..81b2452 100644 --- a/src/SFML/Window/iOS/SFMain.mm +++ b/src/SFML/Window/iOS/SFMain.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SFView.hpp b/src/SFML/Window/iOS/SFView.hpp index 4804797..1066927 100644 --- a/src/SFML/Window/iOS/SFView.hpp +++ b/src/SFML/Window/iOS/SFView.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SFView.mm b/src/SFML/Window/iOS/SFView.mm index b818749..efe8d3e 100644 --- a/src/SFML/Window/iOS/SFView.mm +++ b/src/SFML/Window/iOS/SFView.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SFViewController.hpp b/src/SFML/Window/iOS/SFViewController.hpp index ecc8476..37a06aa 100644 --- a/src/SFML/Window/iOS/SFViewController.hpp +++ b/src/SFML/Window/iOS/SFViewController.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SFViewController.mm b/src/SFML/Window/iOS/SFViewController.mm index 0142297..a17f99c 100644 --- a/src/SFML/Window/iOS/SFViewController.mm +++ b/src/SFML/Window/iOS/SFViewController.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SensorImpl.hpp b/src/SFML/Window/iOS/SensorImpl.hpp index 0e3f211..cce8e44 100644 --- a/src/SFML/Window/iOS/SensorImpl.hpp +++ b/src/SFML/Window/iOS/SensorImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/SensorImpl.mm b/src/SFML/Window/iOS/SensorImpl.mm index 96e4c7a..7801a8f 100644 --- a/src/SFML/Window/iOS/SensorImpl.mm +++ b/src/SFML/Window/iOS/SensorImpl.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/VideoModeImpl.mm b/src/SFML/Window/iOS/VideoModeImpl.mm index dd3d134..d054adf 100644 --- a/src/SFML/Window/iOS/VideoModeImpl.mm +++ b/src/SFML/Window/iOS/VideoModeImpl.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. diff --git a/src/SFML/Window/iOS/WindowImplUIKit.hpp b/src/SFML/Window/iOS/WindowImplUIKit.hpp index 53c066e..444672c 100644 --- a/src/SFML/Window/iOS/WindowImplUIKit.hpp +++ b/src/SFML/Window/iOS/WindowImplUIKit.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -150,6 +150,14 @@ public: virtual void setMouseCursorVisible(bool visible); //////////////////////////////////////////////////////////// + /// \brief Clips or releases the mouse cursor + /// + /// \param grabbed True to enable, false to disable + /// + //////////////////////////////////////////////////////////// + virtual void setMouseCursorGrabbed(bool grabbed); + + //////////////////////////////////////////////////////////// /// \brief Enable or disable automatic key-repeat /// /// \param enabled True to enable, false to disable diff --git a/src/SFML/Window/iOS/WindowImplUIKit.mm b/src/SFML/Window/iOS/WindowImplUIKit.mm index 3e7c833..3abfc10 100644 --- a/src/SFML/Window/iOS/WindowImplUIKit.mm +++ b/src/SFML/Window/iOS/WindowImplUIKit.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// 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. @@ -184,6 +184,13 @@ void WindowImplUIKit::setMouseCursorVisible(bool visible) //////////////////////////////////////////////////////////// +void WindowImplUIKit::setMouseCursorGrabbed(bool grabbed) +{ + // Not applicable +} + + +//////////////////////////////////////////////////////////// void WindowImplUIKit::setKeyRepeatEnabled(bool enabled) { // Not applicable |