Replaced Xlib by XCB implementation.

* Added FindXCB.cmake script
* Added AutoPointer wrapper for automatically free'ing pointers
* Huge commit: Ported linux implementation of sfml-window to xcb
* Xcb is now used for window creation, event loop etc
* As GLX is linked to Xlib, that part of the implementation
  still uses Xlib.
* Also, some keyboard related (such as XLookupString) stuff
  is still Xlib, as xcb does not have it (yet?).
* Replaced some enums with the xcb equivalents
This commit is contained in:
Lukas W 2012-11-25 11:54:45 +01:00 committed by Stefan Schindler
parent 19920f572f
commit 135c1716e8
12 changed files with 862 additions and 435 deletions

View File

@ -0,0 +1,97 @@
# Try to find libxcb
#
#
# Once done this will define:
# LIBXCB_FOUND - True if xcb was found
# LIBXCB_INCLUDE_DIRS - Directories containing the headers
# LIBXCB_LIBRARIES - List of libraries to link to
#
# Also for each requested component:
# LIBXCB_${UPPER_COMPONENT_NAME}_FOUND
# LIBXCB_${UPPER_COMPONENT_NAME}_INCLUDE_DIRS
# LIBXCB_${UPPER_COMPONENT_NAME}_LIBRARIES
include(FindPackageHandleStandardArgs)
IF(NOT WIN32)
IF(LIBXCB_LIBRARIES AND LIBXCB_INCLUDE_DIR)
set(XCB_FIND_QUIETLY TRUE)
ENDIF()
# Find xcb
FIND_PATH(LIBXCB_INCLUDE_DIR xcb/xcb.h)
FIND_LIBRARY(LIBXCB_LIBRARY NAMES xcb libxcb)
# Add xcb info to LIBXCB_LIBRARIES and LIBXCB_INCLUDE_DIRS
SET(LIBXCB_LIBRARIES ${LIBXCB_LIBRARY})
SET(LIBXCB_INCLUDE_DIRS ${LIBXCB_INCLUDE_DIR})
find_package_handle_standard_args(LIBXCB DEFAULT_MSG
LIBXCB_LIBRARY LIBXCB_INCLUDE_DIR)
mark_as_advanced(LIBXCB_LIBRARY LIBXCB_INCLUDE_DIR)
# Check whether we should search for XLIB_XCB
set(FIND_XLIB_XCB FALSE)
FOREACH(XCB_COMPONENT ${XCB_FIND_COMPONENTS})
# Generate upper string of the component name
string(TOUPPER ${XCB_COMPONENT} XCB_COMPONENT_UPPER)
IF(${XCB_COMPONENT_UPPER} MATCHES "XLIB_XCB")
set(FIND_XLIB_XCB TRUE)
ELSE()
# XCB_COMPONENTS is generated to be a copy of XCB_FIND_COMPONENTS
# without XLIB_XCB (for later component search)
set(XCB_COMPONENTS ${XCB_COMPONENTS} ${XCB_COMPONENT})
ENDIF()
ENDFOREACH()
# Find XLIB_XCB if requested
IF(FIND_XLIB_XCB)
FIND_PATH(XLIB_XCB_INCLUDE_DIR X11/Xlib-xcb.h)
FIND_LIBRARY(XLIB_XCB_LIBRARY NAMES X11-xcb libX11-xcb)
SET(XLIB_XCB_LIBRARIES ${XLIB_XCB_LIBRARY})
SET(XLIB_XCB_INCLUDE_DIRS ${XLIB_XCB_INCLUDE_DIR})
find_package_handle_standard_args(XLIB_XCB DEFAULT_MSG
XLIB_XCB_LIBRARY LIBXCB_INCLUDE_DIR)
mark_as_advanced(XLIB_XCB_LIBRARY XLIB_XCB_INCLUDE_DIR)
# Add xlib_xcb info to LIBXCB_LIBRARIES and LIBXCB_INCLUDE_DIRS
set(LIBXCB_LIBRARIES ${LIBXCB_LIBRARIES} ${XLIB_XCB_LIBRARIES})
set(LIBXCB_INCLUDE_DIRS ${LIBXCB_INCLUDE_DIRS} ${XLIB_XCB_INCLUDE_DIR})
if(NOT XLIB_XCB_FOUND)
message(FATAL_ERROR "XlibXcb library not found")
endif()
ELSE()
# Add component name to the component list
set(${XCB_COMPONENTS} ${XCB_FIND_COMPONENTS})
ENDIF()
# Loop through requested xcb components (does not contain xlib_xcb)
FOREACH(XCB_COMPONENT ${XCB_COMPONENTS})
# Generate lower and upper string of the component name
string(TOLOWER ${XCB_COMPONENT} XCB_COMPONENT_LOWER)
string(TOUPPER ${XCB_COMPONENT} XCB_COMPONENT_UPPER)
# Find the specific component
FIND_LIBRARY(LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY
NAMES libxcb-${XCB_COMPONENT_LOWER} xcb-${XCB_COMPONENT_LOWER})
find_package_handle_standard_args(LIBXCB_${XCB_COMPONENT_UPPER} DEFAULT_MSG
LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY LIBXCB_INCLUDE_DIR)
mark_as_advanced(LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY)
# Append the component's library path to LIBXCB_LIBRARIES
set(LIBXCB_LIBRARIES ${LIBXCB_LIBRARIES} ${LIBXCB_${XCB_COMPONENT_UPPER}_LIBRARY})
if(NOT LIBXCB_${XCB_COMPONENT_UPPER}_FOUND)
message(FATAL_ERROR "xcb-${XCB_COMPONENT_LOWER} not found")
endif()
ENDFOREACH()
endif()

View File

@ -69,6 +69,8 @@ if(SFML_OS_WINDOWS)
add_definitions(-DUNICODE -D_UNICODE) add_definitions(-DUNICODE -D_UNICODE)
elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD) elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
set(PLATFORM_SRC set(PLATFORM_SRC
${SRCROOT}/Linux/AutoPointer.cpp
${SRCROOT}/Linux/AutoPointer.hpp
${SRCROOT}/Unix/Display.cpp ${SRCROOT}/Unix/Display.cpp
${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/Display.hpp
${SRCROOT}/Unix/InputImpl.cpp ${SRCROOT}/Unix/InputImpl.cpp
@ -193,11 +195,11 @@ if(NOT SFML_OPENGL_ES)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR}) include_directories(${OPENGL_INCLUDE_DIR})
if(SFML_OS_LINUX OR SFML_OS_FREEBSD) if(SFML_OS_LINUX OR SFML_OS_FREEBSD)
find_package(X11 REQUIRED) find_package(XCB COMPONENTS xlib_xcb atom icccm image randr REQUIRED)
if(NOT X11_Xrandr_FOUND) if(NOT LIBXCB_FOUND)
message(FATAL_ERROR "Xrandr library not found") message(FATAL_ERROR "Xcb library not found")
endif() endif()
include_directories(${X11_INCLUDE_DIR}) include_directories(${LIBXCB_INCLUDE_DIRS})
endif() endif()
endif() endif()
if(SFML_OPENGL_ES AND SFML_OS_LINUX) if(SFML_OPENGL_ES AND SFML_OS_LINUX)
@ -217,10 +219,11 @@ endif()
# build the list of external libraries to link # build the list of external libraries to link
if(SFML_OS_WINDOWS) if(SFML_OS_WINDOWS)
list(APPEND WINDOW_EXT_LIBS winmm gdi32) list(APPEND WINDOW_EXT_LIBS winmm gdi32)
elseif(SFML_OS_LINUX) elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} ${UDEV_LIBRARIES}) list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} ${LIBXCB_LIBRARIES} ${UDEV_LIBRARIES})
elseif(SFML_OS_FREEBSD) if(SFML_OS_FREEBSD)
list(APPEND WINDOW_EXT_LIBS ${X11_X11_LIB} ${X11_Xrandr_LIB} usbhid) list(APPEND WINDOW_EXT_LIBS usbhid)
endif()
elseif(SFML_OS_MACOSX) elseif(SFML_OS_MACOSX)
list(APPEND WINDOW_EXT_LIBS "-framework Foundation -framework AppKit -framework IOKit -framework Carbon") list(APPEND WINDOW_EXT_LIBS "-framework Foundation -framework AppKit -framework IOKit -framework Carbon")
elseif(SFML_OS_IOS) elseif(SFML_OS_IOS)

View File

