From 608b4fb28d68ea9ba251f31965f533d082cdd816 Mon Sep 17 00:00:00 2001
From: Stefan Schindler <stefan@boxbox.org>
Date: Fri, 8 May 2015 11:27:44 +0200
Subject: [PATCH 01/15] Only spawn Resized event when window size changes.

---
 src/SFML/Window/Unix/WindowImplX11.cpp | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp
index d8c26e06..9a1f4df6 100644
--- a/src/SFML/Window/Unix/WindowImplX11.cpp
+++ b/src/SFML/Window/Unix/WindowImplX11.cpp
@@ -1926,12 +1926,21 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
             if (passEvent(windowEvent, reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent)->window))
                 return false;
 
+            // X notifies about "window configuration events", which also includes moving a window only. Check
+            // for a different size and only spawn a Resized event when it differs.
             xcb_configure_notify_event_t* e = reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent);
-            Event event;
-            event.type        = Event::Resized;
-            event.size.width  = e->width;
-            event.size.height = e->height;
-            pushEvent(event);
+
+            if (e->width != m_previousSize.x || e->height != m_previousSize.y)
+            {
+                m_previousSize.x = e->width;
+                m_previousSize.y = e->height;
+
+                Event event;
+                event.type        = Event::Resized;
+                event.size.width  = e->width;
+                event.size.height = e->height;
+                pushEvent(event);
+            }
             break;
         }
 

From 46a625dde5cdc24057133f61c7594a3dcaf405ea Mon Sep 17 00:00:00 2001
From: Tiaan Louw <tiaanl@gmail.com>
Date: Tue, 31 Mar 2015 21:42:04 +0200
Subject: [PATCH 02/15] Make sure the window still exists before we access the
 dimensions on it

---
 src/SFML/Main/MainAndroid.cpp | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/SFML/Main/MainAndroid.cpp b/src/SFML/Main/MainAndroid.cpp
index 20694025..f6e2849e 100644
--- a/src/SFML/Main/MainAndroid.cpp
+++ b/src/SFML/Main/MainAndroid.cpp
@@ -386,13 +386,16 @@ static void onContentRectChanged(ANativeActivity* activity, const ARect* rect)
     sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);
     sf::Lock lock(states->mutex);
 
-    // Send an event to warn people about the window move/resize
-    sf::Event event;
-    event.type = sf::Event::Resized;
-    event.size.width = ANativeWindow_getWidth(states->window);
-    event.size.height = ANativeWindow_getHeight(states->window);
+    // Make sure the window still exists before we access the dimensions on it
+    if (states->window != NULL) {
+        // Send an event to warn people about the window move/resize
+        sf::Event event;
+        event.type = sf::Event::Resized;
+        event.size.width = ANativeWindow_getWidth(states->window);
+        event.size.height = ANativeWindow_getHeight(states->window);
 
-    states->forwardEvent(event);
+        states->forwardEvent(event);
+    }
 }
 
 

From d2adccfe2ea7a82bcfeccdbe4e0100704027df76 Mon Sep 17 00:00:00 2001
From: Tiaan Louw <tiaanl@gmail.com>
Date: Tue, 31 Mar 2015 23:27:59 +0200
Subject: [PATCH 03/15] Check Android API level

We check the API level before using constants that use API levels that
your device doesn't support.
---
 src/SFML/Main/MainAndroid.cpp | 56 ++++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 7 deletions(-)

diff --git a/src/SFML/Main/MainAndroid.cpp b/src/SFML/Main/MainAndroid.cpp
index f6e2849e..52e3816a 100644
--- a/src/SFML/Main/MainAndroid.cpp
+++ b/src/SFML/Main/MainAndroid.cpp
@@ -53,6 +53,27 @@ namespace sf
 {
 namespace priv
 {
+
+////////////////////////////////////////////////////////////
+int getAndroidApiLevel(ANativeActivity* activity)
+{
+    JNIEnv* lJNIEnv = activity->env;
+
+    jclass versionClass = lJNIEnv->FindClass("android/os/Build$VERSION");
+    if (versionClass == NULL)
+        return 0;
+
+    jfieldID sdkIntFieldID = lJNIEnv->GetStaticFieldID(versionClass, "SDK_INT", "I");
+    if (sdkIntFieldID == NULL)
+        return 0;
+    
+    jint sdkInt = 0;
+    sdkInt = lJNIEnv->GetStaticIntField(versionClass, sdkIntFieldID);
+    
+    return sdkInt;
+}
+
+
 ////////////////////////////////////////////////////////////
 ActivityStates* retrieveStates(ANativeActivity* activity)
 {
@@ -117,6 +138,9 @@ void* main(ActivityStates* states)
 ////////////////////////////////////////////////////////////
 void goToFullscreenMode(ANativeActivity* activity)
 {
+    // Get the current Android API level.
+    int apiLevel = sf::priv::getAndroidApiLevel(activity);
+
     // Hide the status bar
     ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_FULLSCREEN,
         AWINDOW_FLAG_FULLSCREEN);
@@ -137,17 +161,35 @@ void goToFullscreenMode(ANativeActivity* activity)
 
     jclass classView = lJNIEnv->FindClass("android/view/View");
 
-    jfieldID FieldSYSTEM_UI_FLAG_LOW_PROFILE = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_LOW_PROFILE", "I");
-    jint SYSTEM_UI_FLAG_LOW_PROFILE = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_LOW_PROFILE);
+    // Default flags
+    jint flags = 0;
+    
+    // API Level 14
+    if (apiLevel >= 14)
+    {
+        jfieldID FieldSYSTEM_UI_FLAG_LOW_PROFILE = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_LOW_PROFILE", "I");
+        jint SYSTEM_UI_FLAG_LOW_PROFILE = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_LOW_PROFILE);
+        flags |= SYSTEM_UI_FLAG_LOW_PROFILE;
+    }
 
-    jfieldID FieldSYSTEM_UI_FLAG_FULLSCREEN = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_FULLSCREEN", "I");
-    jint SYSTEM_UI_FLAG_FULLSCREEN = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_FULLSCREEN);
+    // API Level 16
+    if (apiLevel >= 16)
+    {
+        jfieldID FieldSYSTEM_UI_FLAG_FULLSCREEN = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_FULLSCREEN", "I");
+        jint SYSTEM_UI_FLAG_FULLSCREEN = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_FULLSCREEN);
+        flags |= SYSTEM_UI_FLAG_FULLSCREEN;
+    }
 
-    //jfieldID FieldSYSTEM_UI_FLAG_IMMERSIVE_STICKY  = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY", "I");
-    //jint SYSTEM_UI_FLAG_IMMERSIVE_STICKY = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+    // API Level 19
+    if (apiLevel >= 19)
+    {
+        jfieldID FieldSYSTEM_UI_FLAG_IMMERSIVE_STICKY  = lJNIEnv->GetStaticFieldID(classView, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY", "I");
+        jint SYSTEM_UI_FLAG_IMMERSIVE_STICKY = lJNIEnv->GetStaticIntField(classView, FieldSYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+        flags |= SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+    }
 
     jmethodID methodsetSystemUiVisibility = lJNIEnv->GetMethodID(classView, "setSystemUiVisibility", "(I)V");
-    lJNIEnv->CallVoidMethod(objectDecorView, methodsetSystemUiVisibility, SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN | 0x00001000);
+    lJNIEnv->CallVoidMethod(objectDecorView, methodsetSystemUiVisibility, flags);
 }
 
 ////////////////////////////////////////////////////////////

From e38a26ec25bc3540eb6745a99d8db55a185e317c Mon Sep 17 00:00:00 2001
From: binary1248 <binary1248@hotmail.com>
Date: Mon, 11 May 2015 00:38:14 +0200
Subject: [PATCH 04/15] Corrected typo.

---
 src/SFML/Window/Unix/Display.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp
index 1cda4a7e..bddd9a7b 100644
--- a/src/SFML/Window/Unix/Display.hpp
+++ b/src/SFML/Window/Unix/Display.hpp
@@ -51,7 +51,7 @@ Display* OpenDisplay();
 /// \brief Get the xcb connection of the shared Display
 ///
 /// This function increments the reference count of the display,
-/// it must be matched with a call to CloseDisplay.
+/// it must be matched with a call to CloseConnection.
 ///
 /// \return Pointer to the shared connection
 ///

From 45577de60a172cd1c92a278320688736134a0ed1 Mon Sep 17 00:00:00 2001
From: binary1248 <binary1248@hotmail.com>
Date: Sun, 10 May 2015 17:04:01 +0200
Subject: [PATCH 05/15] Added support for GL_EXT_texture_edge_clamp as well
 since some GL implementations don't expose GL_SGIS_texture_edge_clamp even
 when clamp-to-edge functionality is supported. Fixes #880

---
 src/SFML/Graphics/GLExtensions.hpp |  4 ++++
 src/SFML/Graphics/GLExtensions.txt |  1 +
 src/SFML/Graphics/GLLoader.cpp     |  7 +++++--
 src/SFML/Graphics/GLLoader.hpp     |  3 +++
 src/SFML/Graphics/Texture.cpp      | 16 ++++++++++------
 5 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/SFML/Graphics/GLExtensions.hpp b/src/SFML/Graphics/GLExtensions.hpp
index 7cff5947..52195a19 100644
--- a/src/SFML/Graphics/GLExtensions.hpp
+++ b/src/SFML/Graphics/GLExtensions.hpp
@@ -45,6 +45,7 @@
     // Core since 1.0
     #define GLEXT_multitexture                        true
     #define GLEXT_texture_edge_clamp                  true
+    #define GLEXT_EXT_texture_edge_clamp              true
     #define GLEXT_blend_minmax                        true
     #define GLEXT_glClientActiveTexture               glClientActiveTexture
     #define GLEXT_glActiveTexture                     glActiveTexture
@@ -130,6 +131,9 @@
     #define GLEXT_texture_edge_clamp                  sfogl_ext_SGIS_texture_edge_clamp
     #define GLEXT_GL_CLAMP_TO_EDGE                    GL_CLAMP_TO_EDGE_SGIS
 
+    // Core since 1.2 - EXT_texture_edge_clamp
+    #define GLEXT_EXT_texture_edge_clamp              sfogl_ext_EXT_texture_edge_clamp
+
     // Core since 1.2 - EXT_blend_minmax
     #define GLEXT_blend_minmax                        sfogl_ext_EXT_blend_minmax
     #define GLEXT_glBlendEquation                     glBlendEquationEXT
diff --git a/src/SFML/Graphics/GLExtensions.txt b/src/SFML/Graphics/GLExtensions.txt
index 5f2b5b33..033404d2 100644
--- a/src/SFML/Graphics/GLExtensions.txt
+++ b/src/SFML/Graphics/GLExtensions.txt
@@ -4,6 +4,7 @@
 // lua LoadGen.lua -style=pointer_c -spec=gl -version=1.1 -indent=space -prefix=sf -extfile=GLExtensions.txt GLLoader
 
 SGIS_texture_edge_clamp
+//EXT_texture_edge_clamp
 EXT_blend_minmax
 EXT_blend_subtract
 ARB_multitexture
diff --git a/src/SFML/Graphics/GLLoader.cpp b/src/SFML/Graphics/GLLoader.cpp
index cceab2f4..e82cd7a2 100644
--- a/src/SFML/Graphics/GLLoader.cpp
+++ b/src/SFML/Graphics/GLLoader.cpp
@@ -50,6 +50,7 @@ static sf::GlFunctionPointer IntGetProcAddress(const char* name)
 }
 
 int sfogl_ext_SGIS_texture_edge_clamp = sfogl_LOAD_FAILED;
