summaryrefslogtreecommitdiff
path: root/src/SFML/Window/Unix
diff options
context:
space:
mode:
authorJames Cowgill <james410@cowgill.org.uk>2014-12-09 20:21:40 +0000
committerJames Cowgill <james410@cowgill.org.uk>2014-12-09 20:21:40 +0000
commitfa21c65d0c764705cfc377bf0d0de08fac26874e (patch)
treedbc9e87bbd8684d15e79fc0c8b7a8985389c3b35 /src/SFML/Window/Unix
parentdd835931261c340acd5f0409341d13fa2670423e (diff)
Imported Upstream version 2.2.0+dfsg
Diffstat (limited to 'src/SFML/Window/Unix')
-rw-r--r--src/SFML/Window/Unix/Display.cpp78
-rw-r--r--src/SFML/Window/Unix/Display.hpp62
-rw-r--r--src/SFML/Window/Unix/GlxContext.cpp341
-rw-r--r--src/SFML/Window/Unix/GlxContext.hpp148
-rw-r--r--src/SFML/Window/Unix/InputImpl.cpp324
-rw-r--r--src/SFML/Window/Unix/InputImpl.hpp168
-rw-r--r--src/SFML/Window/Unix/JoystickImpl.cpp388
-rw-r--r--src/SFML/Window/Unix/JoystickImpl.hpp126
-rw-r--r--src/SFML/Window/Unix/SensorImpl.cpp88
-rw-r--r--src/SFML/Window/Unix/SensorImpl.hpp101
-rw-r--r--src/SFML/Window/Unix/VideoModeImpl.cpp176
-rw-r--r--src/SFML/Window/Unix/WindowImplX11.cpp1109
-rw-r--r--src/SFML/Window/Unix/WindowImplX11.hpp250
13 files changed, 3359 insertions, 0 deletions
diff --git a/src/SFML/Window/Unix/Display.cpp b/src/SFML/Window/Unix/Display.cpp
new file mode 100644
index 0000000..aad1b26
--- /dev/null
+++ b/src/SFML/Window/Unix/Display.cpp
@@ -0,0 +1,78 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/System/Err.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <cassert>
+#include <cstdlib>
+
+
+namespace
+{
+ // The shared display and its reference counter
+ Display* sharedDisplay = NULL;
+ unsigned int referenceCount = 0;
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+Display* OpenDisplay()
+{
+ if (referenceCount == 0)
+ {
+ sharedDisplay = XOpenDisplay(NULL);
+
+ // Opening display failed: The best we can do at the moment is to output a meaningful error message
+ // and cause an abnormal program termination
+ if (!sharedDisplay)
+ {
+ err() << "Failed to open X11 display; make sure the DISPLAY environment variable is set correctly" << std::endl;
+ std::abort();
+ }
+ }
+
+ referenceCount++;
+ return sharedDisplay;
+}
+
+
+////////////////////////////////////////////////////////////
+void CloseDisplay(Display* display)
+{
+ assert(display == sharedDisplay);
+
+ referenceCount--;
+ if (referenceCount == 0)
+ XCloseDisplay(display);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/Display.hpp b/src/SFML/Window/Unix/Display.hpp
new file mode 100644
index 0000000..df018b3
--- /dev/null
+++ b/src/SFML/Window/Unix/Display.hpp
@@ -0,0 +1,62 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_SHAREDDISPLAY_HPP
+#define SFML_SHAREDDISPLAY_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <X11/Xlib.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Get the shared Display
+///
+/// This function increments the reference count of the display,
+/// it must be matched with a call to CloseDisplay.
+///
+/// \return Pointer to the shared display
+///
+////////////////////////////////////////////////////////////
+Display* OpenDisplay();
+
+////////////////////////////////////////////////////////////
+/// \brief Release a reference to the shared
+///
+/// \param display Display to release
+///
+////////////////////////////////////////////////////////////
+void CloseDisplay(Display* display);
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SHAREDDISPLAY_HPP
diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp
new file mode 100644
index 0000000..eac6099
--- /dev/null
+++ b/src/SFML/Window/Unix/GlxContext.cpp
@@ -0,0 +1,341 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Unix/GlxContext.hpp>
+#include <SFML/Window/Unix/WindowImplX11.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <SFML/OpenGL.hpp>
+#include <SFML/System/Err.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+GlxContext::GlxContext(GlxContext* shared) :
+m_window (0),
+m_context (NULL),
+m_ownsWindow(true)
+{
+ // Open a connection with the X server
+ m_display = OpenDisplay();
+
+ // Create a dummy window (disabled and hidden)
+ int screen = DefaultScreen(m_display);
+ m_window = XCreateWindow(m_display,
+ RootWindow(m_display, screen),
+ 0, 0,
+ 1, 1,
+ 0,
+ DefaultDepth(m_display, screen),
+ InputOutput,
+ DefaultVisual(m_display, screen),
+ 0, NULL);
+
+ // Create the context
+ createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings());
+}
+
+
+////////////////////////////////////////////////////////////
+GlxContext::GlxContext(GlxContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) :
+m_window (0),
+m_context (NULL),
+m_ownsWindow(false)
+{
+ // Open a connection with the X server
+ // (important: must be the same display as the owner window)
+ m_display = OpenDisplay();
+
+ // Get the owner window and its device context
+ m_window = static_cast< ::Window>(owner->getSystemHandle());
+
+ // Create the context
+ if (m_window)
+ createContext(shared, bitsPerPixel, settings);
+}
+
+
+////////////////////////////////////////////////////////////
+GlxContext::GlxContext(GlxContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) :
+m_window (0),
+m_context (NULL),
+m_ownsWindow(true)
+{
+ // Open a connection with the X server
+ m_display = OpenDisplay();
+
+ // Create the hidden window
+ int screen = DefaultScreen(m_display);
+ m_window = XCreateWindow(m_display,
+ RootWindow(m_display, screen),
+ 0, 0,
+ width, height,
+ 0,
+ DefaultDepth(m_display, screen),
+ InputOutput,
+ DefaultVisual(m_display, screen),
+ 0, NULL);
+
+ // Create the context
+ createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings);
+}
+
+
+////////////////////////////////////////////////////////////
+GlxContext::~GlxContext()
+{
+ // Destroy the context
+ if (m_context)
+ {
+ if (glXGetCurrentContext() == m_context)
+ glXMakeCurrent(m_display, None, NULL);
+ glXDestroyContext(m_display, m_context);
+ }
+
+ // Destroy the window if we own it
+ if (m_window && m_ownsWindow)
+ {
+ XDestroyWindow(m_display, m_window);
+ XFlush(m_display);
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+bool GlxContext::makeCurrent()
+{
+ return m_context && glXMakeCurrent(m_display, m_window, m_context);
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::display()
+{
+ if (m_window)
+ glXSwapBuffers(m_display, m_window);
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::setVerticalSyncEnabled(bool enabled)
+{
+ const GLubyte* name = reinterpret_cast<const GLubyte*>("glXSwapIntervalSGI");
+ PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = reinterpret_cast<PFNGLXSWAPINTERVALSGIPROC>(glXGetProcAddress(name));
+ if (glXSwapIntervalSGI)
+ glXSwapIntervalSGI(enabled ? 1 : 0);
+}
+
+
+////////////////////////////////////////////////////////////
+XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPerPixel, const ContextSettings& settings)
+{
+ // Retrieve all the visuals
+ int count;
+ XVisualInfo* visuals = XGetVisualInfo(display, 0, NULL, &count);
+ if (visuals)
+ {
+ // Evaluate all the returned visuals, and pick the best one
+ int bestScore = 0xFFFF;
+ XVisualInfo bestVisual;
+ for (int i = 0; i < count; ++i)
+ {
+ // Check mandatory attributes
+ int doubleBuffer;
+ glXGetConfig(display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer);
+ if (!doubleBuffer)
+ continue;
+
+ // Extract the components of the current visual
+ int red, green, blue, alpha, depth, stencil, multiSampling, samples;
+ glXGetConfig(display, &visuals[i], GLX_RED_SIZE, &red);
+ glXGetConfig(display, &visuals[i], GLX_GREEN_SIZE, &green);
+ glXGetConfig(display, &visuals[i], GLX_BLUE_SIZE, &blue);
+ glXGetConfig(display, &visuals[i], GLX_ALPHA_SIZE, &alpha);
+ glXGetConfig(display, &visuals[i], GLX_DEPTH_SIZE, &depth);
+ glXGetConfig(display, &visuals[i], GLX_STENCIL_SIZE, &stencil);
+ glXGetConfig(display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
+ glXGetConfig(display, &visuals[i], GLX_SAMPLES_ARB, &samples);
+
+ // Evaluate the visual
+ int color = red + green + blue + alpha;
+ int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0);
+
+ // If it's better than the current best, make it the new best
+ if (score < bestScore)
+ {
+ bestScore = score;
+ bestVisual = visuals[i];
+ }
+ }
+
+ // Free the array of visuals
+ XFree(visuals);
+
+ return bestVisual;
+ }
+ else
+ {
+ // Should never happen...
+ err() << "No GLX visual found. You should check your graphics driver" << std::endl;
+
+ return XVisualInfo();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings)
+{
+ XVisualInfo* visualInfo = NULL;
+
+ // Save the creation settings
+ m_settings = settings;
+
+ // Get the context to share display lists with
+ GLXContext toShare = shared ? shared->m_context : NULL;
+
+ // Create the OpenGL context -- first try context versions >= 3.0 if it is requested (they require special code)
+ if (m_settings.majorVersion >= 3)
+ {
+ const GLubyte* name = reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB");
+ PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddress(name));
+ if (glXCreateContextAttribsARB)
+ {
+ // Select a GLXFB config that matches the requested context settings
+ int nbConfigs = 0;
+ int fbAttributes[] =
+ {
+ GLX_DEPTH_SIZE, static_cast<int>(settings.depthBits),
+ GLX_STENCIL_SIZE, static_cast<int>(settings.stencilBits),
+ GLX_SAMPLE_BUFFERS, settings.antialiasingLevel > 0,
+ GLX_SAMPLES, static_cast<int>(settings.antialiasingLevel),
+ GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8,
+ GLX_BLUE_SIZE, 8,
+ GLX_ALPHA_SIZE, bitsPerPixel == 32 ? 8 : 0,
+ GLX_DOUBLEBUFFER, True,
+ GLX_X_RENDERABLE, True,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_CONFIG_CAVEAT, GLX_NONE,
+ None
+ };
+ GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), fbAttributes, &nbConfigs);
+ if (configs && nbConfigs)
+ {
+ while (!m_context && (m_settings.majorVersion >= 3))
+ {
+ // Create the context
+ int attributes[] =
+ {
+ 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, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+ 0, 0
+ };
+ m_context = glXCreateContextAttribsARB(m_display, configs[0], toShare, true, attributes);
+
+ if (m_context)
+ {
+ // Ok: retrieve the config's visual
+ visualInfo = glXGetVisualFromFBConfig(m_display, configs[0]);
+ }
+ else
+ {
+ // If we couldn't create the context, lower the version number and try again -- stop at 3.0
+ // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care
+ if (m_settings.minorVersion > 0)
+ {
+ // If the minor version is not 0, we decrease it and try again
+ m_settings.minorVersion--;
+ }
+ else
+ {
+ // If the minor version is 0, we decrease the major version
+ m_settings.majorVersion--;
+ m_settings.minorVersion = 9;
+ }
+ }
+ }
+ XFree(configs);
+ }
+ }
+ }
+
+ // If the OpenGL >= 3.0 context failed or if we don't want one, create a regular OpenGL 1.x/2.x context
+ if (!m_context)
+ {
+ // set the context version to 2.0 (arbitrary)
+ m_settings.majorVersion = 2;
+ m_settings.minorVersion = 0;
+
+ // Retrieve the attributes of the target window
+ XWindowAttributes windowAttributes;
+ if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0)
+ {
+ err() << "Failed to get the window attributes" << std::endl;
+ return;
+ }
+
+ // Get its visual
+ XVisualInfo tpl;
+ tpl.screen = DefaultScreen(m_display);
+ tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
+ int nbVisuals = 0;
+ visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals);
+
+ // Create the context, using the target window's visual
+ m_context = glXCreateContext(m_display, visualInfo, toShare, true);
+ if (!m_context)
+ {
+ err() << "Failed to create an OpenGL context for this window" << std::endl;
+ return;
+ }
+ }
+
+ // Update the creation settings from the chosen format
+ int depth, stencil, multiSampling, samples;
+ glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth);
+ glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil);
+ glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
+ glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples);
+ 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);
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/GlxContext.hpp b/src/SFML/Window/Unix/GlxContext.hpp
new file mode 100644
index 0000000..0b5982f
--- /dev/null
+++ b/src/SFML/Window/Unix/GlxContext.hpp
@@ -0,0 +1,148 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_GLXCONTEXT_HPP
+#define SFML_GLXCONTEXT_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/GlContext.hpp>
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Linux (GLX) implementation of OpenGL contexts
+///
+////////////////////////////////////////////////////////////
+class GlxContext : public GlContext
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new default context
+ ///
+ /// \param shared Context to share the new one with (can be NULL)
+ ///
+ ////////////////////////////////////////////////////////////
+ GlxContext(GlxContext* shared);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context attached to a window
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param owner Pointer to the owner window
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ ///
+ ////////////////////////////////////////////////////////////
+ GlxContext(GlxContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a new context that embeds its own rendering target
+ ///
+ /// \param shared Context to share the new one with
+ /// \param settings Creation parameters
+ /// \param width Back buffer width, in pixels
+ /// \param height Back buffer height, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ GlxContext(GlxContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~GlxContext();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Activate the context as the current target for rendering
+ ///
+ /// \return True on success, false if any error happened
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool makeCurrent();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Display what has been rendered to the context so far
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void display();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable vertical synchronization
+ ///
+ /// Activating vertical synchronization will limit the number
+ /// of frames displayed to the refresh rate of the monitor.
+ /// This can avoid some visual artifacts, and limit the framerate
+ /// to a good value (but not constant across different computers).
+ ///
+ /// \param enabled True to enable v-sync, false to deactivate
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVerticalSyncEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Select the best GLX visual for a given set of settings
+ ///
+ /// \param display X display
+ /// \param bitsPerPixel Pixel depth, in bits per pixel
+ /// \param settings Requested context settings
+ ///
+ /// \return The best visual
+ ///
+ ////////////////////////////////////////////////////////////
+ static XVisualInfo selectBestVisual(::Display* display, unsigned int bitsPerPixel, const ContextSettings& settings);
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \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
+ ///
+ ////////////////////////////////////////////////////////////
+ void createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ ::Display* m_display; ///< Connection to the X server
+ ::Window m_window; ///< Window to which the context is attached
+ GLXContext m_context; ///< OpenGL context
+ bool m_ownsWindow; ///< Do we own the window associated to the context?
+};
+
+} // namespace priv
+
+} // namespace sf
+
+#endif // SFML_GLXCONTEXT_HPP
diff --git a/src/SFML/Window/Unix/InputImpl.cpp b/src/SFML/Window/Unix/InputImpl.cpp
new file mode 100644
index 0000000..8ff7697
--- /dev/null
+++ b/src/SFML/Window/Unix/InputImpl.cpp
@@ -0,0 +1,324 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Unix/InputImpl.hpp>
+#include <SFML/Window/Window.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool InputImpl::isKeyPressed(Keyboard::Key key)
+{
+ // Get the corresponding X11 keysym
+ KeySym keysym = 0;
+ switch (key)
+ {
+ case Keyboard::A: keysym = XK_A; break;
+ case Keyboard::B: keysym = XK_B; break;
+ case Keyboard::C: keysym = XK_C; break;
+ case Keyboard::D: keysym = XK_D; break;
+ case Keyboard::E: keysym = XK_E; break;
+ case Keyboard::F: keysym = XK_F; break;
+ case Keyboard::G: keysym = XK_G; break;
+ case Keyboard::H: keysym = XK_H; break;
+ case Keyboard::I: keysym = XK_I; break;
+ case Keyboard::J: keysym = XK_J; break;
+ case Keyboard::K: keysym = XK_K; break;
+ case Keyboard::L: keysym = XK_L; break;
+ case Keyboard::M: keysym = XK_M; break;
+ case Keyboard::N: keysym = XK_N; break;
+ case Keyboard::O: keysym = XK_O; break;
+ case Keyboard::P: keysym = XK_P; break;
+ case Keyboard::Q: keysym = XK_Q; break;
+ case Keyboard::R: keysym = XK_R; break;
+ case Keyboard::S: keysym = XK_S; break;
+ case Keyboard::T: keysym = XK_T; break;
+ case Keyboard::U: keysym = XK_U; break;
+ case Keyboard::V: keysym = XK_V; break;
+ case Keyboard::W: keysym = XK_W; break;
+ case Keyboard::X: keysym = XK_X; break;
+ case Keyboard::Y: keysym = XK_Y; break;
+ case Keyboard::Z: keysym = XK_Z; break;
+ case Keyboard::Num0: keysym = XK_0; break;
+ case Keyboard::Num1: keysym = XK_1; break;
+ case Keyboard::Num2: keysym = XK_2; break;
+ case Keyboard::Num3: keysym = XK_3; break;
+ case Keyboard::Num4: keysym = XK_4; break;
+ case Keyboard::Num5: keysym = XK_5; break;
+ case Keyboard::Num6: keysym = XK_6; break;
+ case Keyboard::Num7: keysym = XK_7; break;
+ case Keyboard::Num8: keysym = XK_8; break;
+ case Keyboard::Num9: keysym = XK_9; break;
+ case Keyboard::Escape: keysym = XK_Escape; break;
+ case Keyboard::LControl: keysym = XK_Control_L; break;
+ case Keyboard::LShift: keysym = XK_Shift_L; break;
+ case Keyboard::LAlt: keysym = XK_Alt_L; break;
+ case Keyboard::LSystem: keysym = XK_Super_L; break;
+ case Keyboard::RControl: keysym = XK_Control_R; break;
+ case Keyboard::RShift: keysym = XK_Shift_R; break;
+ case Keyboard::RAlt: keysym = XK_Alt_R; break;
+ case Keyboard::RSystem: keysym = XK_Super_R; break;
+ case Keyboard::Menu: keysym = XK_Menu; break;
+ case Keyboard::LBracket: keysym = XK_bracketleft; break;
+ case Keyboard::RBracket: keysym = XK_bracketright; break;
+ case Keyboard::SemiColon: keysym = XK_semicolon; break;
+ case Keyboard::Comma: keysym = XK_comma; break;
+ case Keyboard::Period: keysym = XK_period; break;
+ case Keyboard::Quote: keysym = XK_dead_acute; break;
+ case Keyboard::Slash: keysym = XK_slash; break;
+ case Keyboard::BackSlash: keysym = XK_backslash; break;
+ case Keyboard::Tilde: keysym = XK_dead_grave; break;
+ case Keyboard::Equal: keysym = XK_equal; break;
+ case Keyboard::Dash: keysym = XK_minus; break;
+ case Keyboard::Space: keysym = XK_space; break;
+ case Keyboard::Return: keysym = XK_Return; break;
+ case Keyboard::BackSpace: keysym = XK_BackSpace; break;
+ case Keyboard::Tab: keysym = XK_Tab; break;
+ case Keyboard::PageUp: keysym = XK_Prior; break;
+ case Keyboard::PageDown: keysym = XK_Next; break;
+ case Keyboard::End: keysym = XK_End; break;
+ case Keyboard::Home: keysym = XK_Home; break;
+ case Keyboard::Insert: keysym = XK_Insert; break;
+ case Keyboard::Delete: keysym = XK_Delete; break;
+ case Keyboard::Add: keysym = XK_KP_Add; break;
+ case Keyboard::Subtract: keysym = XK_KP_Subtract; break;
+ case Keyboard::Multiply: keysym = XK_KP_Multiply; break;
+ case Keyboard::Divide: keysym = XK_KP_Divide; break;
+ case Keyboard::Left: keysym = XK_Left; break;
+ case Keyboard::Right: keysym = XK_Right; break;
+ case Keyboard::Up: keysym = XK_Up; break;
+ case Keyboard::Down: keysym = XK_Down; break;
+ case Keyboard::Numpad0: keysym = XK_KP_0; break;
+ case Keyboard::Numpad1: keysym = XK_KP_1; break;
+ case Keyboard::Numpad2: keysym = XK_KP_2; break;
+ case Keyboard::Numpad3: keysym = XK_KP_3; break;
+ case Keyboard::Numpad4: keysym = XK_KP_4; break;
+ case Keyboard::Numpad5: keysym = XK_KP_5; break;
+ case Keyboard::Numpad6: keysym = XK_KP_6; break;
+ case Keyboard::Numpad7: keysym = XK_KP_7; break;
+ case Keyboard::Numpad8: keysym = XK_KP_8; break;
+ case Keyboard::Numpad9: keysym = XK_KP_9; break;
+ case Keyboard::F1: keysym = XK_F1; break;
+ case Keyboard::F2: keysym = XK_F2; break;
+ case Keyboard::F3: keysym = XK_F3; break;
+ case Keyboard::F4: keysym = XK_F4; break;
+ case Keyboard::F5: keysym = XK_F5; break;
+ case Keyboard::F6: keysym = XK_F6; break;
+ case Keyboard::F7: keysym = XK_F7; break;
+ case Keyboard::F8: keysym = XK_F8; break;
+ case Keyboard::F9: keysym = XK_F9; break;
+ case Keyboard::F10: keysym = XK_F10; break;
+ case Keyboard::F11: keysym = XK_F11; break;
+ case Keyboard::F12: keysym = XK_F12; break;
+ case Keyboard::F13: keysym = XK_F13; break;
+ case Keyboard::F14: keysym = XK_F14; break;
+ case Keyboard::F15: keysym = XK_F15; break;
+ case Keyboard::Pause: keysym = XK_Pause; break;
+ default: keysym = 0; break;
+ }
+
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ // Convert to keycode
+ KeyCode keycode = XKeysymToKeycode(display, keysym);
+ if (keycode != 0)
+ {
+ // Get the whole keyboard state
+ char keys[32];
+ XQueryKeymap(display, keys);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ // Check our keycode
+ return (keys[keycode / 8] & (1 << (keycode % 8))) != 0;
+ }
+ else
+ {
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ return false;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setVirtualKeyboardVisible(bool visible)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isMouseButtonPressed(Mouse::Button button)
+{
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ // we don't care about these but they are required
+ ::Window root, child;
+ int wx, wy;
+ int gx, gy;
+
+ unsigned int buttons = 0;
+ XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &wx, &wy, &buttons);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ switch (button)
+ {
+ case Mouse::Left: return buttons & Button1Mask;
+ case Mouse::Right: return buttons & Button3Mask;
+ case Mouse::Middle: return buttons & Button2Mask;
+ case Mouse::XButton1: return false; // not supported by X
+ case Mouse::XButton2: return false; // not supported by X
+ default: return false;
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition()
+{
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ // we don't care about these but they are required
+ ::Window root, child;
+ int x, y;
+ unsigned int buttons;
+
+ int gx = 0;
+ int gy = 0;
+ XQueryPointer(display, DefaultRootWindow(display), &root, &child, &gx, &gy, &x, &y, &buttons);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ return Vector2i(gx, gy);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition(const Window& relativeTo)
+{
+ WindowHandle handle = relativeTo.getSystemHandle();
+ if (handle)
+ {
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ // we don't care about these but they are required
+ ::Window root, child;
+ int gx, gy;
+ unsigned int buttons;
+
+ int x = 0;
+ int y = 0;
+ XQueryPointer(display, handle, &root, &child, &gx, &gy, &x, &y, &buttons);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+
+ return Vector2i(x, y);
+ }
+ else
+ {
+ return Vector2i();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position)
+{
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y);
+ XFlush(display);
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo)
+{
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+
+ WindowHandle handle = relativeTo.getSystemHandle();
+ if (handle)
+ {
+ XWarpPointer(display, None, handle, 0, 0, 0, 0, position.x, position.y);
+ XFlush(display);
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isTouchDown(unsigned int /*finger*/)
+{
+ // Not applicable
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/)
+{
+ // Not applicable
+ return Vector2i();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/, const Window& /*relativeTo*/)
+{
+ // Not applicable
+ return Vector2i();
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/InputImpl.hpp b/src/SFML/Window/Unix/InputImpl.hpp
new file mode 100644
index 0000000..32c8f21
--- /dev/null
+++ b/src/SFML/Window/Unix/InputImpl.hpp
@@ -0,0 +1,168 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_INPUTIMPLX11_HPP
+#define SFML_INPUTIMPLX11_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Keyboard.hpp>
+#include <SFML/Window/Mouse.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Linux (X11) implementation of inputs (keyboard + mouse)
+///
+////////////////////////////////////////////////////////////
+class InputImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a key is pressed
+ ///
+ /// \param key Key to check
+ ///
+ /// \return True if the key is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isKeyPressed(Keyboard::Key key);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the virtual keyboard
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setVirtualKeyboardVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a mouse button is pressed
+ ///
+ /// \param button Button to check
+ ///
+ /// \return True if the button is pressed, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isMouseButtonPressed(Mouse::Button button);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of the mouse in desktop coordinates
+ ///
+ /// This function returns the current position of the mouse
+ /// cursor, in global (desktop) coordinates.
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of the mouse in window coordinates
+ ///
+ /// This function returns the current position of the mouse
+ /// cursor, relative to the given window.
+ /// If no window is used, it returns desktop coordinates.
+ ///
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getMousePosition(const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the current position of the mouse in desktop coordinates
+ ///
+ /// This function sets the current position of the mouse
+ /// cursor in global (desktop) coordinates.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(const Vector2i& position);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Set the current position of the mouse in window coordinates
+ ///
+ /// This function sets the current position of the mouse
+ /// cursor, relative to the given window.
+ /// If no window is used, it sets the position in desktop coordinates.
+ ///
+ /// \param position New position of the mouse
+ /// \param relativeTo Reference window
+ ///
+ ////////////////////////////////////////////////////////////
+ static void setMousePosition(const Vector2i& position, const Window& relativeTo);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a touch event is currently down
+ ///
+ /// \param finger Finger index
+ ///
+ /// \return True if \a finger is currently touching the screen, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isTouchDown(unsigned int finger);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of a touch in desktop coordinates
+ ///
+ /// This function returns the current touch position
+ /// in global (desktop) coordinates.
+ ///
+ /// \param finger Finger index
+ ///
+ /// \return Current position of \a finger, or undefined if it's not down
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getTouchPosition(unsigned int finger);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the current position of a touch in window coordinates
+ ///
+ /// This function returns the current touch position
+ /// in global (desktop) coordinates.
+ ///
+ /// \param finger Finger index
+ /// \param relativeTo Reference window
+ ///
+ /// \return Current position of \a finger, or undefined if it's not down
+ ///
+ ////////////////////////////////////////////////////////////
+ static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_INPUTIMPLX11_HPP
diff --git a/src/SFML/Window/Unix/JoystickImpl.cpp b/src/SFML/Window/Unix/JoystickImpl.cpp
new file mode 100644
index 0000000..0b8d479
--- /dev/null
+++ b/src/SFML/Window/Unix/JoystickImpl.cpp
@@ -0,0 +1,388 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/JoystickImpl.hpp>
+#include <SFML/System/Err.hpp>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <libudev.h>
+#include <unistd.h>
+#include <cstdio>
+#include <cstdlib>
+#include <sstream>
+
+namespace
+{
+ int notifyFd = -1;
+ int inputFd = -1;
+ bool plugged[sf::Joystick::Count];
+
+ void updatePluggedList()
+ {
+ udev* udevContext = udev_new();
+
+ for (unsigned int i = 0; i < sf::Joystick::Count; ++i)
+ {
+ std::ostringstream name;
+ name << "js" << i;
+ std::string nameString = name.str();
+
+ int file = ::open(("/dev/input/" + nameString).c_str(), O_RDONLY);
+
+ if (file < 0)
+ {
+ plugged[i] = false;
+ continue;
+ }
+
+ ::close(file);
+
+ // Check if the device is really a joystick or an
+ // accelerometer by inspecting whether
+ // ID_INPUT_ACCELEROMETER is present
+ if (!udevContext)
+ {
+ // Go safe and assume it is if udev isn't available
+ plugged[i] = true;
+ continue;
+ }
+
+ udev_device* udevDevice = udev_device_new_from_subsystem_sysname(udevContext, "input", nameString.c_str());
+
+ if (!udevDevice)
+ {
+ // Go safe and assume it is if we can't get the device
+ plugged[i] = true;
+ continue;
+ }
+
+ if (udev_device_get_property_value(udevDevice, "ID_INPUT_ACCELEROMETER"))
+ {
+ // This device is an accelerometer
+ plugged[i] = false;
+ }
+ else
+ {
+ // This device is not an accelerometer
+ // Assume it's a joystick
+ plugged[i] = true;
+ }
+
+ udev_device_unref(udevDevice);
+ }
+
+ if (udevContext)
+ udev_unref(udevContext);
+ }
+
+ bool hasInotifyEvent()
+ {
+ fd_set descriptorSet;
+ FD_ZERO(&descriptorSet);
+ FD_SET(notifyFd, &descriptorSet);
+ timeval timeout = {0, 0};
+
+ return (select(notifyFd + 1, &descriptorSet, NULL, NULL, &timeout) > 0) &&
+ FD_ISSET(notifyFd, &descriptorSet);
+ }
+
+ // Get the joystick name
+ std::string getJoystickName(int file, unsigned int index)
+ {
+ // Get the name
+ char name[128];
+
+ if (ioctl(file, JSIOCGNAME(sizeof(name)), name) >= 0)
+ return std::string(name);
+
+ sf::err() << "Unable to get name for joystick at index " << index << std::endl;
+
+ return std::string("Unknown Joystick");
+ }
+
+ // Get a system attribute from a udev device as an unsigned int
+ unsigned int getUdevAttributeUint(udev_device* device, unsigned int index, const std::string& attributeName)
+ {
+ udev_device* udevDeviceParent = udev_device_get_parent_with_subsystem_devtype(device, "usb", "usb_device");
+
+ if (!udevDeviceParent)
+ {
+ sf::err() << "Unable to get joystick attribute. "
+ << "Could not find parent USB device for joystick at index " << index << "." << std::endl;
+ return 0;
+ }
+
+ const char* attributeString = udev_device_get_sysattr_value(udevDeviceParent, attributeName.c_str());
+
+ if (!attributeString)
+ {
+ sf::err() << "Unable to get joystick attribute '" << attributeName << "'. "
+ << "Attribute does not exist for joystick at index " << index << "." << std::endl;
+ return 0;
+ }
+
+ return static_cast<unsigned int>(std::strtoul(attributeString, NULL, 16));
+ }
+
+ // Get a system attribute for a joystick at index as an unsigned int
+ unsigned int getAttributeUint(unsigned int index, const std::string& attributeName)
+ {
+ udev* udevContext = udev_new();
+
+ if (!udevContext)
+ {
+ sf::err() << "Unable to get joystick attribute. "
+ << "Could not create udev context." << std::endl;
+ return 0;
+ }
+
+ std::ostringstream sysname("js");
+ sysname << index;
+
+ udev_device* udevDevice = udev_device_new_from_subsystem_sysname(udevContext, "input", sysname.str().c_str());
+
+ if (!udevDevice)
+ {
+ sf::err() << "Unable to get joystick attribute. "
+ << "Could not find USB device for joystick at index " << index << "." << std::endl;
+ udev_unref(udevContext);
+ return 0;
+ }
+
+ unsigned int attribute = getUdevAttributeUint(udevDevice, index, attributeName);
+
+ udev_device_unref(udevDevice);
+ udev_unref(udevContext);
+ return attribute;
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void JoystickImpl::initialize()
+{
+ // Reset the array of plugged joysticks
+ std::fill(plugged, plugged + Joystick::Count, false);
+
+ // Do an initial scan
+ updatePluggedList();
+
+ // Create the inotify instance
+ notifyFd = inotify_init();
+ if (notifyFd < 0)
+ {
+ err() << "Failed to initialize inotify, joystick connections and disconnections won't be notified" << std::endl;
+ return;
+ }
+
+ // Watch nodes created and deleted in the /dev/input directory
+ inputFd = inotify_add_watch(notifyFd, "/dev/input", IN_CREATE | IN_DELETE);
+ if (inputFd < 0)
+ {
+ err() << "Failed to initialize inotify, joystick connections and disconnections won't be notified" << std::endl;
+
+ // No need to hang on to the inotify handle in this case
+ ::close(notifyFd);
+ notifyFd = -1;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::cleanup()
+{
+ // Stop watching the /dev/input directory
+ if (inputFd >= 0)
+ inotify_rm_watch(notifyFd, inputFd);
+
+ // Close the inotify file descriptor
+ if (notifyFd >= 0)
+ ::close(notifyFd);
+}
+
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::isConnected(unsigned int index)
+{
+ // See if we can skip scanning if inotify is available
+ if (notifyFd < 0)
+ {
+ // inotify is not available, perform a scan every query
+ updatePluggedList();
+ }
+ else if (hasInotifyEvent())
+ {
+ // Check if new joysticks were added/removed since last update
+ // Don't bother decomposing and interpreting the filename, just do a full scan
+ updatePluggedList();
+
+ // Flush all the pending events
+ if (lseek(notifyFd, 0, SEEK_END) < 0)
+ err() << "Failed to flush inotify of all pending joystick events." << std::endl;
+ }
+
+ // Then check if the joystick is connected
+ return plugged[index];
+}
+
+////////////////////////////////////////////////////////////
+bool JoystickImpl::open(unsigned int index)
+{
+ if (plugged[index])
+ {
+ std::ostringstream name;
+ name << "/dev/input/js" << index;
+
+ // Open the joystick's file descriptor (read-only and non-blocking)
+ m_file = ::open(name.str().c_str(), O_RDONLY | O_NONBLOCK);
+ if (m_file >= 0)
+ {
+ // Retrieve the axes mapping
+ ioctl(m_file, JSIOCGAXMAP, m_mapping);
+
+ // Get info
+ m_identification.name = getJoystickName(m_file, index);
+ m_identification.vendorId = getAttributeUint(index, "idVendor");
+ m_identification.productId = getAttributeUint(index, "idProduct");
+
+ // Reset the joystick state
+ m_state = JoystickState();
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void JoystickImpl::close()
+{
+ ::close(m_file);
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickCaps JoystickImpl::getCapabilities() const
+{
+ JoystickCaps caps;
+
+ // Get the number of buttons
+ char buttonCount;
+ ioctl(m_file, JSIOCGBUTTONS, &buttonCount);
+ caps.buttonCount = buttonCount;
+ if (caps.buttonCount > Joystick::ButtonCount)
+ caps.buttonCount = Joystick::ButtonCount;
+
+ // Get the supported axes
+ char axesCount;
+ ioctl(m_file, JSIOCGAXES, &axesCount);
+ for (int i = 0; i < axesCount; ++i)
+ {
+ switch (m_mapping[i])
+ {
+ case ABS_X: caps.axes[Joystick::X] = true; break;
+ case ABS_Y: caps.axes[Joystick::Y] = true; break;
+ case ABS_Z:
+ case ABS_THROTTLE: caps.axes[Joystick::Z] = true; break;
+ case ABS_RZ:
+ case ABS_RUDDER: caps.axes[Joystick::R] = true; break;
+ case ABS_RX: caps.axes[Joystick::U] = true; break;
+ case ABS_RY: caps.axes[Joystick::V] = true; break;
+ case ABS_HAT0X: caps.axes[Joystick::PovX] = true; break;
+ case ABS_HAT0Y: caps.axes[Joystick::PovY] = true; break;
+ default: break;
+ }
+ }
+
+ return caps;
+}
+
+
+////////////////////////////////////////////////////////////
+Joystick::Identification JoystickImpl::getIdentification() const
+{
+ return m_identification;
+}
+
+
+////////////////////////////////////////////////////////////
+JoystickState JoystickImpl::JoystickImpl::update()
+{
+ // pop events from the joystick file
+ js_event joyState;
+ while (read(m_file, &joyState, sizeof(joyState)) > 0)
+ {
+ switch (joyState.type & ~JS_EVENT_INIT)
+ {
+ // An axis was moved
+ case JS_EVENT_AXIS:
+ {
+ float value = joyState.value * 100.f / 32767.f;
+ 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;
+ }
+
+ // A button was pressed
+ case JS_EVENT_BUTTON:
+ {
+ if (joyState.number < Joystick::ButtonCount)
+ m_state.buttons[joyState.number] = (joyState.value != 0);
+ break;
+ }
+ }
+ }
+
+ // Check the connection state of the joystick (read() fails with an error != EGAIN if it's no longer connected)
+ m_state.connected = (errno == EAGAIN);
+
+ return m_state;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/JoystickImpl.hpp b/src/SFML/Window/Unix/JoystickImpl.hpp
new file mode 100644
index 0000000..50777ef
--- /dev/null
+++ b/src/SFML/Window/Unix/JoystickImpl.hpp
@@ -0,0 +1,126 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_JOYSTICKIMPLLINUX_HPP
+#define SFML_JOYSTICKIMPLLINUX_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <linux/joystick.h>
+#include <fcntl.h>
+#include <string>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Linux implementation of joysticks
+///
+////////////////////////////////////////////////////////////
+class JoystickImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the joystick module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a joystick is currently connected
+ ///
+ /// \param index Index of the joystick to check
+ ///
+ /// \return True if the joystick is connected, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isConnected(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the joystick
+ ///
+ /// \param index Index assigned to the joystick
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(unsigned int index);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the joystick
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick capabilities
+ ///
+ /// \return Joystick capabilities
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickCaps getCapabilities() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the joystick identification
+ ///
+ /// \return Joystick identification
+ ///
+ ////////////////////////////////////////////////////////////
+ Joystick::Identification getIdentification() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the joystick and get its new state
+ ///
+ /// \return Joystick state
+ ///
+ ////////////////////////////////////////////////////////////
+ JoystickState update();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ int m_file; ///< File descriptor of the joystick
+ char m_mapping[ABS_MAX + 1]; ///< Axes mapping (index to axis id)
+ JoystickState m_state; ///< Current state of the joystick
+ sf::Joystick::Identification m_identification; ///< Identification of the joystick
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_JOYSTICKIMPLLINUX_HPP
diff --git a/src/SFML/Window/Unix/SensorImpl.cpp b/src/SFML/Window/Unix/SensorImpl.cpp
new file mode 100644
index 0000000..be5e439
--- /dev/null
+++ b/src/SFML/Window/Unix/SensorImpl.cpp
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/SensorImpl.hpp>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+void SensorImpl::initialize()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::cleanup()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::isAvailable(Sensor::Type /*sensor*/)
+{
+ // To be implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+bool SensorImpl::open(Sensor::Type /*sensor*/)
+{
+ // To be implemented
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::close()
+{
+ // To be implemented
+}
+
+
+////////////////////////////////////////////////////////////
+Vector3f SensorImpl::update()
+{
+ // To be implemented
+ return Vector3f(0, 0, 0);
+}
+
+
+////////////////////////////////////////////////////////////
+void SensorImpl::setEnabled(bool /*enabled*/)
+{
+ // To be implemented
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/SensorImpl.hpp b/src/SFML/Window/Unix/SensorImpl.hpp
new file mode 100644
index 0000000..bbd705b
--- /dev/null
+++ b/src/SFML/Window/Unix/SensorImpl.hpp
@@ -0,0 +1,101 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_SENSORIMPLUNIX_HPP
+#define SFML_SENSORIMPLUNIX_HPP
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Unix implementation of sensors
+///
+////////////////////////////////////////////////////////////
+class SensorImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global initialization of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Perform the global cleanup of the sensor module
+ ///
+ ////////////////////////////////////////////////////////////
+ static void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check if a sensor is available
+ ///
+ /// \param sensor Sensor to check
+ ///
+ /// \return True if the sensor is available, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ static bool isAvailable(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Open the sensor
+ ///
+ /// \param sensor Type of the sensor
+ ///
+ /// \return True on success, false on failure
+ ///
+ ////////////////////////////////////////////////////////////
+ bool open(Sensor::Type sensor);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Close the sensor
+ ///
+ ////////////////////////////////////////////////////////////
+ void close();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Update the sensor and get its new value
+ ///
+ /// \return Sensor value
+ ///
+ ////////////////////////////////////////////////////////////
+ Vector3f update();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable the sensor
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ void setEnabled(bool enabled);
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_SENSORIMPLUNIX_HPP
diff --git a/src/SFML/Window/Unix/VideoModeImpl.cpp b/src/SFML/Window/Unix/VideoModeImpl.cpp
new file mode 100644
index 0000000..c7e6204
--- /dev/null
+++ b/src/SFML/Window/Unix/VideoModeImpl.cpp
@@ -0,0 +1,176 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/VideoModeImpl.hpp>
+#include <SFML/Window/Unix/Display.hpp>
+#include <SFML/System/Err.hpp>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+#include <algorithm>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
+{
+ std::vector<VideoMode> modes;
+
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+ if (display)
+ {
+ // Retrieve the default screen number
+ int screen = DefaultScreen(display);
+
+ // Check if the XRandR extension is present
+ int version;
+ if (XQueryExtension(display, "RANDR", &version, &version, &version))
+ {
+ // Get the current configuration
+ XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen));
+ if (config)
+ {
+ // Get the available screen sizes
+ int nbSizes;
+ XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
+ if (sizes && (nbSizes > 0))
+ {
+ // Get the list of supported depths
+ int nbDepths = 0;
+ int* depths = XListDepths(display, screen, &nbDepths);
+ if (depths && (nbDepths > 0))
+ {
+ // Combine depths and sizes to fill the array of supported modes
+ for (int i = 0; i < nbDepths; ++i)
+ {
+ for (int j = 0; j < nbSizes; ++j)
+ {
+ // Convert to VideoMode
+ VideoMode mode(sizes[j].width, sizes[j].height, depths[i]);
+
+ // Add it only if it is not already in the array
+ if (std::find(modes.begin(), modes.end(), mode) == modes.end())
+ modes.push_back(mode);
+ }
+ }
+
+ // Free the array of depths
+ XFree(depths);
+ }
+ }
+
+ // Free the configuration instance
+ XRRFreeScreenConfigInfo(config);
+ }
+ else
+ {
+ // Failed to get the screen configuration
+ err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl;
+ }
+ }
+ else
+ {
+ // XRandr extension is not supported: we cannot get the video modes
+ err() << "Failed to use the XRandR extension while trying to get the supported video modes" << std::endl;
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+ }
+ else
+ {
+ // We couldn't connect to the X server
+ err() << "Failed to connect to the X server while trying to get the supported video modes" << std::endl;
+ }
+
+ return modes;
+}
+
+
+////////////////////////////////////////////////////////////
+VideoMode VideoModeImpl::getDesktopMode()
+{
+ VideoMode desktopMode;
+
+ // Open a connection with the X server
+ Display* display = OpenDisplay();
+ if (display)
+ {
+ // Retrieve the default screen number
+ int screen = DefaultScreen(display);
+
+ // Check if the XRandR extension is present
+ int version;
+ if (XQueryExtension(display, "RANDR", &version, &version, &version))
+ {
+ // Get the current configuration
+ XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen));
+ if (config)
+ {
+ // Get the current video mode
+ Rotation currentRotation;
+ int currentMode = XRRConfigCurrentConfiguration(config, &currentRotation);
+
+ // Get the available screen sizes
+ int nbSizes;
+ XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
+ if (sizes && (nbSizes > 0))
+ desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, DefaultDepth(display, screen));
+
+ // Free the configuration instance
+ XRRFreeScreenConfigInfo(config);
+ }
+ else
+ {
+ // Failed to get the screen configuration
+ err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl;
+ }
+ }
+ else
+ {
+ // XRandr extension is not supported: we cannot get the video modes
+ err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl;
+ }
+
+ // Close the connection with the X server
+ CloseDisplay(display);
+ }
+ else
+ {
+ // We couldn't connect to the X server
+ err() << "Failed to connect to the X server while trying to get the desktop video modes" << std::endl;
+ }
+
+ return desktopMode;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp
new file mode 100644
index 0000000..9e29757
--- /dev/null
+++ b/src/SFML/Window/Unix/WindowImplX11.cpp
@@ -0,0 +1,1109 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <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/System/Utf.hpp>
+#include <SFML/System/Err.hpp>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/extensions/Xrandr.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <cstring>
+#include <sstream>
+#include <vector>
+#include <string>
+#include <iterator>
+#include <algorithm>
+
+#ifdef SFML_OPENGL_ES
+ #include <SFML/Window/EglContext.hpp>
+ typedef sf::priv::EglContext ContextType;
+#else
+ #include <SFML/Window/Unix/GlxContext.hpp>
+ typedef sf::priv::GlxContext ContextType;
+#endif
+
+////////////////////////////////////////////////////////////
+// Private data
+////////////////////////////////////////////////////////////
+namespace
+{
+ sf::priv::WindowImplX11* fullscreenWindow = NULL;
+ std::vector<sf::priv::WindowImplX11*> allWindows;
+ unsigned long eventMask = FocusChangeMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
+ PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask |
+ EnterWindowMask | LeaveWindowMask;
+
+ // Filter the events received by windows (only allow those matching a specific window)
+ Bool checkEvent(::Display*, XEvent* event, XPointer userData)
+ {
+ // Just check if the event matches the window
+ return event->xany.window == reinterpret_cast< ::Window >(userData);
+ }
+
+ // Find the name of the current executable
+ void findExecutableName(char* buffer, std::size_t bufferSize)
+ {
+ //Default fallback name
+ const char* executableName = "sfml";
+ std::size_t length = readlink("/proc/self/exe", buffer, bufferSize);
+ if ((length > 0) && (length < bufferSize))
+ {
+ // Remove the path to keep the executable name only
+ buffer[length] = '\0';
+ executableName = basename(buffer);
+ }
+ std::memmove(buffer, executableName, std::strlen(executableName) + 1);
+ }
+}
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+WindowImplX11::WindowImplX11(WindowHandle handle) :
+m_window (0),
+m_inputMethod (NULL),
+m_inputContext(NULL),
+m_isExternal (true),
+m_atomClose (0),
+m_oldVideoMode(-1),
+m_hiddenCursor(0),
+m_keyRepeat (true),
+m_previousSize(-1, -1),
+m_useSizeHints(false)
+{
+ // Open a connection with the X server
+ m_display = OpenDisplay();
+ m_screen = DefaultScreen(m_display);
+
+ // Save the window handle
+ m_window = handle;
+
+ if (m_window)
+ {
+ // Make sure the window is listening to all the required events
+ XSelectInput(m_display, m_window, eventMask & ~ButtonPressMask);
+
+ // Do some common initializations
+ initialize();
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) :
+m_window (0),
+m_inputMethod (NULL),
+m_inputContext(NULL),
+m_isExternal (false),
+m_atomClose (0),
+m_oldVideoMode(-1),
+m_hiddenCursor(0),
+m_keyRepeat (true),
+m_previousSize(-1, -1),
+m_useSizeHints(false)
+{
+ // Open a connection with the X server
+ m_display = OpenDisplay();
+ m_screen = DefaultScreen(m_display);
+ ::Window root = RootWindow(m_display, m_screen);
+
+ // Compute position and size
+ int left, top;
+ bool fullscreen = (style & Style::Fullscreen) != 0;
+ if (!fullscreen)
+ {
+ left = (DisplayWidth(m_display, m_screen) - mode.width) / 2;
+ top = (DisplayHeight(m_display, m_screen) - mode.height) / 2;
+ }
+ else
+ {
+ left = 0;
+ top = 0;
+ }
+ int width = mode.width;
+ int height = mode.height;
+
+ // Switch to fullscreen if necessary
+ if (fullscreen)
+ switchToFullscreen(mode);
+
+ // Choose the visual according to the context settings
+ XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings);
+
+ // Define the window attributes
+ XSetWindowAttributes attributes;
+ attributes.override_redirect = fullscreen;
+ attributes.event_mask = eventMask;
+ attributes.colormap = XCreateColormap(m_display, root, visualInfo.visual, AllocNone);
+
+ // Create the window
+ m_window = XCreateWindow(m_display,
+ root,
+ left, top,
+ width, height,
+ 0,
+ visualInfo.depth,
+ InputOutput,
+ visualInfo.visual,
+ CWEventMask | CWOverrideRedirect | CWColormap, &attributes);
+ if (!m_window)
+ {
+ err() << "Failed to create window" << std::endl;
+ return;
+ }
+
+ // Set the window's name
+ setTitle(title);
+
+ // Set the window's style (tell the windows manager to change our window's decorations and functions according to the requested style)
+ if (!fullscreen)
+ {
+ Atom WMHintsAtom = XInternAtom(m_display, "_MOTIF_WM_HINTS", false);
+ if (WMHintsAtom)
+ {
+ static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0;
+ static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1;
+
+ //static const unsigned long MWM_DECOR_ALL = 1 << 0;
+ static const unsigned long MWM_DECOR_BORDER = 1 << 1;
+ static const unsigned long MWM_DECOR_RESIZEH = 1 << 2;
+ static const unsigned long MWM_DECOR_TITLE = 1 << 3;
+ static const unsigned long MWM_DECOR_MENU = 1 << 4;
+ static const unsigned long MWM_DECOR_MINIMIZE = 1 << 5;
+ static const unsigned long MWM_DECOR_MAXIMIZE = 1 << 6;
+
+ //static const unsigned long MWM_FUNC_ALL = 1 << 0;
+ static const unsigned long MWM_FUNC_RESIZE = 1 << 1;
+ static const unsigned long MWM_FUNC_MOVE = 1 << 2;
+ static const unsigned long MWM_FUNC_MINIMIZE = 1 << 3;
+ static const unsigned long MWM_FUNC_MAXIMIZE = 1 << 4;
+ static const unsigned long MWM_FUNC_CLOSE = 1 << 5;
+
+ struct WMHints
+ {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long state;
+ };
+
+ WMHints hints;
+ hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
+ hints.decorations = 0;
+ hints.functions = 0;
+
+ if (style & Style::Titlebar)
+ {
+ hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU;
+ hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE;
+ }
+ if (style & Style::Resize)
+ {
+ hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH;
+ hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
+ }
+ if (style & Style::Close)
+ {
+ hints.decorations |= 0;
+ hints.functions |= MWM_FUNC_CLOSE;
+ }
+
+ const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&hints);
+ XChangeProperty(m_display, m_window, WMHintsAtom, WMHintsAtom, 32, PropModeReplace, ptr, 5);
+ }
+
+ // This is a hack to force some windows managers to disable resizing
+ if (!(style & Style::Resize))
+ {
+ m_useSizeHints = true;
+ XSizeHints* sizeHints = XAllocSizeHints();
+ sizeHints->flags = PMinSize | PMaxSize;
+ sizeHints->min_width = sizeHints->max_width = width;
+ sizeHints->min_height = sizeHints->max_height = height;
+ XSetWMNormalHints(m_display, m_window, sizeHints);
+ XFree(sizeHints);
+ }
+ }
+
+ // Set the window's WM class (this can be used by window managers)
+ char windowClass[512];
+ findExecutableName(windowClass, sizeof(windowClass));
+ XClassHint* classHint = XAllocClassHint();
+ classHint->res_name = windowClass;
+ classHint->res_class = windowClass;
+ XSetClassHint(m_display, m_window, classHint);
+ XFree(classHint);
+
+ // Do some common initializations
+ initialize();
+
+ // In fullscreen mode, we must grab keyboard and mouse inputs
+ if (fullscreen)
+ {
+ XGrabPointer(m_display, m_window, true, 0, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
+ XGrabKeyboard(m_display, m_window, true, GrabModeAsync, GrabModeAsync, CurrentTime);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+WindowImplX11::~WindowImplX11()
+{
+ // Cleanup graphical resources
+ cleanup();
+
+ // Destroy the cursor
+ if (m_hiddenCursor)
+ XFreeCursor(m_display, m_hiddenCursor);
+
+ // Destroy the input context
+ if (m_inputContext)
+ XDestroyIC(m_inputContext);
+
+ // Destroy the window
+ if (m_window && !m_isExternal)
+ {
+ XDestroyWindow(m_display, m_window);
+ XFlush(m_display);
+ }
+
+ // Close the input method
+ if (m_inputMethod)
+ XCloseIM(m_inputMethod);
+
+ // Close the connection with the X server
+ CloseDisplay(m_display);
+
+ // Remove this window from the global list of windows (required for focus request)
+ allWindows.erase(std::find(allWindows.begin(), allWindows.end(), this));
+}
+
+
+////////////////////////////////////////////////////////////
+WindowHandle WindowImplX11::getSystemHandle() const
+{
+ return m_window;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::processEvents()
+{
+ XEvent event;
+ while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window)))
+ {
+ processEvent(event);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i WindowImplX11::getPosition() const
+{
+ ::Window root, child;
+ int localX, localY, x, y;
+ unsigned int width, height, border, depth;
+
+ XGetGeometry(m_display, m_window, &root, &localX, &localY, &width, &height, &border, &depth);
+ XTranslateCoordinates(m_display, m_window, root, localX, localY, &x, &y, &child);
+
+ return Vector2i(x, y);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setPosition(const Vector2i& position)
+{
+ XMoveWindow(m_display, m_window, position.x, position.y);
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2u WindowImplX11::getSize() const
+{
+ XWindowAttributes attributes;
+ XGetWindowAttributes(m_display, m_window, &attributes);
+ return Vector2u(attributes.width, attributes.height);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setSize(const Vector2u& size)
+{
+ // If we used size hint to fix the size of the window, we must update them
+ if (m_useSizeHints)
+ {
+ XSizeHints* sizeHints = XAllocSizeHints();
+ sizeHints->flags = PMinSize | PMaxSize;
+ sizeHints->min_width = sizeHints->max_width = size.x;
+ sizeHints->min_height = sizeHints->max_height = size.y;
+ XSetWMNormalHints(m_display, m_window, sizeHints);
+ XFree(sizeHints);
+ }
+
+ XResizeWindow(m_display, m_window, size.x, size.y);
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setTitle(const String& title)
+{
+ // Bare X11 has no Unicode window title support.
+ // There is however an option to tell the window manager your Unicode title via hints.
+
+ // Convert to UTF-8 encoding.
+ std::basic_string<Uint8> utf8Title;
+ Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title));
+
+ // Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title.
+ Atom wmName = XInternAtom(m_display, "_NET_WM_NAME", False);
+ Atom useUtf8 = XInternAtom(m_display, "UTF8_STRING", False);
+ XChangeProperty(m_display, m_window, wmName, useUtf8, 8,
+ PropModeReplace, utf8Title.c_str(), utf8Title.size());
+
+ // Set the non-Unicode title as a fallback for window managers who don't support _NET_WM_NAME.
+ XStoreName(m_display, m_window, title.toAnsiString().c_str());
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels)
+{
+ // X11 wants BGRA pixels: swap red and blue channels
+ // Note: this memory will be freed by XDestroyImage
+ Uint8* iconPixels = static_cast<Uint8*>(std::malloc(width * height * 4));
+ for (std::size_t i = 0; i < width * height; ++i)
+ {
+ iconPixels[i * 4 + 0] = pixels[i * 4 + 2];
+ iconPixels[i * 4 + 1] = pixels[i * 4 + 1];
+ iconPixels[i * 4 + 2] = pixels[i * 4 + 0];
+ iconPixels[i * 4 + 3] = pixels[i * 4 + 3];
+ }
+
+ // Create the icon pixmap
+ Visual* defVisual = DefaultVisual(m_display, m_screen);
+ unsigned int defDepth = DefaultDepth(m_display, m_screen);
+ XImage* iconImage = XCreateImage(m_display, defVisual, defDepth, ZPixmap, 0, (char*)iconPixels, width, height, 32, 0);
+ if (!iconImage)
+ {
+ err() << "Failed to set the window's icon" << std::endl;
+ return;
+ }
+ Pixmap iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth);
+ XGCValues values;
+ GC iconGC = XCreateGC(m_display, iconPixmap, 0, &values);
+ XPutImage(m_display, iconPixmap, iconGC, iconImage, 0, 0, 0, 0, width, height);
+ XFreeGC(m_display, iconGC);
+ XDestroyImage(iconImage);
+
+ // Create the mask pixmap (must have 1 bit depth)
+ std::size_t pitch = (width + 7) / 8;
+ static std::vector<Uint8> maskPixels(pitch * height, 0);
+ for (std::size_t j = 0; j < height; ++j)
+ {
+ for (std::size_t i = 0; i < pitch; ++i)
+ {
+ for (std::size_t k = 0; k < 8; ++k)
+ {
+ if (i * 8 + k < width)
+ {
+ Uint8 opacity = (pixels[(i * 8 + k + j * width) * 4 + 3] > 0) ? 1 : 0;
+ maskPixels[i + j * pitch] |= (opacity << k);
+ }
+ }
+ }
+ }
+ Pixmap maskPixmap = XCreatePixmapFromBitmapData(m_display, m_window, (char*)&maskPixels[0], width, height, 1, 0, 1);
+
+ // Send our new icon to the window through the WMHints
+ XWMHints* hints = XAllocWMHints();
+ hints->flags = IconPixmapHint | IconMaskHint;
+ hints->icon_pixmap = iconPixmap;
+ hints->icon_mask = maskPixmap;
+ XSetWMHints(m_display, m_window, hints);
+ XFree(hints);
+
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setVisible(bool visible)
+{
+ if (visible)
+ XMapWindow(m_display, m_window);
+ else
+ XUnmapWindow(m_display, m_window);
+
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setMouseCursorVisible(bool visible)
+{
+ XDefineCursor(m_display, m_window, visible ? None : m_hiddenCursor);
+ XFlush(m_display);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::setKeyRepeatEnabled(bool enabled)
+{
+ m_keyRepeat = enabled;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::requestFocus()
+{
+ // Focus is only stolen among SFML windows, not between applications
+ // Check the global list of windows to find out whether an SFML window has the focus
+ // Note: can't handle console and other non-SFML windows belonging to the application.
+ bool sfmlWindowFocused = false;
+ for (std::vector<WindowImplX11*>::iterator itr = allWindows.begin(); itr != allWindows.end(); ++itr)
+ {
+ if ((*itr)->hasFocus())
+ {
+ sfmlWindowFocused = true;
+ break;
+ }
+ }
+
+ // Check if window is viewable (not on other desktop, ...)
+ // TODO: Check also if minimized
+ XWindowAttributes attributes;
+ if (XGetWindowAttributes(m_display, m_window, &attributes) == 0)
+ {
+ sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl;
+ return; // error getting attribute
+ }
+
+ bool windowViewable = (attributes.map_state == IsViewable);
+
+ if (sfmlWindowFocused && windowViewable)
+ {
+ // Another SFML window of this application has the focus and the current window is viewable:
+ // steal focus (i.e. bring window to the front and give it input focus)
+ XRaiseWindow(m_display, m_window);
+ XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime);
+ }
+ else
+ {
+ // Otherwise: display urgency hint (flashing application logo)
+ // Ensure WM hints exist, allocate if necessary
+ XWMHints* hints = XGetWMHints(m_display, m_window);
+ if (hints == NULL)
+ hints = XAllocWMHints();
+
+ // Add urgency (notification) flag to hints
+ hints->flags |= XUrgencyHint;
+ XSetWMHints(m_display, m_window, hints);
+ XFree(hints);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplX11::hasFocus() const
+{
+ ::Window focusedWindow = 0;
+ int revertToReturn = 0;
+ XGetInputFocus(m_display, &focusedWindow, &revertToReturn);
+
+ return m_window == focusedWindow;
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::switchToFullscreen(const VideoMode& mode)
+{
+ // Check if the XRandR extension is present
+ int version;
+ if (XQueryExtension(m_display, "RANDR", &version, &version, &version))
+ {
+ // Get the current configuration
+ XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen));
+ if (config)
+ {
+ // Get the current rotation
+ Rotation currentRotation;
+ m_oldVideoMode = XRRConfigCurrentConfiguration(config, &currentRotation);
+
+ // Get the available screen sizes
+ int nbSizes;
+ XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
+ if (sizes && (nbSizes > 0))
+ {
+ // Search a matching size
+ for (int i = 0; i < nbSizes; ++i)
+ {
+ if ((sizes[i].width == static_cast<int>(mode.width)) && (sizes[i].height == static_cast<int>(mode.height)))
+ {
+ // Switch to fullscreen mode
+ XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime);
+
+ // Set "this" as the current fullscreen window
+ fullscreenWindow = this;
+ break;
+ }
+ }
+ }
+
+ // Free the configuration instance
+ XRRFreeScreenConfigInfo(config);
+ }
+ else
+ {
+ // Failed to get the screen configuration
+ err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl;
+ }
+ }
+ else
+ {
+ // XRandr extension is not supported: we cannot use fullscreen mode
+ err() << "Fullscreen is not supported, switching to window mode" << std::endl;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::initialize()
+{
+ // Get the atom defining the close event
+ m_atomClose = XInternAtom(m_display, "WM_DELETE_WINDOW", false);
+ XSetWMProtocols(m_display, m_window, &m_atomClose, 1);
+
+ // Create the input context
+ m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL);
+ if (m_inputMethod)
+ {
+ m_inputContext = XCreateIC(m_inputMethod,
+ XNClientWindow, m_window,
+ XNFocusWindow, m_window,
+ XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
+ (void*)NULL);
+ }
+ else
+ {
+ m_inputContext = NULL;
+ }
+ if (!m_inputContext)
+ err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl;
+
+ // Show the window
+ XMapWindow(m_display, m_window);
+ XFlush(m_display);
+
+ // Create the hidden cursor
+ createHiddenCursor();
+
+ // Flush the commands queue
+ XFlush(m_display);
+
+ // Add this window to the global list of windows (required for focus request)
+ allWindows.push_back(this);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::createHiddenCursor()
+{
+ // Create the cursor's pixmap (1x1 pixels)
+ Pixmap cursorPixmap = XCreatePixmap(m_display, m_window, 1, 1, 1);
+ GC graphicsContext = XCreateGC(m_display, cursorPixmap, 0, NULL);
+ XDrawPoint(m_display, cursorPixmap, graphicsContext, 0, 0);
+ XFreeGC(m_display, graphicsContext);
+
+ // Create the cursor, using the pixmap as both the shape and the mask of the cursor
+ XColor color;
+ color.flags = DoRed | DoGreen | DoBlue;
+ color.red = color.blue = color.green = 0;
+ m_hiddenCursor = XCreatePixmapCursor(m_display, cursorPixmap, cursorPixmap, &color, &color, 0, 0);
+
+ // We don't need the pixmap any longer, free it
+ XFreePixmap(m_display, cursorPixmap);
+}
+
+
+////////////////////////////////////////////////////////////
+void WindowImplX11::cleanup()
+{
+ // Restore the previous video mode (in case we were running in fullscreen)
+ if (fullscreenWindow == this)
+ {
+ // Get current screen info
+ XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen));
+ if (config)
+ {
+ // Get the current rotation
+ Rotation currentRotation;
+ XRRConfigCurrentConfiguration(config, &currentRotation);
+
+ // Reset the video mode
+ XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime);
+
+ // Free the configuration instance
+ XRRFreeScreenConfigInfo(config);
+ }
+
+ // Reset the fullscreen window
+ fullscreenWindow = NULL;
+ }
+
+ // Unhide the mouse cursor (in case it was hidden)
+ setMouseCursorVisible(true);
+}
+
+
+////////////////////////////////////////////////////////////
+bool WindowImplX11::processEvent(XEvent windowEvent)
+{
+ // This function implements a workaround to properly discard
+ // repeated key events when necessary. The problem is that the
+ // system's key events policy doesn't match SFML's one: X server will generate
+ // both repeated KeyPress and KeyRelease events when maintaining a key down, while
+ // SFML only wants repeated KeyPress events. Thus, we have to:
+ // - Discard duplicated KeyRelease events when KeyRepeatEnabled is true
+ // - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false
+
+ // Detect repeated key events
+ // (code shamelessly taken from SDL)
+ if (windowEvent.type == KeyRelease)
+ {
+ // Check if there's a matching KeyPress event in the queue
+ XEvent nextEvent;
+ if (XPending(m_display))
+ {
+ // Grab it but don't remove it from the queue, it still needs to be processed :)
+ XPeekEvent(m_display, &nextEvent);
+ if (nextEvent.type == KeyPress)
+ {
+ // Check if it is a duplicated event (same timestamp as the KeyRelease event)
+ if ((nextEvent.xkey.keycode == windowEvent.xkey.keycode) &&
+ (nextEvent.xkey.time - windowEvent.xkey.time < 2))
+ {
+ // If we don't want repeated events, remove the next KeyPress from the queue
+ if (!m_keyRepeat)
+ XNextEvent(m_display, &nextEvent);
+
+ // This KeyRelease is a repeated event and we don't want it
+ return false;
+ }
+ }
+ }
+ }
+
+ // Convert the X11 event to a sf::Event
+ switch (windowEvent.type)
+ {
+ // Destroy event
+ case DestroyNotify:
+ {
+ // The window is about to be destroyed: we must cleanup resources
+ cleanup();
+ break;
+ }
+
+ // Gain focus event
+ case FocusIn:
+ {
+ // Update the input context
+ if (m_inputContext)
+ XSetICFocus(m_inputContext);
+
+ Event event;
+ event.type = Event::GainedFocus;
+ pushEvent(event);
+
+ // If the window has been previously marked urgent (notification) as a result of a focus request, undo that
+ XWMHints* hints = XGetWMHints(m_display, m_window);
+ if (hints != NULL)
+ {
+ // Remove urgency (notification) flag from hints
+ hints->flags &= ~XUrgencyHint;
+ XSetWMHints(m_display, m_window, hints);
+ XFree(hints);
+ }
+ break;
+ }
+
+ // Lost focus event
+ case FocusOut:
+ {
+ // Update the input context
+ if (m_inputContext)
+ XUnsetICFocus(m_inputContext);
+
+ Event event;
+ event.type = Event::LostFocus;
+ pushEvent(event);
+ break;
+ }
+
+ // Resize event
+ case ConfigureNotify:
+ {
+ // ConfigureNotify can be triggered for other reasons, check if the size has actually changed
+ if ((windowEvent.xconfigure.width != m_previousSize.x) || (windowEvent.xconfigure.height != m_previousSize.y))
+ {
+ Event event;
+ event.type = Event::Resized;
+ event.size.width = windowEvent.xconfigure.width;
+ event.size.height = windowEvent.xconfigure.height;
+ pushEvent(event);
+
+ m_previousSize.x = windowEvent.xconfigure.width;
+ m_previousSize.y = windowEvent.xconfigure.height;
+ }
+ break;
+ }
+
+ // Close event
+ case ClientMessage:
+ {
+ if ((windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast<long>(m_atomClose))
+ {
+ Event event;
+ event.type = Event::Closed;
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // 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);
+
+ // Fill the event parameters
+ // TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping
+ Event event;
+ event.type = Event::KeyPressed;
+ event.key.code = keysymToSF(symbol);
+ event.key.alt = windowEvent.xkey.state & Mod1Mask;
+ event.key.control = windowEvent.xkey.state & ControlMask;
+ event.key.shift = windowEvent.xkey.state & ShiftMask;
+ event.key.system = windowEvent.xkey.state & Mod4Mask;
+ pushEvent(event);
+
+ // Generate a TextEntered event
+ if (!XFilterEvent(&windowEvent, None))
+ {
+ #ifdef X_HAVE_UTF8_STRING
+ if (m_inputContext)
+ {
+ Status status;
+ Uint8 keyBuffer[16];
+ int length = Xutf8LookupString(m_inputContext, &windowEvent.xkey, reinterpret_cast<char*>(keyBuffer), sizeof(keyBuffer), NULL, &status);
+ if (length > 0)
+ {
+ Uint32 unicode = 0;
+ Utf8::decode(keyBuffer, keyBuffer + length, unicode, 0);
+ if (unicode != 0)
+ {
+ Event textEvent;
+ textEvent.type = Event::TextEntered;
+ textEvent.text.unicode = unicode;
+ pushEvent(textEvent);
+ }
+ }
+ }
+ else
+ #endif
+ {
+ static XComposeStatus status;
+ char keyBuffer[16];
+ if (XLookupString(&windowEvent.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status))
+ {
+ Event textEvent;
+ textEvent.type = Event::TextEntered;
+ textEvent.text.unicode = static_cast<Uint32>(keyBuffer[0]);
+ pushEvent(textEvent);
+ }
+ }
+ }
+
+ break;
+ }
+
+ // 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);
+
+ // Fill the event parameters
+ Event event;
+ event.type = Event::KeyReleased;
+ event.key.code = keysymToSF(symbol);
+ event.key.alt = windowEvent.xkey.state & Mod1Mask;
+ event.key.control = windowEvent.xkey.state & ControlMask;
+ event.key.shift = windowEvent.xkey.state & ShiftMask;
+ event.key.system = windowEvent.xkey.state & Mod4Mask;
+ pushEvent(event);
+
+ break;
+ }
+
+ // Mouse button pressed
+ case ButtonPress:
+ {
+ unsigned int button = windowEvent.xbutton.button;
+ if ((button == Button1) || (button == Button2) || (button == Button3) || (button == 8) || (button == 9))
+ {
+ Event event;
+ event.type = Event::MouseButtonPressed;
+ event.mouseButton.x = windowEvent.xbutton.x;
+ event.mouseButton.y = windowEvent.xbutton.y;
+ switch (button)
+ {
+ case Button1: event.mouseButton.button = Mouse::Left; break;
+ case Button2: event.mouseButton.button = Mouse::Middle; break;
+ case Button3: event.mouseButton.button = Mouse::Right; break;
+ case 8: event.mouseButton.button = Mouse::XButton1; break;
+ case 9: event.mouseButton.button = Mouse::XButton2; break;
+ }
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Mouse button released
+ case ButtonRelease:
+ {
+ unsigned int button = windowEvent.xbutton.button;
+ if ((button == Button1) || (button == Button2) || (button == Button3) || (button == 8) || (button == 9))
+ {
+ Event event;
+ event.type = Event::MouseButtonReleased;
+ event.mouseButton.x = windowEvent.xbutton.x;
+ event.mouseButton.y = windowEvent.xbutton.y;
+ switch (button)
+ {
+ case Button1: event.mouseButton.button = Mouse::Left; break;
+ case Button2: event.mouseButton.button = Mouse::Middle; break;
+ case Button3: event.mouseButton.button = Mouse::Right; break;
+ case 8: event.mouseButton.button = Mouse::XButton1; break;
+ case 9: event.mouseButton.button = Mouse::XButton2; break;
+ }
+ pushEvent(event);
+ }
+ else if ((button == Button4) || (button == Button5))
+ {
+ Event event;
+ event.type = Event::MouseWheelMoved;
+ event.mouseWheel.delta = windowEvent.xbutton.button == Button4 ? 1 : -1;
+ event.mouseWheel.x = windowEvent.xbutton.x;
+ event.mouseWheel.y = windowEvent.xbutton.y;
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Mouse moved
+ case MotionNotify:
+ {
+ Event event;
+ event.type = Event::MouseMoved;
+ event.mouseMove.x = windowEvent.xmotion.x;
+ event.mouseMove.y = windowEvent.xmotion.y;
+ pushEvent(event);
+ break;
+ }
+
+ // Mouse entered
+ case EnterNotify:
+ {
+ if (windowEvent.xcrossing.mode == NotifyNormal)
+ {
+ Event event;
+ event.type = Event::MouseEntered;
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Mouse left
+ case LeaveNotify:
+ {
+ if (windowEvent.xcrossing.mode == NotifyNormal)
+ {
+ Event event;
+ event.type = Event::MouseLeft;
+ pushEvent(event);
+ }
+ break;
+ }
+
+ // Parent window changed
+ case ReparentNotify:
+ {
+ XSync(m_display, True); // Discard remaining events
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+Keyboard::Key WindowImplX11::keysymToSF(KeySym symbol)
+{
+ // First convert to uppercase (to avoid dealing with two different keysyms for the same key)
+ KeySym lower, key;
+ XConvertCase(symbol, &lower, &key);
+
+ switch (key)
+ {
+ case XK_Shift_L: return Keyboard::LShift;
+ case XK_Shift_R: return Keyboard::RShift;
+ case XK_Control_L: return Keyboard::LControl;
+ case XK_Control_R: return Keyboard::RControl;
+ case XK_Alt_L: return Keyboard::LAlt;
+ case XK_Alt_R: return Keyboard::RAlt;
+ case XK_Super_L: return Keyboard::LSystem;
+ case XK_Super_R: return Keyboard::RSystem;
+ case XK_Menu: return Keyboard::Menu;
+ case XK_Escape: return Keyboard::Escape;
+ case XK_semicolon: return Keyboard::SemiColon;
+ case XK_slash: return Keyboard::Slash;
+ case XK_equal: return Keyboard::Equal;
+ case XK_minus: return Keyboard::Dash;
+ case XK_bracketleft: return Keyboard::LBracket;
+ case XK_bracketright: return Keyboard::RBracket;
+ case XK_comma: return Keyboard::Comma;
+ case XK_period: return Keyboard::Period;
+ case XK_dead_acute: return Keyboard::Quote;
+ case XK_backslash: return Keyboard::BackSlash;
+ case XK_dead_grave: return Keyboard::Tilde;
+ case XK_space: return Keyboard::Space;
+ case XK_Return: return Keyboard::Return;
+ case XK_KP_Enter: return Keyboard::Return;
+ case XK_BackSpace: return Keyboard::BackSpace;
+ case XK_Tab: return Keyboard::Tab;
+ case XK_Prior: return Keyboard::PageUp;
+ case XK_Next: return Keyboard::PageDown;
+ case XK_End: return Keyboard::End;
+ case XK_Home: return Keyboard::Home;
+ case XK_Insert: return Keyboard::Insert;
+ case XK_Delete: return Keyboard::Delete;
+ case XK_KP_Add: return Keyboard::Add;
+ case XK_KP_Subtract: return Keyboard::Subtract;
+ case XK_KP_Multiply: return Keyboard::Multiply;
+ case XK_KP_Divide: return Keyboard::Divide;
+ case XK_Pause: return Keyboard::Pause;
+ case XK_F1: return Keyboard::F1;
+ case XK_F2: return Keyboard::F2;
+ case XK_F3: return Keyboard::F3;
+ case XK_F4: return Keyboard::F4;
+ case XK_F5: return Keyboard::F5;
+ case XK_F6: return Keyboard::F6;
+ case XK_F7: return Keyboard::F7;
+ case XK_F8: return Keyboard::F8;
+ case XK_F9: return Keyboard::F9;
+ case XK_F10: return Keyboard::F10;
+ case XK_F11: return Keyboard::F11;
+ case XK_F12: return Keyboard::F12;
+ case XK_F13: return Keyboard::F13;
+ case XK_F14: return Keyboard::F14;
+ case XK_F15: return Keyboard::F15;
+ case XK_Left: return Keyboard::Left;
+ case XK_Right: return Keyboard::Right;
+ case XK_Up: return Keyboard::Up;
+ case XK_Down: return Keyboard::Down;
+ case XK_KP_0: return Keyboard::Numpad0;
+ case XK_KP_1: return Keyboard::Numpad1;
+ case XK_KP_2: return Keyboard::Numpad2;
+ case XK_KP_3: return Keyboard::Numpad3;
+ case XK_KP_4: return Keyboard::Numpad4;
+ case XK_KP_5: return Keyboard::Numpad5;
+ case XK_KP_6: return Keyboard::Numpad6;
+ case XK_KP_7: return Keyboard::Numpad7;
+ case XK_KP_8: return Keyboard::Numpad8;
+ case XK_KP_9: return Keyboard::Numpad9;
+ case XK_A: return Keyboard::A;
+ case XK_Z: return Keyboard::Z;
+ case XK_E: return Keyboard::E;
+ case XK_R: return Keyboard::R;
+ case XK_T: return Keyboard::T;
+ case XK_Y: return Keyboard::Y;
+ case XK_U: return Keyboard::U;
+ case XK_I: return Keyboard::I;
+ case XK_O: return Keyboard::O;
+ case XK_P: return Keyboard::P;
+ case XK_Q: return Keyboard::Q;
+ case XK_S: return Keyboard::S;
+ case XK_D: return Keyboard::D;
+ case XK_F: return Keyboard::F;
+ case XK_G: return Keyboard::G;
+ case XK_H: return Keyboard::H;
+ case XK_J: return Keyboard::J;
+ case XK_K: return Keyboard::K;
+ case XK_L: return Keyboard::L;
+ case XK_M: return Keyboard::M;
+ case XK_W: return Keyboard::W;
+ case XK_X: return Keyboard::X;
+ case XK_C: return Keyboard::C;
+ case XK_V: return Keyboard::V;
+ case XK_B: return Keyboard::B;
+ case XK_N: return Keyboard::N;
+ case XK_0: return Keyboard::Num0;
+ case XK_1: return Keyboard::Num1;
+ case XK_2: return Keyboard::Num2;
+ case XK_3: return Keyboard::Num3;
+ case XK_4: return Keyboard::Num4;
+ case XK_5: return Keyboard::Num5;
+ case XK_6: return Keyboard::Num6;
+ case XK_7: return Keyboard::Num7;
+ case XK_8: return Keyboard::Num8;
+ case XK_9: return Keyboard::Num9;
+ }
+
+ return Keyboard::Unknown;
+}
+
+} // namespace priv
+
+} // namespace sf
diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp
new file mode 100644
index 0000000..d824492
--- /dev/null
+++ b/src/SFML/Window/Unix/WindowImplX11.hpp
@@ -0,0 +1,250 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifndef SFML_WINDOWIMPLX11_HPP
+#define SFML_WINDOWIMPLX11_HPP
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/Event.hpp>
+#include <SFML/Window/WindowImpl.hpp>
+#include <SFML/System/String.hpp>
+#include <X11/Xlib.h>
+#include <set>
+
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+/// \brief Linux (X11) implementation of WindowImpl
+///
+////////////////////////////////////////////////////////////
+class WindowImplX11 : public WindowImpl
+{
+public:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Construct the window implementation from an existing control
+ ///
+ /// \param handle Platform-specific handle of the control
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplX11(WindowHandle handle);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create the window implementation
+ ///
+ /// \param mode Video mode to use
+ /// \param title Title of the window
+ /// \param style Window style (resizable, fixed, or fullscren)
+ /// \param settings Additional settings for the underlying OpenGL context
+ ///
+ ////////////////////////////////////////////////////////////
+ WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Destructor
+ ///
+ ////////////////////////////////////////////////////////////
+ ~WindowImplX11();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the OS-specific handle of the window
+ ///
+ /// \return Handle of the window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual WindowHandle getSystemHandle() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the position of the window
+ ///
+ /// \return Position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2i getPosition() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the position of the window on screen
+ ///
+ /// \param position New position of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setPosition(const Vector2i& position);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Get the client size of the window
+ ///
+ /// \return Size of the window, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual Vector2u getSize() const;
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the size of the rendering region of the window
+ ///
+ /// \param size New size, in pixels
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setSize(const Vector2u& size);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the title of the window
+ ///
+ /// \param title New title
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setTitle(const String& title);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Change the window's icon
+ ///
+ /// \param width Icon's width, in pixels
+ /// \param height Icon's height, in pixels
+ /// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the window
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Show or hide the mouse cursor
+ ///
+ /// \param visible True to show, false to hide
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setMouseCursorVisible(bool visible);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Enable or disable automatic key-repeat
+ ///
+ /// \param enabled True to enable, false to disable
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void setKeyRepeatEnabled(bool enabled);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Request the current window to be made the active
+ /// foreground window
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void requestFocus();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Check whether the window has the input focus
+ ///
+ /// \return True if window has focus, false otherwise
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual bool hasFocus() const;
+
+protected:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process incoming events from the operating system
+ ///
+ ////////////////////////////////////////////////////////////
+ virtual void processEvents();
+
+private:
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Switch to fullscreen mode
+ ///
+ /// \param Mode video mode to switch to
+ ///
+ ////////////////////////////////////////////////////////////
+ void switchToFullscreen(const VideoMode& mode);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Do some common initializations after the window has been created
+ ///
+ ////////////////////////////////////////////////////////////
+ void initialize();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Create a transparent mouse cursor
+ ///
+ ////////////////////////////////////////////////////////////
+ void createHiddenCursor();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Cleanup graphical resources attached to the window
+ ///
+ ////////////////////////////////////////////////////////////
+ void cleanup();
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Process an incoming event from the window
+ ///
+ /// \param windowEvent Event which has been received
+ ///
+ /// \return True if the event was processed, false if it was discarded
+ ///
+ ////////////////////////////////////////////////////////////
+ bool processEvent(XEvent windowEvent);
+
+ ////////////////////////////////////////////////////////////
+ /// \brief Convert a X11 keysym to SFML key code
+ ///
+ /// \param symbol Key symbol to convert
+ ///
+ /// \return Corresponding SFML key code
+ ///
+ ////////////////////////////////////////////////////////////
+ static Keyboard::Key keysymToSF(KeySym symbol);
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ ::Window m_window; ///< X11 structure defining our window
+ ::Display* m_display; ///< Pointer to the display
+ int m_screen; ///< Screen identifier
+ XIM m_inputMethod; ///< Input method linked to the X display
+ XIC m_inputContext; ///< Input context used to get Unicode input in our window
+ bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
+ Atom m_atomClose; ///< Atom used to identify the close event
+ int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
+ Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one
+ bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
+ Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
+ bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
+};
+
+} // namespace priv
+
+} // namespace sf
+
+
+#endif // SFML_WINDOWIMPLX11_HPP