@ -0,0 +1,44 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2012 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Linux/AutoPointer.hpp>
#include <cstdlib>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
ErrorPointer::ErrorPointer(xcb_connection_t *&connection, xcb_void_cookie_t &cookie)
: AutoPointer(xcb_request_check(connection, cookie))
{
}
} // namespace priv
} // namespace sf

View File

@ -0,0 +1,132 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2012 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef AUTOPOINTER_HPP
#define AUTOPOINTER_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <X11/Xlib-xcb.h>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Pointer Wrapper. Memory is automatically free'd
/// on deletion of the object.
///
////////////////////////////////////////////////////////////
template<typename T>
class AutoPointer
{
public:
////////////////////////////////////////////////////////////
/// \brief Constructor
///
////////////////////////////////////////////////////////////
AutoPointer(T* ptr)
{
pointer = ptr;
}
////////////////////////////////////////////////////////////
/// \brief Constructor
///
////////////////////////////////////////////////////////////
AutoPointer()
: pointer(NULL)
{
}
////////////////////////////////////////////////////////////
/// \brief Destructor, frees the error pointer
///
////////////////////////////////////////////////////////////
~AutoPointer()
{
free(pointer);
}
////////////////////////////////////////////////////////////
/// \brief Operator for error member access
///
////////////////////////////////////////////////////////////
T* operator->() const
{
return pointer;
}
////////////////////////////////////////////////////////////
/// \brief Assignment operator. Frees the previous pointer
///
////////////////////////////////////////////////////////////
T* operator=(T*& new_pointer) const
{
free(pointer);
pointer = new_pointer;
}
T** operator&()
{
return &pointer;
}
////////////////////////////////////////////////////////////
/// \brief Check if reqeust succeeded
///
/// \return true if reqeust succeeded
///
////////////////////////////////////////////////////////////
bool isNull() const
{
return pointer == NULL;
}
private:
T* pointer;
};
////////////////////////////////////////////////////////////
/// \brief Wrapper for automatically creating and freeing
/// an error struct out of a cookie
///
////////////////////////////////////////////////////////////
class ErrorPointer : public AutoPointer<xcb_generic_error_t>
{
public:
////////////////////////////////////////////////////////////
/// \brief Construct the error pointer from a cookie
///
////////////////////////////////////////////////////////////
ErrorPointer(xcb_connection_t*& connection, xcb_void_cookie_t& cookie);
};
} // namespace priv
} // namespace sf
#endif // AUTOPOINTER_HPP

View File

@ -63,6 +63,13 @@ Display* OpenDisplay()
} }
////////////////////////////////////////////////////////////
xcb_connection_t* OpenConnection()
{
return XGetXCBConnection(OpenDisplay());
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CloseDisplay(Display* display) void CloseDisplay(Display* display)
{ {
@ -73,6 +80,27 @@ void CloseDisplay(Display* display)
XCloseDisplay(display); XCloseDisplay(display);
} }
////////////////////////////////////////////////////////////
void CloseConnection(xcb_connection_t* connection)
{
assert(connection == XGetXCBConnection(sharedDisplay));
return CloseDisplay(sharedDisplay);
}
////////////////////////////////////////////////////////////
xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr)
{
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
for (; iter.rem; --screen_nbr, xcb_screen_next (&iter))
{
if (screen_nbr == 0)
return iter.data;
}
return NULL;
}
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -28,7 +28,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <X11/Xlib.h> #include <X11/Xlib-xcb.h>
namespace sf namespace sf
@ -47,13 +47,42 @@ namespace priv
Display* OpenDisplay(); Display* OpenDisplay();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Release a reference to the shared /// \brief Get the xcb connection of the shared Display
/// ///
/// \param display Display to release /// This function increments the reference count of the display,
/// it must be matched with a call to CloseDisplay.
///
/// \return Pointer to the shared connection
///
////////////////////////////////////////////////////////////
xcb_connection_t* OpenConnection();
////////////////////////////////////////////////////////////
/// \brief Release a reference to the shared display
///
/// \param Display to release
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CloseDisplay(Display* display); void CloseDisplay(Display* display);
////////////////////////////////////////////////////////////
/// \brief Release a reference to the shared display
///
/// \param Connection of display to release
///
////////////////////////////////////////////////////////////
void CloseConnection(xcb_connection_t* connection);
////////////////////////////////////////////////////////////
/// \brief Get screen of a display by index (equivalent to XScreenOfDisplay)
///
/// \param The index of the screen
///
/// \return Pointer to the screen
///
////////////////////////////////////////////////////////////
xcb_screen_t* XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr);
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -44,18 +44,22 @@ m_ownsWindow(true)
{ {
// Open a connection with the X server // Open a connection with the X server
m_display = OpenDisplay(); m_display = OpenDisplay();
m_connection = XGetXCBConnection(m_display);
// Create a dummy window (disabled and hidden) // Create a dummy window (disabled and hidden)
int screen = DefaultScreen(m_display); xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display));
m_window = XCreateWindow(m_display, m_window = xcb_generate_id(m_connection);
RootWindow(m_display, screen), xcb_create_window(
m_connection,
screen->root_depth,
m_window, screen->root,
0, 0, 0, 0,
1, 1, 1, 1,
0, 0,
DefaultDepth(m_display, screen), XCB_WINDOW_CLASS_INPUT_OUTPUT,
InputOutput, screen->root_visual,
DefaultVisual(m_display, screen), 0, NULL
0, NULL); );
// Create the context // Create the context
createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings()); createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings());
@ -71,6 +75,7 @@ m_ownsWindow(false)
// Open a connection with the X server // Open a connection with the X server
// (important: must be the same display as the owner window) // (important: must be the same display as the owner window)
m_display = OpenDisplay(); m_display = OpenDisplay();
m_connection = XGetXCBConnection(m_display);
// Get the owner window and its device context // Get the owner window and its device context
m_window = static_cast< ::Window>(owner->getSystemHandle()); m_window = static_cast< ::Window>(owner->getSystemHandle());
@ -89,18 +94,22 @@ m_ownsWindow(true)
{ {
// Open a connection with the X server // Open a connection with the X server
m_display = OpenDisplay(); m_display = OpenDisplay();
m_connection = XGetXCBConnection(m_display);
// Create the hidden window // Create the hidden window
int screen = DefaultScreen(m_display); xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, DefaultScreen(m_display));
m_window = XCreateWindow(m_display, m_window = xcb_generate_id(m_connection);
RootWindow(m_display, screen), xcb_create_window(
m_connection,
screen->root_depth,
m_window, screen->root,
0, 0, 0, 0,
width, height, width, height,
0, 0,
DefaultDepth(m_display, screen), XCB_WINDOW_CLASS_INPUT_OUTPUT,
InputOutput, screen->root_visual,
DefaultVisual(m_display, screen), 0, NULL
0, NULL); );
// Create the context // Create the context
createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings); createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings);
@ -121,8 +130,8 @@ GlxContext::~GlxContext()
// Destroy the window if we own it // Destroy the window if we own it
if (m_window && m_ownsWindow) if (m_window && m_ownsWindow)
{ {
XDestroyWindow(m_display, m_window); xcb_destroy_window(m_connection, m_window);
XFlush(m_display); xcb_flush(m_connection);
} }
// Close the connection with the X server // Close the connection with the X server
@ -211,26 +220,88 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings)
{ {
XVisualInfo* visualInfo = NULL;
// Save the creation settings // Save the creation settings
m_settings = settings; m_settings = settings;
// Get the attributes of the target window
XWindowAttributes windowAttributes;
if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0)
{
err() << "Failed to get the window attributes" << std::endl;
return;
}
// Setup the visual infos to match
XVisualInfo tpl;
tpl.depth = windowAttributes.depth;
tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
tpl.screen = DefaultScreen(m_display);
// Get all the visuals matching the template
int nbVisuals = 0;
XVisualInfo* visuals = XGetVisualInfo(m_display, VisualDepthMask | VisualIDMask | VisualScreenMask, &tpl, &nbVisuals);
if (!visuals || (nbVisuals == 0))
{
if (visuals)
XFree(visuals);
err() << "There is no valid visual for the selected screen" << std::endl;
return;
}
// Find the best visual
int bestScore = 0xFFFF;
XVisualInfo* bestVisual = NULL;
for (int i = 0; i < nbVisuals; ++i)
{
// Get the current visual attributes
int RGBA, doubleBuffer, red, green, blue, alpha, depth, stencil, multiSampling, samples;
glXGetConfig(m_display, &visuals[i], GLX_RGBA, &RGBA);
glXGetConfig(m_display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer);
glXGetConfig(m_display, &visuals[i], GLX_RED_SIZE, &red);
glXGetConfig(m_display, &visuals[i], GLX_GREEN_SIZE, &green);
glXGetConfig(m_display, &visuals[i], GLX_BLUE_SIZE, &blue);
glXGetConfig(m_display, &visuals[i], GLX_ALPHA_SIZE, &alpha);
glXGetConfig(m_display, &visuals[i], GLX_DEPTH_SIZE, &depth);
glXGetConfig(m_display, &visuals[i], GLX_STENCIL_SIZE, &stencil);
glXGetConfig(m_display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
glXGetConfig(m_display, &visuals[i], GLX_SAMPLES_ARB, &samples);
// First check the mandatory parameters
if ((RGBA == 0) || (doubleBuffer == 0))
continue;
// Evaluate the current configuration
int color = red + green + blue + alpha;
int score = evaluateFormat(bitsPerPixel, m_settings, color, depth, stencil, multiSampling ? samples : 0);
// Keep it if it's better than the current best
if (score < bestScore)
{
bestScore = score;
bestVisual = &visuals[i];
}
}
// Make sure that we have found a visual
if (!bestVisual)
{
err() << "Failed to find a suitable pixel format for the window -- cannot create OpenGL context" << std::endl;
return;
}
// Get the context to share display lists with // Get the context to share display lists with
GLXContext toShare = shared ? shared->m_context : NULL; 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) // Create the OpenGL context -- first try context versions >= 3.0 if it is requested (they require special code)
if (m_settings.majorVersion >= 3) while (!m_context && (m_settings.majorVersion >= 3))
{ {
const GLubyte* name = reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB"); const GLubyte* name = reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB");
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddress(name)); PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(glXGetProcAddress(name));
if (glXCreateContextAttribsARB) if (glXCreateContextAttribsARB)
{ {
// Select a GLXFB config that matches the requested context settings
int nbConfigs = 0; int nbConfigs = 0;
int fbAttributes[] = int fbAttributes[] =
{ {
@ -250,9 +321,8 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
None None
}; };
GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), fbAttributes, &nbConfigs); GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), fbAttributes, &nbConfigs);
if (configs && nbConfigs) if (configs && nbConfigs)
{
while (!m_context && (m_settings.majorVersion >= 3))
{ {
// Create the context // Create the context
int attributes[] = int attributes[] =
@ -263,16 +333,16 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
0, 0 0, 0
}; };
m_context = glXCreateContextAttribsARB(m_display, configs[0], toShare, true, attributes); 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 (configs)
XFree(configs);
}
// If we couldn't create the context, lower the version number and try again -- stop at 3.0 // 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 // Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care
if (!m_context)
{
if (m_settings.minorVersion > 0) if (m_settings.minorVersion > 0)
{ {
// If the minor version is not 0, we decrease it and try again // If the minor version is not 0, we decrease it and try again
@ -286,10 +356,6 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
} }
} }
} }
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 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) if (!m_context)
@ -298,23 +364,7 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
m_settings.majorVersion = 2; m_settings.majorVersion = 2;
m_settings.minorVersion = 0; m_settings.minorVersion = 0;
// Retrieve the attributes of the target window m_context = glXCreateContext(m_display, bestVisual, toShare, true);
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) if (!m_context)
{ {
err() << "Failed to create an OpenGL context for this window" << std::endl; err() << "Failed to create an OpenGL context for this window" << std::endl;
@ -324,16 +374,21 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
// Update the creation settings from the chosen format // Update the creation settings from the chosen format
int depth, stencil, multiSampling, samples; int depth, stencil, multiSampling, samples;
glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth); glXGetConfig(m_display, bestVisual, GLX_DEPTH_SIZE, &depth);
glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil); glXGetConfig(m_display, bestVisual, GLX_STENCIL_SIZE, &stencil);
glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling); glXGetConfig(m_display, bestVisual, GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples); glXGetConfig(m_display, bestVisual, GLX_SAMPLES_ARB, &samples);
m_settings.depthBits = static_cast<unsigned int>(depth); m_settings.depthBits = static_cast<unsigned int>(depth);
m_settings.stencilBits = static_cast<unsigned int>(stencil); m_settings.stencilBits = static_cast<unsigned int>(stencil);
m_settings.antialiasingLevel = multiSampling ? samples : 0; m_settings.antialiasingLevel = multiSampling ? samples : 0;
// Free the visual info // Change the target window's colormap so that it matches the context's one
XFree(visualInfo); ::Window root = RootWindow(m_display, DefaultScreen(m_display));
Colormap colorMap = XCreateColormap(m_display, root, bestVisual->visual, AllocNone);
XSetWindowColormap(m_display, m_window, colorMap);
// Free the temporary visuals array
XFree(visuals);
} }
} // namespace priv } // namespace priv