+int sfogl_ext_EXT_texture_edge_clamp = sfogl_LOAD_FAILED;
 int sfogl_ext_EXT_blend_minmax = sfogl_LOAD_FAILED;
 int sfogl_ext_EXT_blend_subtract = sfogl_LOAD_FAILED;
 int sfogl_ext_ARB_multitexture = sfogl_LOAD_FAILED;
@@ -317,8 +318,9 @@ typedef struct sfogl_StrToExtMap_s
     PFN_LOADFUNCPOINTERS LoadExtension;
 } sfogl_StrToExtMap;
 
-static sfogl_StrToExtMap ExtensionMap[12] = {
+static sfogl_StrToExtMap ExtensionMap[13] = {
     {"GL_SGIS_texture_edge_clamp", &sfogl_ext_SGIS_texture_edge_clamp, NULL},
+    {"GL_EXT_texture_edge_clamp", &sfogl_ext_EXT_texture_edge_clamp, NULL},
     {"GL_EXT_blend_minmax", &sfogl_ext_EXT_blend_minmax, Load_EXT_blend_minmax},
     {"GL_EXT_blend_subtract", &sfogl_ext_EXT_blend_subtract, NULL},
     {"GL_ARB_multitexture", &sfogl_ext_ARB_multitexture, Load_ARB_multitexture},
@@ -332,7 +334,7 @@ static sfogl_StrToExtMap ExtensionMap[12] = {
     {"GL_EXT_framebuffer_object", &sfogl_ext_EXT_framebuffer_object, Load_EXT_framebuffer_object}
 };
 
-static int g_extensionMapSize = 12;
+static int g_extensionMapSize = 13;
 
 static sfogl_StrToExtMap *FindExtEntry(const char *extensionName)
 {
@@ -350,6 +352,7 @@ static sfogl_StrToExtMap *FindExtEntry(const char *extensionName)
 static void ClearExtensionVars()
 {
     sfogl_ext_SGIS_texture_edge_clamp = sfogl_LOAD_FAILED;
+    sfogl_ext_EXT_texture_edge_clamp = sfogl_LOAD_FAILED;
     sfogl_ext_EXT_blend_minmax = sfogl_LOAD_FAILED;
     sfogl_ext_EXT_blend_subtract = sfogl_LOAD_FAILED;
     sfogl_ext_ARB_multitexture = sfogl_LOAD_FAILED;
diff --git a/src/SFML/Graphics/GLLoader.hpp b/src/SFML/Graphics/GLLoader.hpp
index 42e1e093..00064065 100644
--- a/src/SFML/Graphics/GLLoader.hpp
+++ b/src/SFML/Graphics/GLLoader.hpp
@@ -174,6 +174,7 @@ extern "C" {
 #endif /*__cplusplus*/
 
 extern int sfogl_ext_SGIS_texture_edge_clamp;
+extern int sfogl_ext_EXT_texture_edge_clamp;
 extern int sfogl_ext_EXT_blend_minmax;
 extern int sfogl_ext_EXT_blend_subtract;
 extern int sfogl_ext_ARB_multitexture;
@@ -188,6 +189,8 @@ extern int sfogl_ext_EXT_framebuffer_object;
 
 #define GL_CLAMP_TO_EDGE_SGIS 0x812F
 
+#define GL_CLAMP_TO_EDGE_EXT 0x812F
+
 #define GL_BLEND_EQUATION_EXT 0x8009
 #define GL_FUNC_ADD_EXT 0x8006
 #define GL_MAX_EXT 0x8008
diff --git a/src/SFML/Graphics/Texture.cpp b/src/SFML/Graphics/Texture.cpp
index a747a2db..610dfa2c 100644
--- a/src/SFML/Graphics/Texture.cpp
+++ b/src/SFML/Graphics/Texture.cpp
@@ -158,7 +158,9 @@ bool Texture::create(unsigned int width, unsigned int height)
     // Make sure that the current texture binding will be preserved
     priv::TextureSaver save;
 
-    if (!m_isRepeated && !GLEXT_texture_edge_clamp)
+    static bool textureEdgeClamp = GLEXT_texture_edge_clamp || GLEXT_EXT_texture_edge_clamp;
+
+    if (!m_isRepeated && !textureEdgeClamp)
     {
         static bool warned = false;
 
@@ -175,8 +177,8 @@ bool Texture::create(unsigned int width, unsigned int height)
     // Initialize the texture
     glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
     glCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_actualSize.x, m_actualSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
-    glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (GLEXT_texture_edge_clamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
-    glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (GLEXT_texture_edge_clamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
+    glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
+    glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
     glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
     glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
     m_cacheId = getUniqueId();
@@ -480,7 +482,9 @@ void Texture::setRepeated(bool repeated)
             // Make sure that the current texture binding will be preserved
             priv::TextureSaver save;
 
-            if (!m_isRepeated && !GLEXT_texture_edge_clamp)
+            static bool textureEdgeClamp = GLEXT_texture_edge_clamp || GLEXT_EXT_texture_edge_clamp;
+
+            if (!m_isRepeated && !textureEdgeClamp)
             {
                 static bool warned = false;
 
@@ -495,8 +499,8 @@ void Texture::setRepeated(bool repeated)
             }
 
             glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
-            glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (GLEXT_texture_edge_clamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
-            glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (GLEXT_texture_edge_clamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
+            glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
+            glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
         }
     }
 }

From 11e2901403116c4ab24cf7acc104111eccca8890 Mon Sep 17 00:00:00 2001
From: binary1248 <binary1248@hotmail.com>
Date: Sun, 10 May 2015 03:46:17 +0200
Subject: [PATCH 06/15] Whitelisted SHAPE events that might be sent by some
 compositing window managers even if we didn't select them. Fixes #879

---
 src/SFML/Window/Unix/WindowImplX11.cpp | 28 ++++++++++++++++----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp
index 9a1f4df6..07f27a85 100644
--- a/src/SFML/Window/Unix/WindowImplX11.cpp
+++ b/src/SFML/Window/Unix/WindowImplX11.cpp
@@ -237,21 +237,17 @@ namespace
         return true;
     }
 
-    xcb_query_extension_reply_t getDriExtension()
+    xcb_query_extension_reply_t getXExtension(const std::string& name)
     {
         xcb_connection_t* connection = sf::priv::OpenConnection();
 
         sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
-
-        // Check if the DRI2 extension is present
-        // We don't use xcb_get_extension_data here to avoid having to link to xcb_dri2
-        static const std::string DRI2 = "DRI2";
-        sf::priv::ScopedXcbPtr<xcb_query_extension_reply_t> driExt(xcb_query_extension_reply(
+        sf::priv::ScopedXcbPtr<xcb_query_extension_reply_t> extension(xcb_query_extension_reply(
             connection,
             xcb_query_extension(
                 connection,
-                DRI2.size(),
-                DRI2.c_str()
+                name.size(),
+                name.c_str()
             ),
             &error
         ));
@@ -259,14 +255,14 @@ namespace
         // Close the connection with the X server
         sf::priv::CloseConnection(connection);
 
-        if (error || !driExt || !driExt->present)
+        if (error || !extension || !extension->present)
         {
             xcb_query_extension_reply_t reply;
             std::memset(&reply, 0, sizeof(reply));
             return reply;
         }
 
-        return *driExt.get();
+        return *extension.get();
     }
 
     void dumpXcbExtensions()
@@ -2260,8 +2256,18 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
 
             // Handle any extension events first
 
+            // SHAPE
+            // Ubuntu's Unity desktop environment makes use of the
+            // Compiz compositing window manager
+            // Compiz seems to send SHAPE events to windows even if they
+            // did not specifically select those events
+            // We ignore those events here in order to not generate warnings
+            static xcb_query_extension_reply_t shapeExtension = getXExtension("SHAPE");
+            if (shapeExtension.present && (responseType == shapeExtension.first_event))
+                break;
+
             // DRI2
-            static xcb_query_extension_reply_t driExtension = getDriExtension();
+            static xcb_query_extension_reply_t driExtension = getXExtension("DRI2");
             if (driExtension.present)
             {
                 // Because we are using the XCB event queue instead of the Xlib event

From 717bd85537d734700edae7198b3d0fcfaf3ca82a Mon Sep 17 00:00:00 2001
From: Mario Liebisch <mario.liebisch@gmail.com>
Date: Tue, 12 May 2015 10:40:29 +0200
Subject: [PATCH 07/15] Android: Fixed audio files not loading (and possibly
 crashing) * Added a missing return value for Android's
 `sf::FileInputStream::open()`. * Added a missing return value for Android's
 `sf::priv::ResourceStream::seek()`. * Moved error logging for
 `sf::InputSoundFile` and `sf::OutputSoundFile` to `sf::SoundFileFactory`,
 since this allows more details on *why* reading/writing failed. Before
 missing files would return "format not supported".

---
 src/SFML/Audio/InputSoundFile.cpp          | 9 ---------
 src/SFML/Audio/OutputSoundFile.cpp         | 4 ----
 src/SFML/Audio/SoundFileFactory.cpp        | 9 ++++++++-
 src/SFML/System/Android/ResourceStream.cpp | 2 +-
 src/SFML/System/FileInputStream.cpp        | 1 +
 5 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/src/SFML/Audio/InputSoundFile.cpp b/src/SFML/Audio/InputSoundFile.cpp
index 2f281f56..ede0f478 100644
--- a/src/SFML/Audio/InputSoundFile.cpp
+++ b/src/SFML/Audio/InputSoundFile.cpp
@@ -65,10 +65,7 @@ bool InputSoundFile::openFromFile(const std::string& filename)
     // Find a suitable reader for the file type
     m_reader = SoundFileFactory::createReaderFromFilename(filename);
     if (!m_reader)
-    {
-        err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl;
         return false;
-    }
 
     // Wrap the file into a stream
     FileInputStream* file = new FileInputStream;
@@ -108,10 +105,7 @@ bool InputSoundFile::openFromMemory(const void* data, std::size_t sizeInBytes)
     // Find a suitable reader for the file type
     m_reader = SoundFileFactory::createReaderFromMemory(data, sizeInBytes);
     if (!m_reader)
-    {
-        err() << "Failed to open sound file from memory (format not supported)" << std::endl;
         return false;
-    }
 
     // Wrap the memory file into a stream
     MemoryInputStream* memory = new MemoryInputStream;
@@ -147,10 +141,7 @@ bool InputSoundFile::openFromStream(InputStream& stream)
     // Find a suitable reader for the file type
     m_reader = SoundFileFactory::createReaderFromStream(stream);
     if (!m_reader)
-    {
-        err() << "Failed to open sound file from stream (format not supported)" << std::endl;
         return false;
-    }
 
     // store the stream
     m_stream = &stream;
diff --git a/src/SFML/Audio/OutputSoundFile.cpp b/src/SFML/Audio/OutputSoundFile.cpp
index 5bb0e240..8f43ca76 100644
--- a/src/SFML/Audio/OutputSoundFile.cpp
+++ b/src/SFML/Audio/OutputSoundFile.cpp
@@ -28,7 +28,6 @@
 #include <SFML/Audio/OutputSoundFile.hpp>
 #include <SFML/Audio/SoundFileWriter.hpp>
 #include <SFML/Audio/SoundFileFactory.hpp>
-#include <SFML/System/Err.hpp>
 
 
 namespace sf
@@ -57,10 +56,7 @@ bool OutputSoundFile::openFromFile(const std::string& filename, unsigned int sam
     // Find a suitable writer for the file type
     m_writer = SoundFileFactory::createWriterFromFilename(filename);
     if (!m_writer)
-    {
-        err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl;
         return false;
-    }
 
     // Pass the stream to the reader
     if (!m_writer->open(filename, sampleRate, channelCount))
diff --git a/src/SFML/Audio/SoundFileFactory.cpp b/src/SFML/Audio/SoundFileFactory.cpp
index 02d4c99c..fa2811c8 100644
--- a/src/SFML/Audio/SoundFileFactory.cpp
+++ b/src/SFML/Audio/SoundFileFactory.cpp
@@ -34,6 +34,7 @@
 #include <SFML/Audio/SoundFileWriterWav.hpp>
 #include <SFML/System/FileInputStream.hpp>
 #include <SFML/System/MemoryInputStream.hpp>
+#include <SFML/System/Err.hpp>
 
 
 namespace
@@ -69,8 +70,10 @@ SoundFileReader* SoundFileFactory::createReaderFromFilename(const std::string& f
 
     // Wrap the input file into a file stream
     FileInputStream stream;
-    if (!stream.open(filename))
+    if (!stream.open(filename)) {
+        err() << "Failed to open sound file \"" << filename << "\" (couldn't open stream)" << std::endl;
         return NULL;
+    }
 
     // Test the filename in all the registered factories
     for (ReaderFactoryArray::const_iterator it = s_readers.begin(); it != s_readers.end(); ++it)
@@ -81,6 +84,7 @@ SoundFileReader* SoundFileFactory::createReaderFromFilename(const std::string& f
     }
 
     // No suitable reader found
+    err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl;
     return NULL;
 }
 
@@ -104,6 +108,7 @@ SoundFileReader* SoundFileFactory::createReaderFromMemory(const void* data, std:
     }
 
     // No suitable reader found
+    err() << "Failed to open sound file from memory (format not supported)" << std::endl;
     return NULL;
 }
 
@@ -123,6 +128,7 @@ SoundFileReader* SoundFileFactory::createReaderFromStream(InputStream& stream)
     }
 
     // No suitable reader found
+    err() << "Failed to open sound file from stream (format not supported)" << std::endl;
     return NULL;
 }
 
@@ -141,6 +147,7 @@ SoundFileWriter* SoundFileFactory::createWriterFromFilename(const std::string& f
     }
 
     // No suitable writer found
+    err() << "Failed to open sound file \"" << filename << "\" (format not supported)" << std::endl;
     return NULL;
 }
 
diff --git a/src/SFML/System/Android/ResourceStream.cpp b/src/SFML/System/Android/ResourceStream.cpp
index abfa29e6..fbc1ec4f 100644
--- a/src/SFML/System/Android/ResourceStream.cpp
+++ b/src/SFML/System/Android/ResourceStream.cpp
@@ -63,7 +63,7 @@ Int64 ResourceStream::read(void *data, Int64 size)
 ////////////////////////////////////////////////////////////
 Int64 ResourceStream::seek(Int64 position)
 {
-    AAsset_seek(m_file, position, SEEK_SET);
+    return AAsset_seek(m_file, position, SEEK_SET);
 }
 
 
diff --git a/src/SFML/System/FileInputStream.cpp b/src/SFML/System/FileInputStream.cpp
index dee021f2..bea0461d 100644
--- a/src/SFML/System/FileInputStream.cpp
+++ b/src/SFML/System/FileInputStream.cpp
@@ -61,6 +61,7 @@ bool FileInputStream::open(const std::string& filename)
     if (m_file)
         delete m_file;
     m_file = new sf::priv::ResourceStream(filename);
+    return m_file->tell() != -1;
 #else
     if (m_file)
         std::fclose(m_file);

From 1b1d92d6bba9894a89433f625d169abe5a3df996 Mon Sep 17 00:00:00 2001
From: Juhani Numminen <juhaninumminen0@gmail.com>
Date: Sat, 16 May 2015 08:52:10 +0300
Subject: [PATCH 08/15] Fix function name in short example snippet in
 RenderStates.hpp

---
 include/SFML/Graphics/RenderStates.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/SFML/Graphics/RenderStates.hpp b/include/SFML/Graphics/RenderStates.hpp
index b23a778e..3ab3271f 100644
--- a/include/SFML/Graphics/RenderStates.hpp
+++ b/include/SFML/Graphics/RenderStates.hpp
@@ -150,7 +150,7 @@ public:
 /// directly without defining render states explicitly -- the
 /// default set of states is ok in most cases.
 /// \code
-/// window.Draw(sprite);
+/// window.draw(sprite);
 /// \endcode
 ///
 /// If you want to use a single specific render state,

From 6cec9723387ff2c87f2109aa9cc5da53eb977fbd Mon Sep 17 00:00:00 2001
From: Jan Haller <bromeon@gmail.com>
Date: Wed, 20 May 2015 17:26:26 +0200
Subject: [PATCH 09/15] Removed unnecessary sf:: prefixes

---
 include/SFML/Audio/SoundRecorder.hpp    | 4 ++--
 include/SFML/Graphics/Font.hpp          | 2 +-
 include/SFML/Graphics/Shader.hpp        | 2 +-
 include/SFML/Graphics/Texture.hpp       | 2 +-
 include/SFML/System/FileInputStream.hpp | 2 +-
 include/SFML/Window/Joystick.hpp        | 2 +-
 src/SFML/Audio/SoundRecorder.cpp        | 4 ++--
 src/SFML/Graphics/Shader.cpp            | 4 ++--
 src/SFML/Graphics/Shape.cpp             | 2 +-
 src/SFML/Network/TcpSocket.cpp          | 2 +-
 src/SFML/System/FileInputStream.cpp     | 6 +++---
 11 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/include/SFML/Audio/SoundRecorder.hpp b/include/SFML/Audio/SoundRecorder.hpp
index ab0eb24e..964e4f3f 100644
--- a/include/SFML/Audio/SoundRecorder.hpp
+++ b/include/SFML/Audio/SoundRecorder.hpp
@@ -183,7 +183,7 @@ protected:
     /// \param interval Processing interval
     ///
     ////////////////////////////////////////////////////////////
-    void setProcessingInterval(sf::Time interval);
+    void setProcessingInterval(Time interval);
 
     ////////////////////////////////////////////////////////////
     /// \brief Start capturing audio data
@@ -260,7 +260,7 @@ private:
     Thread             m_thread;             ///< Thread running the background recording task
     std::vector<Int16> m_samples;            ///< Buffer to store captured samples
     unsigned int       m_sampleRate;         ///< Sample rate
-    sf::Time           m_processingInterval; ///< Time period between calls to onProcessSamples
+    Time               m_processingInterval; ///< Time period between calls to onProcessSamples
     bool               m_isCapturing;        ///< Capturing state
     std::string        m_deviceName;         ///< Name of the audio capture device
 };
diff --git a/include/SFML/Graphics/Font.hpp b/include/SFML/Graphics/Font.hpp
index 84eee27f..9d7c6841 100644
--- a/include/SFML/Graphics/Font.hpp
+++ b/include/SFML/Graphics/Font.hpp
@@ -278,7 +278,7 @@ private:
         Page();
 
         GlyphTable       glyphs;  ///< Table mapping code points to their corresponding glyph
-        sf::Texture      texture; ///< Texture containing the pixels of the glyphs
+        Texture          texture; ///< Texture containing the pixels of the glyphs
         unsigned int     nextRow; ///< Y position of the next new row in the texture
         std::vector<Row> rows;    ///< List containing the position of all the existing rows
     };
diff --git a/include/SFML/Graphics/Shader.hpp b/include/SFML/Graphics/Shader.hpp
index d3278f9b..55cc3bb7 100644
--- a/include/SFML/Graphics/Shader.hpp
+++ b/include/SFML/Graphics/Shader.hpp
@@ -399,7 +399,7 @@ public:
     /// \param transform Transform to assign
     ///
     ////////////////////////////////////////////////////////////
-    void setParameter(const std::string& name, const sf::Transform& transform);
+    void setParameter(const std::string& name, const Transform& transform);
 
     ////////////////////////////////////////////////////////////
     /// \brief Change a texture parameter of the shader
diff --git a/include/SFML/Graphics/Texture.hpp b/include/SFML/Graphics/Texture.hpp
index 421861e0..29260d18 100644
--- a/include/SFML/Graphics/Texture.hpp
+++ b/include/SFML/Graphics/Texture.hpp
@@ -187,7 +187,7 @@ public:
     /// \see loadFromFile, loadFromMemory, loadFromImage
     ///
     ////////////////////////////////////////////////////////////
-    bool loadFromStream(sf::InputStream& stream, const IntRect& area = IntRect());
+    bool loadFromStream(InputStream& stream, const IntRect& area = IntRect());
 
     ////////////////////////////////////////////////////////////
     /// \brief Load the texture from an image
diff --git a/include/SFML/System/FileInputStream.hpp b/include/SFML/System/FileInputStream.hpp
index 1afa9391..995351ca 100644
--- a/include/SFML/System/FileInputStream.hpp
+++ b/include/SFML/System/FileInputStream.hpp
@@ -123,7 +123,7 @@ private:
     // Member data
     ////////////////////////////////////////////////////////////
 #ifdef ANDROID
-    sf::priv::ResourceStream *m_file;
+    priv::ResourceStream* m_file;
 #else
     std::FILE* m_file; ///< stdio file stream
 #endif
diff --git a/include/SFML/Window/Joystick.hpp b/include/SFML/Window/Joystick.hpp
index 185fd76f..27f6291e 100644
--- a/include/SFML/Window/Joystick.hpp
+++ b/include/SFML/Window/Joystick.hpp
@@ -77,7 +77,7 @@ public:
     {
         Identification();
 
-        sf::String   name;      ///< Name of the joystick
+        String       name;      ///< Name of the joystick
         unsigned int vendorId;  ///< Manufacturer identifier
         unsigned int productId; ///< Product identifier
     };
diff --git a/src/SFML/Audio/SoundRecorder.cpp b/src/SFML/Audio/SoundRecorder.cpp
index 84a48545..f051b963 100644
--- a/src/SFML/Audio/SoundRecorder.cpp
+++ b/src/SFML/Audio/SoundRecorder.cpp
@@ -135,7 +135,7 @@ std::vector<std::string> SoundRecorder::getAvailableDevices()
 {
     std::vector<std::string> deviceNameList;
 
-    const ALchar *deviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
+    const ALchar* deviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
     if (deviceList)
     {
         while (*deviceList)
@@ -210,7 +210,7 @@ bool SoundRecorder::isAvailable()
 
 
 ////////////////////////////////////////////////////////////
-void SoundRecorder::setProcessingInterval(sf::Time interval)
+void SoundRecorder::setProcessingInterval(Time interval)
 {
     m_processingInterval = interval;
 }
diff --git a/src/SFML/Graphics/Shader.cpp b/src/SFML/Graphics/Shader.cpp
index 80ca28e1..5d87d10d 100644
--- a/src/SFML/Graphics/Shader.cpp
+++ b/src/SFML/Graphics/Shader.cpp
@@ -385,7 +385,7 @@ void Shader::setParameter(const std::string& name, const Color& color)
 
 
 ////////////////////////////////////////////////////////////
-void Shader::setParameter(const std::string& name, const sf::Transform& transform)
+void Shader::setParameter(const std::string& name, const Transform& transform)
 {
     if (m_shaderProgram)
     {
@@ -768,7 +768,7 @@ void Shader::setParameter(const std::string& name, const Color& color)
 
 
 ////////////////////////////////////////////////////////////
-void Shader::setParameter(const std::string& name, const sf::Transform& transform)
+void Shader::setParameter(const std::string& name, const Transform& transform)
 {
 }
 
diff --git a/src/SFML/Graphics/Shape.cpp b/src/SFML/Graphics/Shape.cpp
index 3487777d..5403b404 100644
--- a/src/SFML/Graphics/Shape.cpp
+++ b/src/SFML/Graphics/Shape.cpp
@@ -66,7 +66,7 @@ void Shape::setTexture(const Texture* texture, bool resetRect)
     if (texture)
     {
         // Recompute the texture area if requested, or if there was no texture & rect before
-        if (resetRect || (!m_texture && (m_textureRect == sf::IntRect())))
+        if (resetRect || (!m_texture && (m_textureRect == IntRect())))
             setTextureRect(IntRect(0, 0, texture->getSize().x, texture->getSize().y));
     }
 
diff --git a/src/SFML/Network/TcpSocket.cpp b/src/SFML/Network/TcpSocket.cpp
index 5a032efc..6476c534 100644
--- a/src/SFML/Network/TcpSocket.cpp
+++ b/src/SFML/Network/TcpSocket.cpp
@@ -179,7 +179,7 @@ Socket::Status TcpSocket::connect(const IpAddress& remoteAddress, unsigned short
             {
                 // At this point the connection may have been either accepted or refused.
                 // To know whether it's a success or a failure, we must check the address of the connected peer
-                if (getRemoteAddress() != sf::IpAddress::None)
+                if (getRemoteAddress() != IpAddress::None)
                 {
                     // Connection accepted
                     status = Done;
diff --git a/src/SFML/System/FileInputStream.cpp b/src/SFML/System/FileInputStream.cpp
index bea0461d..82f4d72c 100644
--- a/src/SFML/System/FileInputStream.cpp
+++ b/src/SFML/System/FileInputStream.cpp
@@ -60,7 +60,7 @@ bool FileInputStream::open(const std::string& filename)
 #ifdef ANDROID
     if (m_file)
         delete m_file;
-    m_file = new sf::priv::ResourceStream(filename);
+    m_file = new priv::ResourceStream(filename);
     return m_file->tell() != -1;
 #else
     if (m_file)
@@ -128,9 +128,9 @@ Int64 FileInputStream::getSize()
 #else
     if (m_file)
     {
-        sf::Int64 position = tell();
+        Int64 position = tell();
         std::fseek(m_file, 0, SEEK_END);
-        sf::Int64 size = tell();
+        Int64 size = tell();
         seek(position);
         return size;
     }

From 6de027f198e56947d89694049020de0893d374fc Mon Sep 17 00:00:00 2001
From: Jan Haller <bromeon@gmail.com>
Date: Sat, 23 May 2015 15:15:14 +0200
Subject: [PATCH 10/15] Clarified lifetime requirements of underlying resources
 for Music and Font

---
 include/SFML/Audio/Music.hpp   | 24 ++++++++++++++++--------
 include/SFML/Graphics/Font.hpp | 14 ++++++++++++--
 2 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/include/SFML/Audio/Music.hpp b/include/SFML/Audio/Music.hpp
index a5027244..76b4254e 100644
--- a/include/SFML/Audio/Music.hpp
+++ b/include/SFML/Audio/Music.hpp
@@ -69,6 +69,10 @@ public:
     /// See the documentation of sf::InputSoundFile for the list
     /// of supported formats.
     ///
+    /// \warning Since the music is not loaded at once but rather
+    /// streamed continuously, the file must remain accessible until
+    /// the sf::Music object loads a new music or is destroyed.
+    ///
     /// \param filename Path of the music file to open
     ///
     /// \return True if loading succeeded, false if it failed
@@ -85,10 +89,11 @@ public:
     /// to do so).
     /// See the documentation of sf::InputSoundFile for the list
     /// of supported formats.
-    /// Since the music is not loaded completely but rather streamed
-    /// continuously, the \a data must remain available as long as the
-    /// music is playing (i.e. you can't deallocate it right after calling
-    /// this function).
+    ///
+    /// \warning Since the music is not loaded at once but rather streamed
+    /// continuously, the \a data buffer must remain accessible until
+    /// the sf::Music object loads a new music or is destroyed. That is,
+    /// you can't deallocate the buffer right after calling this function.
     ///
     /// \param data        Pointer to the file data in memory
     /// \param sizeInBytes Size of the data to load, in bytes
@@ -107,10 +112,10 @@ public:
     /// to do so).
     /// See the documentation of sf::InputSoundFile for the list
     /// of supported formats.
-    /// Since the music is not loaded completely but rather streamed
-    /// continuously, the \a stream must remain alive as long as the
-    /// music is playing (i.e. you can't destroy it right after calling
-    /// this function).
+    ///
+    /// \warning Since the music is not loaded at once but rather
+    /// streamed continuously, the \a stream must remain accessible
+    /// until the sf::Music object loads a new music or is destroyed.
     ///
     /// \param stream Source stream to read from
     ///
@@ -184,6 +189,9 @@ private:
 /// musics that usually take hundreds of MB when they are
 /// uncompressed: by streaming it instead of loading it entirely,
 /// you avoid saturating the memory and have almost no loading delay.
+/// This implies that the underlying resource (file, stream or
+/// memory buffer) must remain valid for the lifetime of the
+/// sf::Music object.
 ///
 /// Apart from that, a sf::Music has almost the same features as
 /// the sf::SoundBuffer / sf::Sound pair: you can play/pause/stop
diff --git a/include/SFML/Graphics/Font.hpp b/include/SFML/Graphics/Font.hpp
index 9d7c6841..2b19d398 100644
--- a/include/SFML/Graphics/Font.hpp
+++ b/include/SFML/Graphics/Font.hpp
@@ -95,6 +95,10 @@ public:
     /// fonts installed on the user's system, thus you can't
     /// load them directly.
     ///
+    /// \warning SFML cannot preload all the font data in this
+    /// function, so the file has to remain accessible until
+    /// the sf::Font object loads a new font or is destroyed.
+    ///
     /// \param filename Path of the font file to load
     ///
     /// \return True if loading succeeded, false if it failed
@@ -109,9 +113,11 @@ public:
     ///
     /// The supported font formats are: TrueType, Type 1, CFF,
     /// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
-    /// Warning: SFML cannot preload all the font data in this
+    ///
+    /// \warning SFML cannot preload all the font data in this
     /// function, so the buffer pointed by \a data has to remain
-    /// valid as long as the font is used.
+    /// valid until the sf::Font object loads a new font or
+    /// is destroyed.
     ///
     /// \param data        Pointer to the file data in memory
     /// \param sizeInBytes Size of the data to load, in bytes
@@ -132,6 +138,10 @@ public:
     /// function, so the contents of \a stream have to remain
     /// valid as long as the font is used.
     ///
+    /// \warning SFML cannot preload all the font data in this
+    /// function, so the stream has to remain accessible until
+    /// the sf::Font object loads a new font or is destroyed.
+    ///
     /// \param stream Source stream to read from
     ///
     /// \return True if loading succeeded, false if it failed

From 0df1c97af741bd1659780ce8c150ed8d357e9a4e Mon Sep 17 00:00:00 2001
From: binary1248 <binary1248@hotmail.com>
Date: Sat, 23 May 2015 19:32:41 +0200
Subject: [PATCH 11/15] Fixed keyboard mapping not being correct after the user
 changes their keyboard layout while an SFML application is running. Fixes
 #895

---
 src/SFML/Window/Unix/Display.cpp       | 146 ++++++++---------
 src/SFML/Window/Unix/Display.hpp       |   6 +
 src/SFML/Window/Unix/InputImpl.cpp     | 216 +++++++++++++------------
 src/SFML/Window/Unix/InputImpl.hpp     |   6 +
 src/SFML/Window/Unix/WindowImplX11.cpp |  56 +++++++
 5 files changed, 251 insertions(+), 179 deletions(-)

diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp
index e537224c..cf1357db 100644
--- a/src/SFML/Window/Unix/Display.cpp
+++ b/src/SFML/Window/Unix/Display.cpp
@@ -145,77 +145,6 @@ namespace
 
         return keysym;
     }
-
-    void buildMap()
-    {
-        // Open a connection with the X server
-        xcb_connection_t* connection = sf::priv::OpenConnection();
-
-        firstKeycode = xcb_get_setup(connection)->min_keycode;
-        lastKeycode = xcb_get_setup(connection)->max_keycode;
-
-        sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
-
-        sf::priv::ScopedXcbPtr<xcb_get_keyboard_mapping_reply_t> keyboardMapping(xcb_get_keyboard_mapping_reply(
-            connection,
-            xcb_get_keyboard_mapping(
-                connection,
-                firstKeycode,
-                lastKeycode - firstKeycode + 1
-            ),
-            &error
-        ));
-
-        sf::priv::CloseConnection(connection);
-
-        if (error || !keyboardMapping)
-        {
-            sf::err() << "Failed to get keyboard mapping" << std::endl;
-            return;
-        }
-
-        uint8_t keysymsPerKeycode = keyboardMapping->keysyms_per_keycode;
-
-        if (!keysymsPerKeycode)
-        {
-            sf::err() << "Error: No keysyms per keycode" << std::endl;
-            return;
-        }
-
-        const xcb_keysym_t* keysyms = xcb_get_keyboard_mapping_keysyms(keyboardMapping.get());
-
-        if (!keysyms)
-        {
-            sf::err() << "Failed to get keyboard mapping keysyms" << std::endl;
-            return;
-        }
-
-        xcb_keycode_t range = lastKeycode - firstKeycode + 1;
-
-        std::fill(keysymMap, keysymMap + 256, XK_VoidSymbol);
-
-        for (xcb_keycode_t i = firstKeycode; ; ++i)
-        {
-            const xcb_keysym_t* keysym = &keysyms[(i - firstKeycode) * keysymsPerKeycode];
-
-            if ((keysymsPerKeycode == 1) || (keysym[1] == XCB_NO_SYMBOL))
-            {
-                keysymMap[i] = keysymToLower(keysym[0]);
-
-                if (i == lastKeycode)
-                    break;
-
-                continue;
-            }
-
-            keysymMap[i] = keysym[0];
-
-            if (i == lastKeycode)
-                break;
-        }
-
-        mapBuilt = true;
-    }
 }
 
 namespace sf
@@ -344,11 +273,84 @@ xcb_atom_t getAtom(const std::string& name, bool onlyIfExists)
 const xcb_keysym_t* getKeysymMap()
 {
     if (!mapBuilt)
-        buildMap();
+        buildKeysymMap();
 
     return keysymMap;
 }
 
+
+////////////////////////////////////////////////////////////
+void buildKeysymMap()
+{
+    // Open a connection with the X server
+    xcb_connection_t* connection = sf::priv::OpenConnection();
+
+    firstKeycode = xcb_get_setup(connection)->min_keycode;
+    lastKeycode = xcb_get_setup(connection)->max_keycode;
+
+    sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
+
+    sf::priv::ScopedXcbPtr<xcb_get_keyboard_mapping_reply_t> keyboardMapping(xcb_get_keyboard_mapping_reply(
+        connection,
+        xcb_get_keyboard_mapping(
+            connection,
+            firstKeycode,
+            lastKeycode - firstKeycode + 1
+        ),
+        &error
+    ));
+
+    sf::priv::CloseConnection(connection);
+
+    if (error || !keyboardMapping)
+    {
+        sf::err() << "Failed to get keyboard mapping" << std::endl;
+        return;
+    }
+
+    uint8_t keysymsPerKeycode = keyboardMapping->keysyms_per_keycode;
+
+    if (!keysymsPerKeycode)
+    {
+        sf::err() << "Error: No keysyms per keycode" << std::endl;
+        return;
+    }
+
+    const xcb_keysym_t* keysyms = xcb_get_keyboard_mapping_keysyms(keyboardMapping.get());
+
+    if (!keysyms)
+    {
+        sf::err() << "Failed to get keyboard mapping keysyms" << std::endl;
+        return;
+    }
+
+    xcb_keycode_t range = lastKeycode - firstKeycode + 1;
+
+    std::fill(keysymMap, keysymMap + 256, XK_VoidSymbol);
+
+    for (xcb_keycode_t i = firstKeycode; ; ++i)
+    {
+        const xcb_keysym_t* keysym = &keysyms[(i - firstKeycode) * keysymsPerKeycode];
+
+        if ((keysymsPerKeycode == 1) || (keysym[1] == XCB_NO_SYMBOL))
+        {
+            keysymMap[i] = keysymToLower(keysym[0]);
+
+            if (i == lastKeycode)
+                break;
+
+            continue;
+        }
+
+        keysymMap[i] = keysym[0];
+
+        if (i == lastKeycode)
+            break;
+    }
+
+    mapBuilt = true;
+}
+
 } // namespace priv
 
 } // namespace sf
diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp
index bddd9a7b..da29d510 100644
--- a/src/SFML/Window/Unix/Display.hpp
+++ b/src/SFML/Window/Unix/Display.hpp
@@ -127,6 +127,12 @@ xcb_atom_t getAtom(const std::string& name, bool onlyIfExists = false);
 ////////////////////////////////////////////////////////////
 const xcb_keysym_t* getKeysymMap();
 
+////////////////////////////////////////////////////////////
+/// \brief Build the keysym map
+///
+////////////////////////////////////////////////////////////
+void buildKeysymMap();
+
 } // namespace priv
 
 } // namespace sf
diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp
index 4d815f84..39491151 100644
--- a/src/SFML/Window/Unix/InputImpl.cpp
+++ b/src/SFML/Window/Unix/InputImpl.cpp
@@ -59,113 +59,6 @@ namespace
 
         return 255;
     }
-
-    void buildMap()
-    {
-        keycodeMap[sf::Keyboard::A]         = getKeycode(XK_a);
-        keycodeMap[sf::Keyboard::B]         = getKeycode(XK_b);
-        keycodeMap[sf::Keyboard::C]         = getKeycode(XK_c);
-        keycodeMap[sf::Keyboard::D]         = getKeycode(XK_d);
-        keycodeMap[sf::Keyboard::E]         = getKeycode(XK_e);
-        keycodeMap[sf::Keyboard::F]         = getKeycode(XK_f);
-        keycodeMap[sf::Keyboard::G]         = getKeycode(XK_g);
-        keycodeMap[sf::Keyboard::H]         = getKeycode(XK_h);
-        keycodeMap[sf::Keyboard::I]         = getKeycode(XK_i);
-        keycodeMap[sf::Keyboard::J]         = getKeycode(XK_j);
-        keycodeMap[sf::Keyboard::K]         = getKeycode(XK_k);
-        keycodeMap[sf::Keyboard::L]         = getKeycode(XK_l);
-        keycodeMap[sf::Keyboard::M]         = getKeycode(XK_m);
-        keycodeMap[sf::Keyboard::N]         = getKeycode(XK_n);
-        keycodeMap[sf::Keyboard::O]         = getKeycode(XK_o);
-        keycodeMap[sf::Keyboard::P]         = getKeycode(XK_p);
-        keycodeMap[sf::Keyboard::Q]         = getKeycode(XK_q);
-        keycodeMap[sf::Keyboard::R]         = getKeycode(XK_r);
-        keycodeMap[sf::Keyboard::S]         = getKeycode(XK_s);
-        keycodeMap[sf::Keyboard::T]         = getKeycode(XK_t);
-        keycodeMap[sf::Keyboard::U]         = getKeycode(XK_u);
-        keycodeMap[sf::Keyboard::V]         = getKeycode(XK_v);
-        keycodeMap[sf::Keyboard::W]         = getKeycode(XK_w);
-        keycodeMap[sf::Keyboard::X]         = getKeycode(XK_x);
-        keycodeMap[sf::Keyboard::Y]         = getKeycode(XK_y);
-        keycodeMap[sf::Keyboard::Z]         = getKeycode(XK_z);
-        keycodeMap[sf::Keyboard::Num0]      = getKeycode(XK_0);
-        keycodeMap[sf::Keyboard::Num1]      = getKeycode(XK_1);
-        keycodeMap[sf::Keyboard::Num2]      = getKeycode(XK_2);
-        keycodeMap[sf::Keyboard::Num3]      = getKeycode(XK_3);
-        keycodeMap[sf::Keyboard::Num4]      = getKeycode(XK_4);
-        keycodeMap[sf::Keyboard::Num5]      = getKeycode(XK_5);
-        keycodeMap[sf::Keyboard::Num6]      = getKeycode(XK_6);
-        keycodeMap[sf::Keyboard::Num7]      = getKeycode(XK_7);
-        keycodeMap[sf::Keyboard::Num8]      = getKeycode(XK_8);
-        keycodeMap[sf::Keyboard::Num9]      = getKeycode(XK_9);
-        keycodeMap[sf::Keyboard::Escape]    = getKeycode(XK_Escape);
-        keycodeMap[sf::Keyboard::LControl]  = getKeycode(XK_Control_L);
-        keycodeMap[sf::Keyboard::LShift]    = getKeycode(XK_Shift_L);
-        keycodeMap[sf::Keyboard::LAlt]      = getKeycode(XK_Alt_L);
-        keycodeMap[sf::Keyboard::LSystem]   = getKeycode(XK_Super_L);
-        keycodeMap[sf::Keyboard::RControl]  = getKeycode(XK_Control_R);
-        keycodeMap[sf::Keyboard::RShift]    = getKeycode(XK_Shift_R);
-        keycodeMap[sf::Keyboard::RAlt]      = getKeycode(XK_Alt_R);
-        keycodeMap[sf::Keyboard::RSystem]   = getKeycode(XK_Super_R);
-        keycodeMap[sf::Keyboard::Menu]      = getKeycode(XK_Menu);
-        keycodeMap[sf::Keyboard::LBracket]  = getKeycode(XK_bracketleft);
-        keycodeMap[sf::Keyboard::RBracket]  = getKeycode(XK_bracketright);
-        keycodeMap[sf::Keyboard::SemiColon] = getKeycode(XK_semicolon);
-        keycodeMap[sf::Keyboard::Comma]     = getKeycode(XK_comma);
-        keycodeMap[sf::Keyboard::Period]    = getKeycode(XK_period);
-        keycodeMap[sf::Keyboard::Quote]     = getKeycode(XK_apostrophe);
-        keycodeMap[sf::Keyboard::Slash]     = getKeycode(XK_slash);
-        keycodeMap[sf::Keyboard::BackSlash] = getKeycode(XK_backslash);
-        keycodeMap[sf::Keyboard::Tilde]     = getKeycode(XK_grave);
-        keycodeMap[sf::Keyboard::Equal]     = getKeycode(XK_equal);
-        keycodeMap[sf::Keyboard::Dash]      = getKeycode(XK_minus);
-        keycodeMap[sf::Keyboard::Space]     = getKeycode(XK_space);
-        keycodeMap[sf::Keyboard::Return]    = getKeycode(XK_Return);
-        keycodeMap[sf::Keyboard::BackSpace] = getKeycode(XK_BackSpace);
-        keycodeMap[sf::Keyboard::Tab]       = getKeycode(XK_Tab);
-        keycodeMap[sf::Keyboard::PageUp]    = getKeycode(XK_Prior);
-        keycodeMap[sf::Keyboard::PageDown]  = getKeycode(XK_Next);
-        keycodeMap[sf::Keyboard::End]       = getKeycode(XK_End);
-        keycodeMap[sf::Keyboard::Home]      = getKeycode(XK_Home);
-        keycodeMap[sf::Keyboard::Insert]    = getKeycode(XK_Insert);
-        keycodeMap[sf::Keyboard::Delete]    = getKeycode(XK_Delete);
-        keycodeMap[sf::Keyboard::Add]       = getKeycode(XK_KP_Add);
-        keycodeMap[sf::Keyboard::Subtract]  = getKeycode(XK_KP_Subtract);
-        keycodeMap[sf::Keyboard::Multiply]  = getKeycode(XK_KP_Multiply);
-        keycodeMap[sf::Keyboard::Divide]    = getKeycode(XK_KP_Divide);
-        keycodeMap[sf::Keyboard::Left]      = getKeycode(XK_Left);
-        keycodeMap[sf::Keyboard::Right]     = getKeycode(XK_Right);
-        keycodeMap[sf::Keyboard::Up]        = getKeycode(XK_Up);
-        keycodeMap[sf::Keyboard::Down]      = getKeycode(XK_Down);
-        keycodeMap[sf::Keyboard::Numpad0]   = getKeycode(XK_KP_0);
-        keycodeMap[sf::Keyboard::Numpad1]   = getKeycode(XK_KP_1);
-        keycodeMap[sf::Keyboard::Numpad2]   = getKeycode(XK_KP_2);
-        keycodeMap[sf::Keyboard::Numpad3]   = getKeycode(XK_KP_3);
-        keycodeMap[sf::Keyboard::Numpad4]   = getKeycode(XK_KP_4);
-        keycodeMap[sf::Keyboard::Numpad5]   = getKeycode(XK_KP_5);
-        keycodeMap[sf::Keyboard::Numpad6]   = getKeycode(XK_KP_6);
-        keycodeMap[sf::Keyboard::Numpad7]   = getKeycode(XK_KP_7);
-        keycodeMap[sf::Keyboard::Numpad8]   = getKeycode(XK_KP_8);
-        keycodeMap[sf::Keyboard::Numpad9]   = getKeycode(XK_KP_9);
-        keycodeMap[sf::Keyboard::F1]        = getKeycode(XK_F1);
-        keycodeMap[sf::Keyboard::F2]        = getKeycode(XK_F2);
-        keycodeMap[sf::Keyboard::F3]        = getKeycode(XK_F3);
-        keycodeMap[sf::Keyboard::F4]        = getKeycode(XK_F4);
-        keycodeMap[sf::Keyboard::F5]        = getKeycode(XK_F5);
-        keycodeMap[sf::Keyboard::F6]        = getKeycode(XK_F6);
-        keycodeMap[sf::Keyboard::F7]        = getKeycode(XK_F7);
-        keycodeMap[sf::Keyboard::F8]        = getKeycode(XK_F8);
-        keycodeMap[sf::Keyboard::F9]        = getKeycode(XK_F9);
-        keycodeMap[sf::Keyboard::F10]       = getKeycode(XK_F10);
-        keycodeMap[sf::Keyboard::F11]       = getKeycode(XK_F11);
-        keycodeMap[sf::Keyboard::F12]       = getKeycode(XK_F12);
-        keycodeMap[sf::Keyboard::F13]       = getKeycode(XK_F13);
-        keycodeMap[sf::Keyboard::F14]       = getKeycode(XK_F14);
-        keycodeMap[sf::Keyboard::F15]       = getKeycode(XK_F15);
-        keycodeMap[sf::Keyboard::Pause]     = getKeycode(XK_Pause);
-
-        mapBuilt = true;
-    }
 }
 
 
@@ -423,6 +316,115 @@ Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/, const Window& /*re
     return Vector2i();
 }
 
+
+////////////////////////////////////////////////////////////
+void InputImpl::buildMap()
+{
+    keycodeMap[sf::Keyboard::A]         = getKeycode(XK_a);
+    keycodeMap[sf::Keyboard::B]         = getKeycode(XK_b);
+    keycodeMap[sf::Keyboard::C]         = getKeycode(XK_c);
+    keycodeMap[sf::Keyboard::D]         = getKeycode(XK_d);
+    keycodeMap[sf::Keyboard::E]         = getKeycode(XK_e);
+    keycodeMap[sf::Keyboard::F]         = getKeycode(XK_f);
+    keycodeMap[sf::Keyboard::G]         = getKeycode(XK_g);
+    keycodeMap[sf::Keyboard::H]         = getKeycode(XK_h);
+    keycodeMap[sf::Keyboard::I]         = getKeycode(XK_i);
+    keycodeMap[sf::Keyboard::J]         = getKeycode(XK_j);
+    keycodeMap[sf::Keyboard::K]         = getKeycode(XK_k);
+    keycodeMap[sf::Keyboard::L]         = getKeycode(XK_l);
+    keycodeMap[sf::Keyboard::M]         = getKeycode(XK_m);
+    keycodeMap[sf::Keyboard::N]         = getKeycode(XK_n);
+    keycodeMap[sf::Keyboard::O]         = getKeycode(XK_o);
+    keycodeMap[sf::Keyboard::P]         = getKeycode(XK_p);
+    keycodeMap[sf::Keyboard::Q]         = getKeycode(XK_q);
+    keycodeMap[sf::Keyboard::R]         = getKeycode(XK_r);
+    keycodeMap[sf::Keyboard::S]         = getKeycode(XK_s);
+    keycodeMap[sf::Keyboard::T]         = getKeycode(XK_t);
+    keycodeMap[sf::Keyboard::U]         = getKeycode(XK_u);
+    keycodeMap[sf::Keyboard::V]         = getKeycode(XK_v);
+    keycodeMap[sf::Keyboard::W]         = getKeycode(XK_w);
+    keycodeMap[sf::Keyboard::X]         = getKeycode(XK_x);
+    keycodeMap[sf::Keyboard::Y]         = getKeycode(XK_y);
+    keycodeMap[sf::Keyboard::Z]         = getKeycode(XK_z);
+    keycodeMap[sf::Keyboard::Num0]      = getKeycode(XK_0);
+    keycodeMap[sf::Keyboard::Num1]      = getKeycode(XK_1);
+    keycodeMap[sf::Keyboard::Num2]      = getKeycode(XK_2);
+    keycodeMap[sf::Keyboard::Num3]      = getKeycode(XK_3);
+    keycodeMap[sf::Keyboard::Num4]      = getKeycode(XK_4);
+    keycodeMap[sf::Keyboard::Num5]      = getKeycode(XK_5);
+    keycodeMap[sf::Keyboard::Num6]      = getKeycode(XK_6);
+    keycodeMap[sf::Keyboard::Num7]      = getKeycode(XK_7);
+    keycodeMap[sf::Keyboard::Num8]      = getKeycode(XK_8);
+    keycodeMap[sf::Keyboard::Num9]      = getKeycode(XK_9);
+    keycodeMap[sf::Keyboard::Escape]    = getKeycode(XK_Escape);
+    keycodeMap[sf::Keyboard::LControl]  = getKeycode(XK_Control_L);
+    keycodeMap[sf::Keyboard::LShift]    = getKeycode(XK_Shift_L);
+    keycodeMap[sf::Keyboard::LAlt]      = getKeycode(XK_Alt_L);
+    keycodeMap[sf::Keyboard::LSystem]   = getKeycode(XK_Super_L);
+    keycodeMap[sf::Keyboard::RControl]  = getKeycode(XK_Control_R);
+    keycodeMap[sf::Keyboard::RShift]    = getKeycode(XK_Shift_R);
+    keycodeMap[sf::Keyboard::RAlt]      = getKeycode(XK_Alt_R);
+    keycodeMap[sf::Keyboard::RSystem]   = getKeycode(XK_Super_R);
+    keycodeMap[sf::Keyboard::Menu]      = getKeycode(XK_Menu);
+    keycodeMap[sf::Keyboard::LBracket]  = getKeycode(XK_bracketleft);
+    keycodeMap[sf::Keyboard::RBracket]  = getKeycode(XK_bracketright);
+    keycodeMap[sf::Keyboard::SemiColon] = getKeycode(XK_semicolon);
+    keycodeMap[sf::Keyboard::Comma]     = getKeycode(XK_comma);
+    keycodeMap[sf::Keyboard::Period]    = getKeycode(XK_period);
+    keycodeMap[sf::Keyboard::Quote]     = getKeycode(XK_apostrophe);
+    keycodeMap[sf::Keyboard::Slash]     = getKeycode(XK_slash);
+    keycodeMap[sf::Keyboard::BackSlash] = getKeycode(XK_backslash);
+    keycodeMap[sf::Keyboard::Tilde]     = getKeycode(XK_grave);
+    keycodeMap[sf::Keyboard::Equal]     = getKeycode(XK_equal);
+    keycodeMap[sf::Keyboard::Dash]      = getKeycode(XK_minus);
+    keycodeMap[sf::Keyboard::Space]     = getKeycode(XK_space);
+    keycodeMap[sf::Keyboard::Return]    = getKeycode(XK_Return);
+    keycodeMap[sf::Keyboard::BackSpace] = getKeycode(XK_BackSpace);
+    keycodeMap[sf::Keyboard::Tab]       = getKeycode(XK_Tab);
+    keycodeMap[sf::Keyboard::PageUp]    = getKeycode(XK_Prior);
+    keycodeMap[sf::Keyboard::PageDown]  = getKeycode(XK_Next);
+    keycodeMap[sf::Keyboard::End]       = getKeycode(XK_End);
+    keycodeMap[sf::Keyboard::Home]      = getKeycode(XK_Home);
+    keycodeMap[sf::Keyboard::Insert]    = getKeycode(XK_Insert);
+    keycodeMap[sf::Keyboard::Delete]    = getKeycode(XK_Delete);
+    keycodeMap[sf::Keyboard::Add]       = getKeycode(XK_KP_Add);
+    keycodeMap[sf::Keyboard::Subtract]  = getKeycode(XK_KP_Subtract);
+    keycodeMap[sf::Keyboard::Multiply]  = getKeycode(XK_KP_Multiply);
+    keycodeMap[sf::Keyboard::Divide]    = getKeycode(XK_KP_Divide);
+    keycodeMap[sf::Keyboard::Left]      = getKeycode(XK_Left);
+    keycodeMap[sf::Keyboard::Right]     = getKeycode(XK_Right);
+    keycodeMap[sf::Keyboard::Up]        = getKeycode(XK_Up);
+    keycodeMap[sf::Keyboard::Down]      = getKeycode(XK_Down);
+    keycodeMap[sf::Keyboard::Numpad0]   = getKeycode(XK_KP_0);
+    keycodeMap[sf::Keyboard::Numpad1]   = getKeycode(XK_KP_1);
+    keycodeMap[sf::Keyboard::Numpad2]   = getKeycode(XK_KP_2);
+    keycodeMap[sf::Keyboard::Numpad3]   = getKeycode(XK_KP_3);
+    keycodeMap[sf::Keyboard::Numpad4]   = getKeycode(XK_KP_4);
+    keycodeMap[sf::Keyboard::Numpad5]   = getKeycode(XK_KP_5);
+    keycodeMap[sf::Keyboard::Numpad6]   = getKeycode(XK_KP_6);
+    keycodeMap[sf::Keyboard::Numpad7]   = getKeycode(XK_KP_7);
+    keycodeMap[sf::Keyboard::Numpad8]   = getKeycode(XK_KP_8);
+    keycodeMap[sf::Keyboard::Numpad9]   = getKeycode(XK_KP_9);
+    keycodeMap[sf::Keyboard::F1]        = getKeycode(XK_F1);
+    keycodeMap[sf::Keyboard::F2]        = getKeycode(XK_F2);
+    keycodeMap[sf::Keyboard::F3]        = getKeycode(XK_F3);
+    keycodeMap[sf::Keyboard::F4]        = getKeycode(XK_F4);
+    keycodeMap[sf::Keyboard::F5]        = getKeycode(XK_F5);
+    keycodeMap[sf::Keyboard::F6]        = getKeycode(XK_F6);
+    keycodeMap[sf::Keyboard::F7]        = getKeycode(XK_F7);
+    keycodeMap[sf::Keyboard::F8]        = getKeycode(XK_F8);
+    keycodeMap[sf::Keyboard::F9]        = getKeycode(XK_F9);
+    keycodeMap[sf::Keyboard::F10]       = getKeycode(XK_F10);
+    keycodeMap[sf::Keyboard::F11]       = getKeycode(XK_F11);
+    keycodeMap[sf::Keyboard::F12]       = getKeycode(XK_F12);
+    keycodeMap[sf::Keyboard::F13]       = getKeycode(XK_F13);
+    keycodeMap[sf::Keyboard::F14]       = getKeycode(XK_F14);
+    keycodeMap[sf::Keyboard::F15]       = getKeycode(XK_F15);
+    keycodeMap[sf::Keyboard::Pause]     = getKeycode(XK_Pause);
+
+    mapBuilt = true;
+}
+
 } // namespace priv
 
 } // namespace sf
diff --git a/src/SFML/Window/Unix/InputImpl.hpp b/src/SFML/Window/Unix/InputImpl.hpp
index 9425c3df..ec4f11e9 100644
--- a/src/SFML/Window/Unix/InputImpl.hpp
+++ b/src/SFML/Window/Unix/InputImpl.hpp
@@ -158,6 +158,12 @@ public:
     ///
     ////////////////////////////////////////////////////////////
     static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
+
+    ////////////////////////////////////////////////////////////
+    /// \brief Build the SFML to X11 keymap
+    ///
+    ////////////////////////////////////////////////////////////
+    static void buildMap();
 };
 
 } // namespace priv
diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp
index 07f27a85..7d8f984a 100644
--- a/src/SFML/Window/Unix/WindowImplX11.cpp
+++ b/src/SFML/Window/Unix/WindowImplX11.cpp
@@ -28,6 +28,7 @@
 #include <SFML/Window/WindowStyle.hpp> // important to be included first (conflict with None)
 #include <SFML/Window/Unix/WindowImplX11.hpp>
 #include <SFML/Window/Unix/Display.hpp>
+#include <SFML/Window/Unix/InputImpl.hpp>
 #include <SFML/Window/Unix/ScopedXcbPtr.hpp>
 #include <SFML/System/Utf.hpp>
 #include <SFML/System/Err.hpp>
@@ -50,6 +51,10 @@
 #define XCB_DRI2_BUFFER_SWAP_COMPLETE 0
 #define XCB_DRI2_INVALIDATE_BUFFERS   1
 
+// So we don't have to require xcb xkb to be present
+#define XCB_XKB_NEW_KEYBOARD_NOTIFY 0
+#define XCB_XKB_MAP_NOTIFY 1
+
 #ifdef SFML_OPENGL_ES
     #include <SFML/Window/EglContext.hpp>
     typedef sf::priv::EglContext ContextType;
@@ -2317,6 +2322,57 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
                 }
             }
 
+            // XKEYBOARD
+            // When the X server sends us XKEYBOARD events, it means that
+            // the user probably changed the layout of their keyboard
+            // We update our keymaps in that case
+            static xcb_query_extension_reply_t xkeyboardExtension = getXExtension("XKEYBOARD");
+            if (xkeyboardExtension.present && (responseType == xkeyboardExtension.first_event))
+            {
+                // We do this so we don't have to include the xkb header for the struct declaration
+                uint8_t xkbType = reinterpret_cast<const uint8_t*>(windowEvent)[1];
+
+                // We only bother rebuilding our maps if the xkb mapping actually changes
+                if ((xkbType == XCB_XKB_NEW_KEYBOARD_NOTIFY) || (xkbType == XCB_XKB_MAP_NOTIFY))
+                {
+                    // keysym map
+                    buildKeysymMap();
+
+                    // keycode to SFML
+                    buildMap();
+
+                    // SFML to keycode
+                    InputImpl::buildMap();
+
+                    // XInputMethod expects keyboard mapping changes to be propagated to it
+                    // Same idea here as with the DRI2 events above
+
+                    // We lock/unlock the display to protect against concurrent access
+                    XLockDisplay(m_display);
+
+                    typedef Bool (*wireEventHandler)(Display*, XEvent*, xEvent*);
+
+                    // Probe for any handlers that are registered for this event type
+                    wireEventHandler handler = XESetWireToEvent(m_display, responseType, 0);
+
+                    if (handler)
+                    {
+                        // Restore the previous handler if one was registered
+                        XESetWireToEvent(m_display, responseType, handler);
+
+                        XEvent event;
+                        windowEvent->sequence = LastKnownRequestProcessed(m_display);
+
+                        // Pretend to be the Xlib event queue
+                        handler(m_display, &event, reinterpret_cast<xEvent*>(windowEvent));
+                    }
+
+                    XUnlockDisplay(m_display);
+                }
+
+                break;
+            }
+
             // Print any surprises to stderr (would be nice if people report when this happens)
             dumpUnhandledEvent(responseType);
 

From cadc4d801c038bf441e7f22ee0d88110b09d3b57 Mon Sep 17 00:00:00 2001
From: Pierre-Luc Perrier <pluc@the-pluc.net>
Date: Fri, 22 May 2015 15:11:14 +0200
Subject: [PATCH 12/15] Fix undefined behavior in ewmhSupported() caused by
 some window managers not null-terminating strings. Fixes #892

---
 src/SFML/Window/Unix/WindowImplX11.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp
index 7d8f984a..8387975c 100644
--- a/src/SFML/Window/Unix/WindowImplX11.cpp
+++ b/src/SFML/Window/Unix/WindowImplX11.cpp
@@ -235,9 +235,12 @@ namespace
 
         sf::priv::CloseConnection(connection);
 
-        const char* name = reinterpret_cast<const char*>(xcb_get_property_value(wmName.get()));
-
-        windowManagerName = name;
+        // It seems the wm name string reply is not necessarily
+        // null-terminated. The work around is to get its actual
+        // length to build a proper string
+        const char* begin = reinterpret_cast<const char*>(xcb_get_property_value(wmName.get()));
+        const char* end = begin + xcb_get_property_value_length(wmName.get());
+        windowManagerName = sf::String::fromUtf8(begin, end);
 
         return true;
     }

From 11357b354f620d26828c3b8bf8578ffeb40cb102 Mon Sep 17 00:00:00 2001
From: Mario Liebisch <mario.liebisch@gmail.com>
Date: Thu, 4 Jun 2015 16:55:58 +0200
Subject: [PATCH 13/15] Android: Updated the JNI/event handling code

* Local Java references are now freed after use.
* SFML is now able to consider (Android) events as unhandled and pass them.
* Hovering a pen over the screen no longer triggers movement events (untested).
---
 src/SFML/Window/Android/InputImpl.cpp         | 10 +++
 src/SFML/Window/Android/WindowImplAndroid.cpp | 73 +++++++++++--------
 src/SFML/Window/Android/WindowImplAndroid.hpp |  8 +-
 3 files changed, 55 insertions(+), 36 deletions(-)

diff --git a/src/SFML/Window/Android/InputImpl.cpp b/src/SFML/Window/Android/InputImpl.cpp
index 920587b2..8940b9e2 100644
--- a/src/SFML/Window/Android/InputImpl.cpp
+++ b/src/SFML/Window/Android/InputImpl.cpp
@@ -78,6 +78,7 @@ void InputImpl::setVirtualKeyboardVisible(bool visible)
         "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
     jobject INPUT_METHOD_SERVICE = lJNIEnv->GetStaticObjectField(ClassContext,
         FieldINPUT_METHOD_SERVICE);
+    lJNIEnv->DeleteLocalRef(ClassContext);
 
     // Runs getSystemService(Context.INPUT_METHOD_SERVICE)
     jclass ClassInputMethodManager =
@@ -86,6 +87,7 @@ void InputImpl::setVirtualKeyboardVisible(bool visible)
         "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
     jobject lInputMethodManager = lJNIEnv->CallObjectMethod(lNativeActivity,
         MethodGetSystemService, INPUT_METHOD_SERVICE);
+    lJNIEnv->DeleteLocalRef(INPUT_METHOD_SERVICE);
 
     // Runs getWindow().getDecorView()
     jmethodID MethodGetWindow = lJNIEnv->GetMethodID(ClassNativeActivity,
@@ -95,6 +97,8 @@ void InputImpl::setVirtualKeyboardVisible(bool visible)
     jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(ClassWindow,
         "getDecorView", "()Landroid/view/View;");
     jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow, MethodGetDecorView);
+    lJNIEnv->DeleteLocalRef(lWindow);
+    lJNIEnv->DeleteLocalRef(ClassWindow);
 
     if (visible)
     {
@@ -112,13 +116,19 @@ void InputImpl::setVirtualKeyboardVisible(bool visible)
             "getWindowToken", "()Landroid/os/IBinder;");
         jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView,
             MethodGetWindowToken);
+        lJNIEnv->DeleteLocalRef(ClassView);
 
         // lInputMethodManager.hideSoftInput(...)
         jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(ClassInputMethodManager,
             "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z");
         jboolean lRes = lJNIEnv->CallBooleanMethod(lInputMethodManager,
             MethodHideSoftInput, lBinder, lFlags);
+        lJNIEnv->DeleteLocalRef(lBinder);
     }
+    lJNIEnv->DeleteLocalRef(lNativeActivity);
+    lJNIEnv->DeleteLocalRef(ClassNativeActivity);
+    lJNIEnv->DeleteLocalRef(ClassInputMethodManager);
+    lJNIEnv->DeleteLocalRef(lDecorView);
 
     // Finished with the JVM
     lJavaVM->DetachCurrentThread();
diff --git a/src/SFML/Window/Android/WindowImplAndroid.cpp b/src/SFML/Window/Android/WindowImplAndroid.cpp
index 2c140b05..fb1906bb 100644
--- a/src/SFML/Window/Android/WindowImplAndroid.cpp
+++ b/src/SFML/Window/Android/WindowImplAndroid.cpp
@@ -33,9 +33,11 @@
 #include <SFML/System/Err.hpp>
 #include <android/looper.h>
 
-// Define missing constants
-#define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007
-#define AMOTION_EVENT_ACTION_SCROLL 0x00000008
+// Define missing constants for older API levels
+#if __ANDROID_API__ < 13
+    #define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007
+    #define AMOTION_EVENT_ACTION_SCROLL     0x00000008
+#endif
 
 ////////////////////////////////////////////////////////////
 // Private data
@@ -232,7 +234,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
         if (AInputQueue_preDispatchEvent(states->inputQueue, _event))
             return 1;
 
-        int32_t handled = 0;
+        int handled = 0;
 
         int32_t type = AInputEvent_getType(_event);
 
@@ -244,8 +246,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
             if ((action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_UP || action == AKEY_EVENT_ACTION_MULTIPLE) &&
                 key != AKEYCODE_VOLUME_UP && key != AKEYCODE_VOLUME_DOWN)
             {
-                processKeyEvent(_event, states);
-                handled = 1;
+                handled = processKeyEvent(_event, states);
             }
         }
         else if (type == AINPUT_EVENT_TYPE_MOTION)
@@ -256,16 +257,15 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
             {
                 case AMOTION_EVENT_ACTION_SCROLL:
                 {
-                    processScrollEvent(_event, states);
-                    handled = 1;
+                    handled = processScrollEvent(_event, states);
                     break;
                 }
 
-                case AMOTION_EVENT_ACTION_HOVER_MOVE:
+                // todo: should hover_move indeed trigger the event?
+                // case AMOTION_EVENT_ACTION_HOVER_MOVE:
                 case AMOTION_EVENT_ACTION_MOVE:
                 {
-                    processMotionEvent(_event, states);
-                    handled = 1;
+                    handled = processMotionEvent(_event, states);
                     break;
                 }
 
@@ -273,8 +273,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
                 case AMOTION_EVENT_ACTION_POINTER_DOWN:
                 case AMOTION_EVENT_ACTION_DOWN:
                 {
-                    processPointerEvent(true, _event, states);
-                    handled = 1;
+                    handled = processPointerEvent(true, _event, states);
                     break;
                 }
 
@@ -282,8 +281,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
                 case AMOTION_EVENT_ACTION_UP:
                 case AMOTION_EVENT_ACTION_CANCEL:
                 {
-                    processPointerEvent(false, _event, states);
-                    handled = 1;
+                    handled = processPointerEvent(false, _event, states);
                     break;
                 }
             }
@@ -298,7 +296,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data)
 
 
 ////////////////////////////////////////////////////////////
-void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states)
+int WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states)
 {
     // Prepare the Java virtual machine
     jint lResult;
@@ -314,8 +312,10 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
 
     lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs);
 
-    if (lResult == JNI_ERR)
+    if (lResult == JNI_ERR) {
         err() << "Failed to initialize JNI, couldn't get the Unicode value" << std::endl;
+        return 0;
+    }
 
     // Retrieve everything we need to create this MotionEvent in Java
     jlong downTime = AMotionEvent_getDownTime(_event);
@@ -340,6 +340,9 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
     jmethodID MethodGetAxisValue = lJNIEnv->GetMethodID(ClassMotionEvent, "getAxisValue", "(I)F");
     jfloat delta = lJNIEnv->CallFloatMethod(ObjectMotionEvent, MethodGetAxisValue, 0x00000001);
 
+    lJNIEnv->DeleteLocalRef(ClassMotionEvent);
+    lJNIEnv->DeleteLocalRef(ObjectMotionEvent);
+
     // Create and send our mouse wheel event
     Event event;
     event.type = Event::MouseWheelMoved;
@@ -351,11 +354,13 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates*
 
     // Detach this thread from the JVM
     lJavaVM->DetachCurrentThread();
+
+    return 1;
 }
 
 
 ////////////////////////////////////////////////////////////
-void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* states)
+int WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* states)
 {
     int32_t device = AInputEvent_getSource(_event);
     int32_t action = AKeyEvent_getAction(_event);
@@ -374,7 +379,7 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
     case AKEY_EVENT_ACTION_DOWN:
         event.type = Event::KeyPressed;
         forwardEvent(event);
-        break;
+        return 1;
     case AKEY_EVENT_ACTION_UP:
         event.type = Event::KeyReleased;
         forwardEvent(event);
@@ -385,7 +390,7 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
             event.text.unicode = unicode;
             forwardEvent(event);
         }
-        break;
+        return 1;
     case AKEY_EVENT_ACTION_MULTIPLE:
         // Since complex inputs don't get separate key down/up events
         // both have to be faked at once
@@ -400,27 +405,26 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta
         {
             // This is a unique sequence, which is not yet exposed in the NDK
             // http://code.google.com/p/android/issues/detail?id=33998
+            return 0;
         }
-        else
+        else if (int unicode = getUnicode(_event)) // This is a repeated sequence
         {
-            // This is a repeated sequence
-            if (int unicode = getUnicode(_event))
-            {
-                event.type = Event::TextEntered;
-                event.text.unicode = unicode;
+            event.type = Event::TextEntered;
+            event.text.unicode = unicode;
 
-                int32_t repeats = AKeyEvent_getRepeatCount(_event);
-                for (int32_t i = 0; i < repeats; ++i)
-                    forwardEvent(event);
-            }
+            int32_t repeats = AKeyEvent_getRepeatCount(_event);
+            for (int32_t i = 0; i < repeats; ++i)
+                forwardEvent(event);
+            return 1;
         }
         break;
     }
+    return 0;
 }
 
 
 ////////////////////////////////////////////////////////////
-void WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* states)
+int WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* states)
 {
     int32_t device = AInputEvent_getSource(_event);
     int32_t action = AMotionEvent_getAction(_event);
@@ -462,11 +466,12 @@ void WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates*
 
         forwardEvent(event);
      }
+    return 1;
 }
 
 
 ////////////////////////////////////////////////////////////
-void WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, ActivityStates* states)
+int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, ActivityStates* states)
 {
     int32_t device = AInputEvent_getSource(_event);
     int32_t action = AMotionEvent_getAction(_event);
@@ -525,6 +530,7 @@ void WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, Ac
     }
 
     forwardEvent(event);
+    return 1;
 }
 
 
@@ -693,6 +699,9 @@ int WindowImplAndroid::getUnicode(AInputEvent* event)
     jmethodID MethodGetUnicode = lJNIEnv->GetMethodID(ClassKeyEvent, "getUnicodeChar", "(I)I");
     int unicode = lJNIEnv->CallIntMethod(ObjectKeyEvent, MethodGetUnicode, metaState);
 
+    lJNIEnv->DeleteLocalRef(ClassKeyEvent);
+    lJNIEnv->DeleteLocalRef(ObjectKeyEvent);
+
     // Detach this thread from the JVM
     lJavaVM->DetachCurrentThread();
 
diff --git a/src/SFML/Window/Android/WindowImplAndroid.hpp b/src/SFML/Window/Android/WindowImplAndroid.hpp
index cdfb5217..fb05b35b 100644
--- a/src/SFML/Window/Android/WindowImplAndroid.hpp
+++ b/src/SFML/Window/Android/WindowImplAndroid.hpp
@@ -194,10 +194,10 @@ private:
     ////////////////////////////////////////////////////////////
     static int processEvent(int fd, int events, void* data);
 
-    static void processScrollEvent(AInputEvent* _event, ActivityStates* states);
-    static void processKeyEvent(AInputEvent* _event, ActivityStates* states);
-    static void processMotionEvent(AInputEvent* _event, ActivityStates* states);
-    static void processPointerEvent(bool isDown, AInputEvent* event, ActivityStates* states);
+    static int processScrollEvent(AInputEvent* _event, ActivityStates* states);
+    static int processKeyEvent(AInputEvent* _event, ActivityStates* states);
+    static int processMotionEvent(AInputEvent* _event, ActivityStates* states);
+    static int processPointerEvent(bool isDown, AInputEvent* event, ActivityStates* states);
 
     ////////////////////////////////////////////////////////////
     /// \brief Convert a Android key to SFML key code

From 2d56b412653c5df6624e1c139e94aa2086bd8183 Mon Sep 17 00:00:00 2001
From: binary1248 <binary1248@hotmail.com>
Date: Mon, 22 Jun 2015 11:47:32 +0200
Subject: [PATCH 14/15] Added 2.3.1 changes to changelog.

---
 changelog.txt | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/changelog.txt b/changelog.txt
index b4944c3c..c6bd6613 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,39 @@
+SFML 2.3.1
+==========
+
+Also available on the website: http://www.sfml-dev.org/changelog.php#sfml-2.3.1
+
+Window
+======
+
+Bugfixes
+--------
+* [Android] Make sure a window still exists before trying to access its dimensions (#854)
+* [Android] Added Android API level checks (#856)
+* [Android] Updated the JNI/event handling code (#906)
+* [Linux] Resized events are only spawned when the window size actually changes (#878, #893)
+* [Linux] Whitelisted X SHAPE events (#879, #883)
+* [Linux] Remap Unix keyboard when user changes layout (#895, #897)
+* [Linux] Fix undefined behavior in ewmhSupported() (#892, #901)
+
+
+Graphics
+========
+
+Bugfixes
+--------
+* Added support for GL_EXT_texture_edge_clamp for systems that don't expose GL_SGIS_texture_edge_clamp (#880, #882)
+
+
+Audio
+=====
+
+Bugfixes
+--------
+* [Android] Fixed audio files not loading (and possibly crashing) (#855, #887)
+
+
+
 SFML 2.3
 ========
 

From b735777c4ade9d9b184576e664a4a26d7cdd8ecd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lukas=20D=C3=BCrrenberger?= <eXpl0it3r@sfml-dev.org>
Date: Fri, 22 May 2015 19:52:06 +0200
Subject: [PATCH 15/15] Increased version to 2.3.1.

---
 CMakeLists.txt          | 2 +-
 include/SFML/Config.hpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8ac15c3c..ee11ead1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,7 +40,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake)
 # setup version numbers
 set(VERSION_MAJOR 2)
 set(VERSION_MINOR 3)
-set(VERSION_PATCH 0)
+set(VERSION_PATCH 1)
 
 # add the SFML header path
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
diff --git a/include/SFML/Config.hpp b/include/SFML/Config.hpp
index 58e97974..294f2826 100644
--- a/include/SFML/Config.hpp
+++ b/include/SFML/Config.hpp
@@ -31,7 +31,7 @@
 ////////////////////////////////////////////////////////////
 #define SFML_VERSION_MAJOR 2
 #define SFML_VERSION_MINOR 3
-#define SFML_VERSION_PATCH 0
+#define SFML_VERSION_PATCH 1
 
 
 ////////////////////////////////////////////////////////////