View File

@ -29,7 +29,7 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/GlContext.hpp> #include <SFML/Window/GlContext.hpp>
#include <X11/Xlib.h> #include <X11/Xlib-xcb.h>
#include <GL/glx.h> #include <GL/glx.h>
@ -137,6 +137,7 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
::Display* m_display; ///< Connection to the X server ::Display* m_display; ///< Connection to the X server
::Window m_window; ///< Window to which the context is attached ::Window m_window; ///< Window to which the context is attached
xcb_connection_t* m_connection; ///< Pointer to the xcb connection
GLXContext m_context; ///< OpenGL context GLXContext m_context; ///< OpenGL context
bool m_ownsWindow; ///< Do we own the window associated to the context? bool m_ownsWindow; ///< Do we own the window associated to the context?
}; };

View File

@ -28,8 +28,10 @@
#include <SFML/Window/Unix/InputImpl.hpp> #include <SFML/Window/Unix/InputImpl.hpp>
#include <SFML/Window/Window.hpp> #include <SFML/Window/Window.hpp>
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <X11/Xlib.h> #include <SFML/Window/Linux/AutoPointer.hpp>
#include <X11/Xlib-xcb.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <cstdlib>
namespace sf namespace sf
@ -149,20 +151,20 @@ bool InputImpl::isKeyPressed(Keyboard::Key key)
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
// Convert to keycode // Convert to keycode
KeyCode keycode = XKeysymToKeycode(display, keysym); KeyCode keycode = XKeysymToKeycode(display, keysym);
if (keycode != 0) if (keycode != 0)
{ {
// Get the whole keyboard state // Get the whole keyboard state
char keys[32]; AutoPointer<xcb_query_keymap_reply_t> keymap = xcb_query_keymap_reply(connection, xcb_query_keymap(connection), NULL);
XQueryKeymap(display, keys);
// Close the connection with the X server // Close the connection with the X server
CloseDisplay(display); CloseDisplay(display);
// Check our keycode // Check our keycode
return (keys[keycode / 8] & (1 << (keycode % 8))) != 0; return (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0;
} }
else else
{ {
@ -186,29 +188,24 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button)
{ {
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
// we don't care about these but they are required // Get pointer mask
::Window root, child; AutoPointer<xcb_query_pointer_reply_t> pointer =
int wx, wy; xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL);
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 // Close the connection with the X server
CloseDisplay(display); CloseDisplay(display);
switch (button) switch (button)
{ {
case Mouse::Left: return buttons & Button1Mask; case Mouse::Left: return pointer->mask & XCB_BUTTON_MASK_1;
case Mouse::Right: return buttons & Button3Mask; case Mouse::Right: return pointer->mask & XCB_BUTTON_MASK_3;
case Mouse::Middle: return buttons & Button2Mask; case Mouse::Middle: return pointer->mask & XCB_BUTTON_MASK_2;
case Mouse::XButton1: return false; // not supported by X case Mouse::XButton1: // not supported by X
case Mouse::XButton2: return false; // not supported by X case Mouse::XButton2: // not supported by X
default: return false; default: return false;
} }
return false;
} }
@ -217,20 +214,15 @@ Vector2i InputImpl::getMousePosition()
{ {
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
// we don't care about these but they are required AutoPointer<xcb_query_pointer_reply_t> pointer =
::Window root, child; xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL);
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 // Close the connection with the X server
CloseDisplay(display); CloseDisplay(display);
return Vector2i(gx, gy); return Vector2i(pointer->root_x, pointer->root_y);
} }
@ -241,21 +233,15 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo)
if (handle) if (handle)
{ {
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); xcb_connection_t* connection = OpenConnection();
// we don't care about these but they are required AutoPointer<xcb_query_pointer_reply_t> pointer =
::Window root, child; xcb_query_pointer_reply(connection, xcb_query_pointer(connection, handle), NULL);
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 // Close the connection with the X server
CloseDisplay(display); CloseConnection(connection);
return Vector2i(x, y); return Vector2i(pointer->win_x, pointer->win_y);
} }
else else
{ {
@ -269,9 +255,10 @@ void InputImpl::setMousePosition(const Vector2i& position)
{ {
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y); xcb_warp_pointer(connection, None, XDefaultRootWindow(display), 0, 0, 0, 0, position.x, position.y);
XFlush(display); xcb_flush(connection);
// Close the connection with the X server // Close the connection with the X server
CloseDisplay(display); CloseDisplay(display);
@ -282,17 +269,17 @@ void InputImpl::setMousePosition(const Vector2i& position)
void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo) void InputImpl::setMousePosition(const Vector2i& position, const Window& relativeTo)
{ {
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); xcb_connection_t* connection = OpenConnection();
WindowHandle handle = relativeTo.getSystemHandle(); WindowHandle handle = relativeTo.getSystemHandle();
if (handle) if (handle)
{ {
XWarpPointer(display, None, handle, 0, 0, 0, 0, position.x, position.y); xcb_warp_pointer(connection, None, handle, 0, 0, 0, 0, position.x, position.y);
XFlush(display); xcb_flush(connection);
} }
// Close the connection with the X server // Close the connection with the X server
CloseDisplay(display); CloseConnection(connection);
} }

View File

@ -28,8 +28,8 @@
#include <SFML/Window/VideoModeImpl.hpp> #include <SFML/Window/VideoModeImpl.hpp>
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <X11/Xlib.h> #include <X11/Xlib-xcb.h>
#include <X11/extensions/Xrandr.h> #include <xcb/randr.h>
#include <algorithm> #include <algorithm>
@ -44,63 +44,62 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
if (display) if (display)
{ {
// Retrieve the default screen number // Check if the XRandR extension is present
int screen = DefaultScreen(display); xcb_query_extension_cookie_t cookie = xcb_query_extension(connection, 5, "RANDR");
// Retrieve the default screen
xcb_screen_t* screen = XCBScreenOfDisplay(connection, DefaultScreen(display));
// Check if the XRandR extension is present // Check if the XRandR extension is present
int version; xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(connection, cookie, NULL);
if (XQueryExtension(display, "RANDR", &version, &version, &version)) if (randr_ext->present)
{ {
// Get the current configuration // Get the current configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); xcb_generic_error_t* errors;
if (config) xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply(
connection, xcb_randr_get_screen_info(connection, screen->root), &errors);
if (! errors)
{ {
// Get the available screen sizes // Get the available screen sizes
int nbSizes; xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config);
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); if (sizes && (config->nSizes > 0))
if (sizes && (nbSizes > 0))
{ {
// Get the list of supported depths // Get the list of supported depths
int nbDepths = 0; xcb_depth_iterator_t iter = xcb_screen_allowed_depths_iterator(screen);
int* depths = XListDepths(display, screen, &nbDepths);
if (depths && (nbDepths > 0))
{
// Combine depths and sizes to fill the array of supported modes // Combine depths and sizes to fill the array of supported modes
for (int i = 0; i < nbDepths; ++i) for (; iter.rem; xcb_depth_next(&iter))
{ {
for (int j = 0; j < nbSizes; ++j) for (int j = 0; j < config->nSizes; ++j)
{ {
// Convert to VideoMode // Convert to VideoMode
VideoMode mode(sizes[j].width, sizes[j].height, depths[i]); VideoMode mode(sizes[j].width, sizes[j].height, iter.data->depth);
// Add it only if it is not already in the array // Add it only if it is not already in the array
if (std::find(modes.begin(), modes.end(), mode) == modes.end()) if (std::find(modes.begin(), modes.end(), mode) == modes.end())
modes.push_back(mode); modes.push_back(mode);
} }
} }
// Free the array of depths
XFree(depths);
} }
} }
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
}
else else
{ {
// Failed to get the screen configuration // Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl; err() << "Failed to retrieve the screen configuration while trying to get the supported video modes" << std::endl;
} }
// Free the configuration instance
free(errors);
free(config);
} }
else else
{ {
// XRandr extension is not supported: we cannot get the video modes // 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; err() << "Failed to use the XRandR extension while trying to get the supported video modes" << std::endl;
} }
free(randr_ext);
// Close the connection with the X server // Close the connection with the X server
CloseDisplay(display); CloseDisplay(display);
} }
@ -121,37 +120,42 @@ VideoMode VideoModeImpl::getDesktopMode()
// Open a connection with the X server // Open a connection with the X server
Display* display = OpenDisplay(); Display* display = OpenDisplay();
xcb_connection_t* connection = XGetXCBConnection(display);
if (display) if (display)
{ {
// Retrieve the default screen number xcb_query_extension_cookie_t cookie = xcb_query_extension(connection, 5, "RANDR");
int screen = DefaultScreen(display); // Retrieve the default screen
xcb_screen_t* screen = XCBScreenOfDisplay(connection, DefaultScreen(display));
// Check if the XRandR extension is present // Check if the XRandR extension is present
int version; xcb_query_extension_reply_t* randr_ext = xcb_query_extension_reply(connection, cookie, NULL);
if (XQueryExtension(display, "RANDR", &version, &version, &version)) if (randr_ext->present)
{ {
// Get the current configuration // Get the current configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); xcb_generic_error_t* errors;
if (config) xcb_randr_get_screen_info_reply_t* config =
xcb_randr_get_screen_info_reply(
connection, xcb_randr_get_screen_info(connection, screen->root), &errors);
if (! errors)
{ {
// Get the current video mode // Get the current video mode
Rotation currentRotation; xcb_randr_rotation_t Rotation = (xcb_randr_rotation_t)config->rotation;
int currentMode = XRRConfigCurrentConfiguration(config, &currentRotation); xcb_randr_mode_t currentMode = config->sizeID;
// Get the available screen sizes // Get the available screen sizes
int nbSizes; int nbSizes = xcb_randr_get_screen_info_sizes_length(config);
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); xcb_randr_screen_size_t* sizes= xcb_randr_get_screen_info_sizes(config);
if (sizes && (nbSizes > 0)) if (sizes && (nbSizes > 0))
desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, DefaultDepth(display, screen)); desktopMode = VideoMode(sizes[currentMode].width, sizes[currentMode].height, screen->root_depth);
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
} }
else else
{ {
// Failed to get the screen configuration // Failed to get the screen configuration
err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl; err() << "Failed to retrieve the screen configuration while trying to get the desktop video modes" << std::endl;
} }
// Free the configuration instance
free(errors);
free(config);
} }
else else
{ {
@ -159,6 +163,7 @@ VideoMode VideoModeImpl::getDesktopMode()
err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl; err() << "Failed to use the XRandR extension while trying to get the desktop video modes" << std::endl;
} }
free(randr_ext);
// Close the connection with the X server // Close the connection with the X server
CloseDisplay(display); CloseDisplay(display);
} }

View File

@ -28,14 +28,15 @@
#include <SFML/Window/WindowStyle.hpp> // important to be included first (conflict with None) #include <SFML/Window/WindowStyle.hpp> // important to be included first (conflict with None)
#include <SFML/Window/Unix/WindowImplX11.hpp> #include <SFML/Window/Unix/WindowImplX11.hpp>
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Linux/AutoPointer.hpp>
#include <SFML/System/Utf.hpp> #include <SFML/System/Utf.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <X11/Xutil.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/extensions/Xrandr.h> #include <X11/Xutil.h>
#include <libgen.h> #include <xcb/xcb_atom.h>
#include <unistd.h> #include <xcb/xcb_icccm.h>
#include <cstring> #include <xcb/xcb_image.h>
#include <xcb/randr.h>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <string> #include <string>
@ -104,6 +105,7 @@ m_useSizeHints(false)
{ {
// Open a connection with the X server // Open a connection with the X server
m_display = OpenDisplay(); m_display = OpenDisplay();
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
m_screen = DefaultScreen(m_display); m_screen = DefaultScreen(m_display);
// Save the window handle // Save the window handle
@ -135,8 +137,14 @@ m_useSizeHints(false)
{ {
// Open a connection with the X server // Open a connection with the X server
m_display = OpenDisplay(); m_display = OpenDisplay();
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
m_connection = XGetXCBConnection(m_display);
if (! m_connection)
{
err() << "Failed cast Display object to an XCB connection object" << std::endl;
return;
}
m_screen = DefaultScreen(m_display); m_screen = DefaultScreen(m_display);
::Window root = RootWindow(m_display, m_screen);
// Compute position and size // Compute position and size
int left, top; int left, top;
@ -162,22 +170,26 @@ m_useSizeHints(false)
XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings); XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings);
// Define the window attributes // Define the window attributes
XSetWindowAttributes attributes; const uint32_t value_list[] = {fullscreen, eventMask};
attributes.override_redirect = fullscreen;
attributes.event_mask = eventMask;
attributes.colormap = XCreateColormap(m_display, root, visualInfo.visual, AllocNone);
// Create the window // Create the window
m_window = XCreateWindow(m_display, m_window = xcb_generate_id(m_connection);
root,
xcb_void_cookie_t cookie = xcb_create_window_checked(
m_connection,
XCB_COPY_FROM_PARENT,
m_window,
RootWindow(m_display, m_screen),
left, top, left, top,
width, height, width, height,
0, 0,
visualInfo.depth, XCB_WINDOW_CLASS_INPUT_OUTPUT,
InputOutput, XCB_COPY_FROM_PARENT,
visualInfo.visual, XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT,
CWEventMask | CWOverrideRedirect | CWColormap, &attributes); value_list);
if (!m_window)
ErrorPointer errptr(m_connection, cookie);
if(! errptr.isNull())
{ {
err() << "Failed to create window" << std::endl; err() << "Failed to create window" << std::endl;
return; return;
@ -189,7 +201,7 @@ m_useSizeHints(false)
// Set the window's style (tell the windows manager to change our window's decorations and functions according to the requested style) // Set the window's style (tell the windows manager to change our window's decorations and functions according to the requested style)
if (!fullscreen) if (!fullscreen)
{ {
Atom WMHintsAtom = XInternAtom(m_display, "_MOTIF_WM_HINTS", false); xcb_atom_t WMHintsAtom = xcb_atom_get(m_connection, "_MOTIF_WM_HINTS");
if (WMHintsAtom) if (WMHintsAtom)
{ {
static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0; static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0;
@ -212,11 +224,11 @@ m_useSizeHints(false)
struct WMHints struct WMHints
{ {
unsigned long flags; uint32_t flags;
unsigned long functions; uint32_t functions;
unsigned long decorations; uint32_t decorations;
long inputMode; int32_t inputMode;
unsigned long state; uint32_t state;
}; };
WMHints hints; WMHints hints;
@ -241,19 +253,18 @@ m_useSizeHints(false)
} }
const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&hints); const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&hints);
XChangeProperty(m_display, m_window, WMHintsAtom, WMHintsAtom, 32, PropModeReplace, ptr, 5); xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
WMHintsAtom, WM_HINTS, 32, 5, ptr);
} }
// This is a hack to force some windows managers to disable resizing // This is a hack to force some windows managers to disable resizing
if (!(style & Style::Resize)) if (!(style & Style::Resize))
{ {
m_useSizeHints = true; xcb_size_hints_t sizeHints;
XSizeHints* sizeHints = XAllocSizeHints(); sizeHints.flags = XCB_SIZE_HINT_P_MIN_SIZE | XCB_SIZE_HINT_P_MAX_SIZE;
sizeHints->flags = PMinSize | PMaxSize; sizeHints.min_width = sizeHints.max_width = width;
sizeHints->min_width = sizeHints->max_width = width; sizeHints.min_height = sizeHints.max_height = height;
sizeHints->min_height = sizeHints->max_height = height; xcb_set_wm_normal_hints(m_connection, m_window, &sizeHints);
XSetWMNormalHints(m_display, m_window, sizeHints);
XFree(sizeHints);
} }
} }
@ -272,8 +283,8 @@ m_useSizeHints(false)
// In fullscreen mode, we must grab keyboard and mouse inputs // In fullscreen mode, we must grab keyboard and mouse inputs
if (fullscreen) if (fullscreen)
{ {
XGrabPointer(m_display, m_window, true, 0, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); xcb_grab_pointer(m_connection, True, m_window, 0, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, m_window, XCB_NONE, XCB_CURRENT_TIME);
XGrabKeyboard(m_display, m_window, true, GrabModeAsync, GrabModeAsync, CurrentTime); xcb_grab_keyboard(m_connection, True, m_window, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
} }
} }
@ -286,7 +297,7 @@ WindowImplX11::~WindowImplX11()
// Destroy the cursor // Destroy the cursor
if (m_hiddenCursor) if (m_hiddenCursor)
XFreeCursor(m_display, m_hiddenCursor); xcb_free_cursor(m_connection, m_hiddenCursor);
// Destroy the input context // Destroy the input context
if (m_inputContext) if (m_inputContext)
@ -295,8 +306,8 @@ WindowImplX11::~WindowImplX11()
// Destroy the window // Destroy the window
if (m_window && !m_isExternal) if (m_window && !m_isExternal)
{ {
XDestroyWindow(m_display, m_window); xcb_destroy_window(m_connection, m_window);
XFlush(m_display); xcb_flush(m_connection);
} }
// Close the input method // Close the input method
@ -321,10 +332,10 @@ WindowHandle WindowImplX11::getSystemHandle() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::processEvents() void WindowImplX11::processEvents()
{ {
XEvent event; while(xcb_generic_event_t* event = xcb_poll_for_event(m_connection))
while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window)))
{ {
processEvent(event); processEvent(event);
free(event);
} }
} }
@ -332,71 +343,51 @@ void WindowImplX11::processEvents()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector2i WindowImplX11::getPosition() const Vector2i WindowImplX11::getPosition() const
{ {
::Window root, child; AutoPointer<xcb_get_geometry_reply_t> reply =
int localX, localY, x, y; xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL);
unsigned int width, height, border, depth; return Vector2i(reply->x, reply->y);
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) void WindowImplX11::setPosition(const Vector2i& position)
{ {
XMoveWindow(m_display, m_window, position.x, position.y); uint32_t values[] = {position.x, position.y};
XFlush(m_display); xcb_configure_window(m_connection, m_window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
values);
xcb_flush(m_connection);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Vector2u WindowImplX11::getSize() const Vector2u WindowImplX11::getSize() const
{ {
XWindowAttributes attributes; AutoPointer<xcb_get_geometry_reply_t> reply =
XGetWindowAttributes(m_display, m_window, &attributes); xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL);
return Vector2u(attributes.width, attributes.height); return Vector2u(reply->width, reply->height);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::setSize(const Vector2u& size) void WindowImplX11::setSize(const Vector2u& size)
{ {
// If we used size hint to fix the size of the window, we must update them uint32_t values[] = {size.x, size.y};
if (m_useSizeHints) xcb_configure_window(m_connection, m_window,
{ XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
XSizeHints* sizeHints = XAllocSizeHints(); values);
sizeHints->flags = PMinSize | PMaxSize; xcb_flush(m_connection);
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) void WindowImplX11::setTitle(const String& title)
{ {
// Bare X11 has no Unicode window title support. const char* c_title = title.c_str();
// There is however an option to tell the window manager your Unicode title via hints. xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
WM_NAME, STRING,
// Convert to UTF-8 encoding. 8, title.length(), c_title);
std::basic_string<Uint8> utf8Title; xcb_flush(m_connection);
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());
} }
@ -404,8 +395,7 @@ void WindowImplX11::setTitle(const String& title)
void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels) void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8* pixels)
{ {
// X11 wants BGRA pixels : swap red and blue channels // X11 wants BGRA pixels : swap red and blue channels
// Note: this memory will be freed by XDestroyImage Uint8 iconPixels[width * height * 4];
Uint8* iconPixels = static_cast<Uint8*>(std::malloc(width * height * 4));
for (std::size_t i = 0; i < width * height; ++i) for (std::size_t i = 0; i < width * height; ++i)
{ {
iconPixels[i * 4 + 0] = pixels[i * 4 + 2]; iconPixels[i * 4 + 0] = pixels[i * 4 + 2];
@ -415,20 +405,25 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
} }
// Create the icon pixmap // Create the icon pixmap
Visual* defVisual = DefaultVisual(m_display, m_screen); uint8_t defDepth = DefaultDepth(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); xcb_pixmap_t iconPixmap = xcb_generate_id(m_connection);
if (!iconImage) xcb_create_pixmap(m_connection, defDepth, iconPixmap, RootWindow(m_display, m_screen),
width, height);
xcb_gcontext_t iconGC = xcb_generate_id(m_connection);
xcb_create_gc(m_connection, iconGC, iconPixmap, 0, NULL);
xcb_void_cookie_t cookie = xcb_put_image_checked(
m_connection, XCB_IMAGE_FORMAT_Z_PIXMAP, iconPixmap, iconGC,
width, height, 0, 0, 0, defDepth, sizeof(iconPixels), iconPixels);
xcb_free_gc(m_connection, iconGC);
ErrorPointer errptr(m_connection, cookie);
if (! errptr.isNull())
{ {
err() << "Failed to set the window's icon" << std::endl; err() << "Failed to set the window's icon: Error code " << (int)errptr->error_code << std::endl;
return; 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) // Create the mask pixmap (must have 1 bit depth)
std::size_t pitch = (width + 7) / 8; std::size_t pitch = (width + 7) / 8;
@ -447,17 +442,16 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
} }
} }
} }
Pixmap maskPixmap = XCreatePixmapFromBitmapData(m_display, m_window, (char*)&maskPixels[0], width, height, 1, 0, 1); xcb_pixmap_t maskPixmap = xcb_create_pixmap_from_bitmap_data(m_connection, m_window, (Uint8*)&maskPixels[0], width, height, 1, 0, 1, NULL);
// Send our new icon to the window through the WMHints // Send our new icon to the window through the WMHints
XWMHints* hints = XAllocWMHints(); xcb_wm_hints_t hints;
hints->flags = IconPixmapHint | IconMaskHint; hints.flags = XCB_WM_HINT_ICON_PIXMAP | XCB_WM_HINT_ICON_MASK;
hints->icon_pixmap = iconPixmap; hints.icon_pixmap = iconPixmap;
hints->icon_mask = maskPixmap; hints.icon_mask = maskPixmap;
XSetWMHints(m_display, m_window, hints); xcb_set_wm_hints(m_connection, m_window, &hints);
XFree(hints);
XFlush(m_display); xcb_flush(m_connection);
} }
@ -465,19 +459,20 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
void WindowImplX11::setVisible(bool visible) void WindowImplX11::setVisible(bool visible)
{ {
if (visible) if (visible)
XMapWindow(m_display, m_window); xcb_map_window(m_connection, m_window);
else else
XUnmapWindow(m_display, m_window); xcb_unmap_window(m_connection, m_window);
XFlush(m_display); xcb_flush(m_connection);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::setMouseCursorVisible(bool visible) void WindowImplX11::setMouseCursorVisible(bool visible)
{ {
XDefineCursor(m_display, m_window, visible ? None : m_hiddenCursor); const uint32_t values = visible ? XCB_NONE : m_hiddenCursor;
XFlush(m_display); xcb_change_window_attributes(m_connection, m_window, XCB_CW_CURSOR, &values);
xcb_flush(m_connection);
} }
@ -553,29 +548,37 @@ bool WindowImplX11::hasFocus() const
void WindowImplX11::switchToFullscreen(const VideoMode& mode) void WindowImplX11::switchToFullscreen(const VideoMode& mode)
{ {
// Check if the XRandR extension is present // Check if the XRandR extension is present
int version; xcb_query_extension_reply_t* randr_ext =
if (XQueryExtension(m_display, "RANDR", &version, &version, &version)) xcb_query_extension_reply(m_connection, xcb_query_extension(m_connection, 5, "RANDR"), NULL);
if (randr_ext->present)
{ {
xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, m_screen);
// Get the current configuration // Get the current configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); xcb_generic_error_t* errors;
if (config) xcb_randr_get_screen_info_reply_t* config =
xcb_randr_get_screen_info_reply(m_connection,
xcb_randr_get_screen_info(m_connection, screen->root),
&errors);
if (! errors)
{ {
// Get the current rotation // Save the current video mode before we switch to fullscreen
Rotation currentRotation; m_oldVideoMode = config->sizeID;
m_oldVideoMode = XRRConfigCurrentConfiguration(config, &currentRotation);
// Get the available screen sizes // Get the available screen sizes
int nbSizes; xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config);
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); if (sizes && (config->nSizes > 0))
if (sizes && (nbSizes > 0))
{ {
// Search a matching size // Search a matching size
for (int i = 0; i < nbSizes; ++i) for (int i = 0; i < config->nSizes; ++i)
{ {
if ((sizes[i].width == static_cast<int>(mode.width)) && (sizes[i].height == static_cast<int>(mode.height))) if ((sizes[i].width == static_cast<int>(mode.width)) && (sizes[i].height == static_cast<int>(mode.height)))
{ {
// Switch to fullscreen mode // Switch to fullscreen mode
XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime); xcb_randr_set_screen_config(m_connection,
screen->root,
config->timestamp,
config->config_timestamp,
i, config->rotation, config->rate);
// Set "this" as the current fullscreen window // Set "this" as the current fullscreen window
fullscreenWindow = this; fullscreenWindow = this;
@ -583,30 +586,36 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode)
} }
} }
} }
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
} }
else else
{ {
// Failed to get the screen configuration // Failed to get the screen configuration
err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl; err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl;
} }
free(errors);
free(config);
} }
else else
{ {
// XRandr extension is not supported: we cannot use fullscreen mode // XRandr extension is not supported: we cannot use fullscreen mode
err() << "Fullscreen is not supported, switching to window mode" << std::endl; err() << "Fullscreen is not supported, switching to window mode" << std::endl;
} }
free(randr_ext);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::initialize() void WindowImplX11::initialize()
{ {
// Make sure the "last key release" is initialized with invalid values
m_lastKeyReleaseEvent.response_type = -1;
m_lastKeyReleaseEvent.detail = 0;
m_lastKeyReleaseEvent.time = 0;
// Get the atom defining the close event // Get the atom defining the close event
m_atomClose = XInternAtom(m_display, "WM_DELETE_WINDOW", false); m_atomClose = xcb_atom_get(m_connection, "WM_DELETE_WINDOW");
XSetWMProtocols(m_display, m_window, &m_atomClose, 1); xcb_atom_t wmprotocolsAtom = xcb_atom_get(m_connection, "WM_PROTOCOLS");
xcb_set_wm_protocols(m_connection, wmprotocolsAtom, m_window, 1, &m_atomClose);
// Create the input context // Create the input context
m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL); m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL);
@ -626,14 +635,14 @@ void WindowImplX11::initialize()
err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl; err() << "Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl;
// Show the window // Show the window
XMapWindow(m_display, m_window); xcb_map_window(m_connection, m_window);
XFlush(m_display); xcb_flush(m_connection);
// Create the hidden cursor // Create the hidden cursor
createHiddenCursor(); createHiddenCursor();
// Flush the commands queue // Flush the commands queue
XFlush(m_display); xcb_flush(m_connection);
// Add this window to the global list of windows (required for focus request) // Add this window to the global list of windows (required for focus request)
allWindows.push_back(this); allWindows.push_back(this);
@ -643,20 +652,19 @@ void WindowImplX11::initialize()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::createHiddenCursor() void WindowImplX11::createHiddenCursor()
{ {
xcb_pixmap_t cursorPixmap = xcb_generate_id(m_connection);
m_hiddenCursor = xcb_generate_id(m_connection);
// Create the cursor's pixmap (1x1 pixels) // Create the cursor's pixmap (1x1 pixels)
Pixmap cursorPixmap = XCreatePixmap(m_display, m_window, 1, 1, 1); xcb_create_pixmap(m_connection, 1, cursorPixmap, m_window, 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 // Create the cursor, using the pixmap as both the shape and the mask of the cursor
XColor color; xcb_create_cursor(m_connection, m_hiddenCursor, cursorPixmap, cursorPixmap,
color.flags = DoRed | DoGreen | DoBlue; 0, 0, 0, // Fore color
color.red = color.blue = color.green = 0; 0, 0, 0, // Back color
m_hiddenCursor = XCreatePixmapCursor(m_display, cursorPixmap, cursorPixmap, &color, &color, 0, 0); 0, 0);
// We don't need the pixmap any longer, free it // We don't need the pixmap any longer, free it
XFreePixmap(m_display, cursorPixmap); xcb_free_pixmap(m_connection, cursorPixmap);
} }
@ -666,20 +674,27 @@ void WindowImplX11::cleanup()
// Restore the previous video mode (in case we were running in fullscreen) // Restore the previous video mode (in case we were running in fullscreen)
if (fullscreenWindow == this) if (fullscreenWindow == this)
{ {
// Get current screen info // Retrieve the default screen
XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); xcb_screen_t* screen = XCBScreenOfDisplay(m_connection, m_screen);
if (config)
{
// Get the current rotation
Rotation currentRotation;
XRRConfigCurrentConfiguration(config, &currentRotation);
// Get current screen info
xcb_generic_error_t* errors;
xcb_randr_get_screen_info_reply_t* config = xcb_randr_get_screen_info_reply(
m_connection, xcb_randr_get_screen_info(m_connection, screen->root), &errors);
if (! errors)
{
// Reset the video mode // Reset the video mode
XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime); xcb_randr_set_screen_config(m_connection,
screen->root,
CurrentTime,
config->config_timestamp,
m_oldVideoMode,
config->rotation, config->rate);
// Free the configuration instance // Free the configuration instance
XRRFreeScreenConfigInfo(config); free(config);
} }
free(errors);
// Reset the fullscreen window // Reset the fullscreen window
fullscreenWindow = NULL; fullscreenWindow = NULL;
@ -691,7 +706,7 @@ void WindowImplX11::cleanup()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool WindowImplX11::processEvent(XEvent windowEvent) bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
{ {
// This function implements a workaround to properly discard // This function implements a workaround to properly discard
// repeated key events when necessary. The problem is that the // repeated key events when necessary. The problem is that the
@ -702,26 +717,34 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
// - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false // - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false
// Detect repeated key events // Detect repeated key events
// (code shamelessly taken from SDL) if ((windowEvent->response_type == XCB_KEY_PRESS) ||
if (windowEvent.type == KeyRelease) (windowEvent->response_type == XCB_KEY_RELEASE))
{ {
// Check if there's a matching KeyPress event in the queue xcb_key_press_event_t* press = reinterpret_cast<xcb_key_press_event_t*>(windowEvent);
XEvent nextEvent; if (press->detail < 256)
if (XPending(m_display))
{ {
// Grab it but don't remove it from the queue, it still needs to be processed :) // To detect if it is a repeated key event, we check the current state of the key.
XPeekEvent(m_display, &nextEvent); // - If the state is "down", KeyReleased events must obviously be discarded.
if (nextEvent.type == KeyPress) // - KeyPress events are a little bit harder to handle: they depend on the EnableKeyRepeat state,
{ // and we need to properly forward the first one.
// Check if it is a duplicated event (same timestamp as the KeyRelease event) xcb_query_keymap_cookie_t cookie = xcb_query_keymap(m_connection);
if ((nextEvent.xkey.keycode == windowEvent.xkey.keycode) && AutoPointer<xcb_query_keymap_reply_t> keymap = xcb_query_keymap_reply(m_connection,
(nextEvent.xkey.time - windowEvent.xkey.time < 2)) cookie, NULL);
{
// 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 if (keymap->keys[press->detail / 8] & (1 << (press->detail % 8)))
{
// KeyRelease event + key down = repeated event --> discard
if (windowEvent->response_type == XCB_KEY_RELEASE)
{
m_lastKeyReleaseEvent = *press;
return false;
}
// KeyPress event + key repeat disabled + matching KeyRelease event = repeated event --> discard
if ((windowEvent->response_type == XCB_KEY_PRESS) && !m_keyRepeat &&
(m_lastKeyReleaseEvent.detail == press->detail) &&
(m_lastKeyReleaseEvent.time == press->time))
{
return false; return false;
} }
} }
@ -729,10 +752,10 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
} }
// Convert the X11 event to a sf::Event // Convert the X11 event to a sf::Event
switch (windowEvent.type) switch (windowEvent->response_type & ~0x80)
{ {
// Destroy event // Destroy event
case DestroyNotify: case XCB_DESTROY_NOTIFY:
{ {
// The window is about to be destroyed: we must cleanup resources // The window is about to be destroyed: we must cleanup resources
cleanup(); cleanup();
@ -740,7 +763,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
} }
// Gain focus event // Gain focus event
case FocusIn: case XCB_FOCUS_IN:
{ {
// Update the input context // Update the input context
if (m_inputContext) if (m_inputContext)
@ -763,7 +786,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
} }
// Lost focus event // Lost focus event
case FocusOut: case XCB_FOCUS_OUT:
{ {
// Update the input context // Update the input context
if (m_inputContext) if (m_inputContext)
@ -776,27 +799,22 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
} }
// Resize event // Resize event
case ConfigureNotify: case XCB_CONFIGURE_NOTIFY:
{
// ConfigureNotify can be triggered for other reasons, check if the size has actually changed
if ((windowEvent.xconfigure.width != m_previousSize.x) || (windowEvent.xconfigure.height != m_previousSize.y))
{ {
xcb_configure_notify_event_t* e = reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent);
Event event; Event event;
event.type = Event::Resized; event.type = Event::Resized;
event.size.width = windowEvent.xconfigure.width; event.size.width = e->width;
event.size.height = windowEvent.xconfigure.height; event.size.height = e->height;
pushEvent(event); pushEvent(event);
m_previousSize.x = windowEvent.xconfigure.width;
m_previousSize.y = windowEvent.xconfigure.height;
}
break; break;
} }
// Close event // Close event
case ClientMessage: case XCB_CLIENT_MESSAGE:
{ {
if ((windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast<long>(m_atomClose)) xcb_client_message_event_t* e = reinterpret_cast<xcb_client_message_event_t*>(windowEvent);
if ((e->format == 32) && (e->data.data32[0]) == static_cast<long>(m_atomClose))
{ {
Event event; Event event;
event.type = Event::Closed; event.type = Event::Closed;
@ -806,34 +824,45 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
} }
// Key down event // Key down event
case KeyPress: case XCB_KEY_PRESS:
{ {
xcb_key_press_event_t* e = reinterpret_cast<xcb_key_press_event_t*>(windowEvent);
// Get the keysym of the key that has been pressed // Get the keysym of the key that has been pressed
static XComposeStatus keyboard; static XComposeStatus keyboard;
char buffer[32]; char buffer[32];
KeySym symbol; KeySym symbol;
XLookupString(&windowEvent.xkey, buffer, sizeof(buffer), &symbol, &keyboard);
// There is no xcb equivalent of XLookupString, so the xcb event
// has to be converted to an XEvent
XEvent fake_event;
fake_event.type = KeyPress;
fake_event.xany.display = m_display;
fake_event.xany.window = e->event;
fake_event.xkey.state = e->state;
fake_event.xkey.keycode = e->detail;
XLookupString(&fake_event.xkey, buffer, sizeof(buffer), &symbol, &keyboard);
// Fill the event parameters // Fill the event parameters
// TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping // TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping
Event event; Event event;
event.type = Event::KeyPressed; event.type = Event::KeyPressed;
event.key.code = keysymToSF(symbol); event.key.code = keysymToSF(symbol);
event.key.alt = windowEvent.xkey.state & Mod1Mask; event.key.alt = e->state & XCB_MOD_MASK_1;
event.key.control = windowEvent.xkey.state & ControlMask; event.key.control = e->state & XCB_MOD_MASK_CONTROL;
event.key.shift = windowEvent.xkey.state & ShiftMask; event.key.shift = e->state & XCB_MOD_MASK_SHIFT;
event.key.system = windowEvent.xkey.state & Mod4Mask; event.key.system = e->state & XCB_MOD_MASK_4;
pushEvent(event); pushEvent(event);
// Generate a TextEntered event // Generate a TextEntered event
if (!XFilterEvent(&windowEvent, None)) if (!XFilterEvent(&fake_event, None))
{ {
#ifdef X_HAVE_UTF8_STRING #ifdef X_HAVE_UTF8_STRING
if (m_inputContext) if (m_inputContext)
{ {
Status status; Status status;
Uint8 keyBuffer[16]; Uint8 keyBuffer[16];
int length = Xutf8LookupString(m_inputContext, &windowEvent.xkey, reinterpret_cast<char*>(keyBuffer), sizeof(keyBuffer), NULL, &status); int length = Xutf8LookupString(m_inputContext, &fake_event.xkey, reinterpret_cast<char*>(keyBuffer), sizeof(keyBuffer), NULL, &status);
if (length > 0) if (length > 0)
{ {
Uint32 unicode = 0; Uint32 unicode = 0;
@ -852,7 +881,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
{ {
static XComposeStatus status; static XComposeStatus status;
char keyBuffer[16]; char keyBuffer[16];
if (XLookupString(&windowEvent.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status)) if (XLookupString(&fake_event.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status))
{ {
Event textEvent; Event textEvent;
textEvent.type = Event::TextEntered; textEvent.type = Event::TextEntered;
@ -868,39 +897,51 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
// Key up event // Key up event
case KeyRelease: case KeyRelease:
{ {
xcb_key_release_event_t* e = reinterpret_cast<xcb_key_release_event_t*>(windowEvent);
// Get the keysym of the key that has been pressed // Get the keysym of the key that has been pressed
char buffer[32]; char buffer[32];
KeySym symbol; KeySym symbol;
XLookupString(&windowEvent.xkey, buffer, 32, &symbol, NULL);
// There is no xcb equivalent of XLookupString, so the xcb event
// has to be converted to an XEvent
XKeyEvent fake_event;
fake_event.display = m_display;
fake_event.state = e->state;
fake_event.keycode = e->detail;
XLookupString(&fake_event, buffer, 32, &symbol, NULL);
// Fill the event parameters // Fill the event parameters
Event event; Event event;
event.type = Event::KeyReleased; event.type = Event::KeyReleased;
event.key.code = keysymToSF(symbol); event.key.code = keysymToSF(symbol);
event.key.alt = windowEvent.xkey.state & Mod1Mask; event.key.alt = e->state & XCB_MOD_MASK_1;
event.key.control = windowEvent.xkey.state & ControlMask; event.key.control = e->state & XCB_MOD_MASK_CONTROL;
event.key.shift = windowEvent.xkey.state & ShiftMask; event.key.shift = e->state & XCB_MOD_MASK_SHIFT;
event.key.system = windowEvent.xkey.state & Mod4Mask; event.key.system = e->state & XCB_MOD_MASK_4;
pushEvent(event); pushEvent(event);
break; break;
} }
// Mouse button pressed // Mouse button pressed
case ButtonPress: case XCB_BUTTON_PRESS:
{ {
unsigned int button = windowEvent.xbutton.button; xcb_button_press_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent);
if ((button == Button1) || (button == Button2) || (button == Button3) || (button == 8) || (button == 9))
// XXX: Why button 8 and 9?
xcb_button_t button = e->detail;
if ((button == XCB_BUTTON_INDEX_1) || (button == XCB_BUTTON_INDEX_2)
|| (button == XCB_BUTTON_INDEX_3) || (button == 8) || (button == 9))
{ {
Event event; Event event;
event.type = Event::MouseButtonPressed; event.type = Event::MouseButtonPressed;
event.mouseButton.x = windowEvent.xbutton.x; event.mouseButton.x = e->event_x;
event.mouseButton.y = windowEvent.xbutton.y; event.mouseButton.y = e->event_y;
switch(button) switch(button)
{ {
case Button1: event.mouseButton.button = Mouse::Left; break; case XCB_BUTTON_INDEX_1: event.mouseButton.button = Mouse::Left; break;
case Button2: event.mouseButton.button = Mouse::Middle; break; case XCB_BUTTON_INDEX_2: event.mouseButton.button = Mouse::Middle; break;
case Button3: event.mouseButton.button = Mouse::Right; break; case XCB_BUTTON_INDEX_3: event.mouseButton.button = Mouse::Right; break;
case 8: event.mouseButton.button = Mouse::XButton1; break; case 8: event.mouseButton.button = Mouse::XButton1; break;
case 9: event.mouseButton.button = Mouse::XButton2; break; case 9: event.mouseButton.button = Mouse::XButton2; break;
} }
@ -910,50 +951,54 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
} }
// Mouse button released // Mouse button released
case ButtonRelease: case XCB_BUTTON_RELEASE:
{ {
unsigned int button = windowEvent.xbutton.button; xcb_button_release_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent);
if ((button == Button1) || (button == Button2) || (button == Button3) || (button == 8) || (button == 9))
xcb_button_t button = e->detail;
if ((button == XCB_BUTTON_INDEX_1) || (button == XCB_BUTTON_INDEX_2)
|| (button == XCB_BUTTON_INDEX_3) || (button == 8) || (button == 9))
{ {
Event event; Event event;
event.type = Event::MouseButtonReleased; event.type = Event::MouseButtonPressed;
event.mouseButton.x = windowEvent.xbutton.x; event.mouseButton.x = e->event_x;
event.mouseButton.y = windowEvent.xbutton.y; event.mouseButton.y = e->event_y;
switch(button) switch(button)
{ {
case Button1: event.mouseButton.button = Mouse::Left; break; case XCB_BUTTON_INDEX_1: event.mouseButton.button = Mouse::Left; break;
case Button2: event.mouseButton.button = Mouse::Middle; break; case XCB_BUTTON_INDEX_2: event.mouseButton.button = Mouse::Middle; break;
case Button3: event.mouseButton.button = Mouse::Right; break; case XCB_BUTTON_INDEX_3: event.mouseButton.button = Mouse::Right; break;
case 8: event.mouseButton.button = Mouse::XButton1; break; case 8: event.mouseButton.button = Mouse::XButton1; break;
case 9: event.mouseButton.button = Mouse::XButton2; break; case 9: event.mouseButton.button = Mouse::XButton2; break;
} }
pushEvent(event); pushEvent(event);
} }
else if ((button == Button4) || (button == Button5)) else if ((button == XCB_BUTTON_INDEX_4) || (button == XCB_BUTTON_INDEX_5))
{ {
Event event; Event event;
event.type = Event::MouseWheelMoved; event.type = Event::MouseWheelMoved;
event.mouseWheel.delta = windowEvent.xbutton.button == Button4 ? 1 : -1; event.mouseWheel.delta = button == XCB_BUTTON_INDEX_4 ? 1 : -1;
event.mouseWheel.x = windowEvent.xbutton.x; event.mouseWheel.x = e->event_x;
event.mouseWheel.y = windowEvent.xbutton.y; event.mouseWheel.y = e->event_y;
pushEvent(event); pushEvent(event);
} }
break; break;
} }
// Mouse moved // Mouse moved
case MotionNotify: case XCB_MOTION_NOTIFY:
{ {
xcb_motion_notify_event_t* e = reinterpret_cast<xcb_motion_notify_event_t*>(windowEvent);
Event event; Event event;
event.type = Event::MouseMoved; event.type = Event::MouseMoved;
event.mouseMove.x = windowEvent.xmotion.x; event.mouseMove.x = e->event_x;
event.mouseMove.y = windowEvent.xmotion.y; event.mouseMove.y = e->event_y;
pushEvent(event); pushEvent(event);
break; break;
} }
// Mouse entered // Mouse entered
case EnterNotify: case XCB_ENTER_NOTIFY:
{ {
if (windowEvent.xcrossing.mode == NotifyNormal) if (windowEvent.xcrossing.mode == NotifyNormal)
{ {
@ -965,7 +1010,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
} }
// Mouse left // Mouse left
case LeaveNotify: case XCB_LEAVE_NOTIFY:
{ {
if (windowEvent.xcrossing.mode == NotifyNormal) if (windowEvent.xcrossing.mode == NotifyNormal)
{ {
@ -989,7 +1034,7 @@ bool WindowImplX11::processEvent(XEvent windowEvent)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Keyboard::Key WindowImplX11::keysymToSF(KeySym symbol) Keyboard::Key WindowImplX11::keysymToSF(xcb_keysym_t symbol)
{ {
// First convert to uppercase (to avoid dealing with two different keysyms for the same key) // First convert to uppercase (to avoid dealing with two different keysyms for the same key)
KeySym lower, key; KeySym lower, key;

View File

@ -31,7 +31,7 @@
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowImpl.hpp> #include <SFML/Window/WindowImpl.hpp>
#include <SFML/System/String.hpp> #include <SFML/System/String.hpp>
#include <X11/Xlib.h> #include <X11/Xlib-xcb.h>
#include <set> #include <set>
@ -213,7 +213,7 @@ private:
/// \return True if the event was processed, false if it was discarded /// \return True if the event was processed, false if it was discarded
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool processEvent(XEvent windowEvent); bool processEvent(xcb_generic_event_t *windowEvent);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Convert a X11 keysym to SFML key code /// \brief Convert a X11 keysym to SFML key code
@ -223,20 +223,21 @@ private:
/// \return Corresponding SFML key code /// \return Corresponding SFML key code
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static Keyboard::Key keysymToSF(KeySym symbol); static Keyboard::Key keysymToSF(xcb_keysym_t symbol);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
::Window m_window; ///< X11 structure defining our window ::Window m_window; ///< X11 structure defining our window
::Display* m_display; ///< Pointer to the display ::Display* m_display; ///< Pointer to the display
xcb_connection_t* m_connection; ///< Pointer to the xcb connection
int m_screen; ///< Screen identifier int m_screen; ///< Screen identifier
XIM m_inputMethod; ///< Input method linked to the X display XIM m_inputMethod; ///< Input method linked to the X display
XIC m_inputContext; ///< Input context used to get Unicode input in our window 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 bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
Atom m_atomClose; ///< Atom used to identify the close event Atom m_atomClose; ///< Atom used to identify the close event
int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen 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 Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? 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) Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
bool m_useSizeHints; ///< Is the size of the window fixed with size hints? bool m_useSizeHints; ///< Is the size of the window fixed with size hints?