Adjusted and fixed XCB patch.
* Adjusted xcb_icccm calls (for recent XCB versions). * Fixed wrong parameter order in xcb_icccm_set_wm_protocols call. * Fixed XCB_BUTTON_RELEASE spawning a MouseButtonPressed event. * Moved files from obsolete Linux/ to Unix/ directory. * Added m_useSizeHints fix. * setTitle() converts to UTF-8 before passing to XCB -> Unicode window title support. * Added XCB-util dependency. * Replaced XSelectInput. Obtaining XCB connection when taking window handle. * Adjusted X11 example for XCB. * Removed AutoPointer, replaced by direct XCB and free() calls. * Added key repeat workaround.
This commit is contained in:
parent
135c1716e8
commit
c7549cd292
@ -3,7 +3,8 @@
|
|||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Window.hpp>
|
#include <SFML/Window.hpp>
|
||||||
#include <X11/Xlib.h>
|
#include <SFML/System/Err.hpp>
|
||||||
|
#include <X11/Xlib-xcb.h>
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#include <GL/glu.h>
|
#include <GL/glu.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -55,9 +56,9 @@ void draw(sf::Window& window, float elapsedTime)
|
|||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glTranslatef(0.f, 0.f, -200.f);
|
glTranslatef(0.f, 0.f, -200.f);
|
||||||
glRotatef(elapsedTime * 0.05f, 1.f, 0.f, 0.f);
|
glRotatef(elapsedTime * 10.f, 1.f, 0.f, 0.f);
|
||||||
glRotatef(elapsedTime * 0.03f, 0.f, 1.f, 0.f);
|
glRotatef(elapsedTime * 6.f, 0.f, 1.f, 0.f);
|
||||||
glRotatef(elapsedTime * 0.09f, 0.f, 0.f, 1.f);
|
glRotatef(elapsedTime * 18.f, 0.f, 0.f, 1.f);
|
||||||
|
|
||||||
// Draw a cube
|
// Draw a cube
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
@ -115,85 +116,104 @@ int main()
|
|||||||
if (!display)
|
if (!display)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
// Get the default screen
|
// Get the XCB connection for the opened display.
|
||||||
int screen = DefaultScreen(display);
|
xcb_connection_t* xcbConnection = XGetXCBConnection(display);
|
||||||
|
|
||||||
// Let's create the main window
|
if (!xcbConnection)
|
||||||
XSetWindowAttributes attributes;
|
{
|
||||||
attributes.background_pixel = BlackPixel(display, screen);
|
sf::err() << "Failed to get the XCB connection for opened display." << std::endl;
|
||||||
attributes.event_mask = KeyPressMask;
|
|
||||||
Window window = XCreateWindow(display, RootWindow(display, screen),
|
|
||||||
0, 0, 650, 330, 0,
|
|
||||||
DefaultDepth(display, screen),
|
|
||||||
InputOutput,
|
|
||||||
DefaultVisual(display, screen),
|
|
||||||
CWBackPixel | CWEventMask, &attributes);
|
|
||||||
if (!window)
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the window's name
|
// Get XCB screen.
|
||||||
XStoreName(display, window , "SFML Window");
|
const xcb_setup_t* xcbSetup = xcb_get_setup(xcbConnection);
|
||||||
|
xcb_screen_iterator_t xcbScreenIter = xcb_setup_roots_iterator(xcbSetup);
|
||||||
|
xcb_screen_t* screen = xcbScreenIter.data;
|
||||||
|
|
||||||
// Let's create the windows which will serve as containers for our SFML views
|
if (!screen)
|
||||||
Window view1 = XCreateWindow(display, window,
|
{
|
||||||
10, 10, 310, 310, 0,
|
sf::err() << "Failed to get the XCB screen." << std::endl;
|
||||||
DefaultDepth(display, screen),
|
return EXIT_FAILURE;
|
||||||
InputOutput,
|
}
|
||||||
DefaultVisual(display, screen),
|
|
||||||
0, NULL);
|
|
||||||
Window view2 = XCreateWindow(display, window,
|
|
||||||
330, 10, 310, 310, 0,
|
|
||||||
DefaultDepth(display, screen),
|
|
||||||
InputOutput,
|
|
||||||
DefaultVisual(display, screen),
|
|
||||||
0, NULL);
|
|
||||||
|
|
||||||
// Show our windows
|
// Generate the XCB window IDs.
|
||||||
XMapWindow(display, window);
|
xcb_window_t rootWindowId = xcb_generate_id(xcbConnection);
|
||||||
XFlush(display);
|
xcb_window_t view1WindowId = xcb_generate_id(xcbConnection);
|
||||||
|
xcb_window_t view2WindowId = xcb_generate_id(xcbConnection);
|
||||||
|
|
||||||
|
// Create the root window with a black background.
|
||||||
|
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||||
|
uint32_t attributes[2] = {screen->black_pixel, XCB_EVENT_MASK_KEY_PRESS};
|
||||||
|
|
||||||
|
xcb_create_window(xcbConnection,
|
||||||
|
XCB_COPY_FROM_PARENT,
|
||||||
|
rootWindowId,
|
||||||
|
screen->root,
|
||||||
|
0, 0, 650, 330,
|
||||||
|
0,
|
||||||
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||||
|
screen->root_visual,
|
||||||
|
mask, attributes);
|
||||||
|
|
||||||
|
// Create windows for the SFML views.
|
||||||
|
xcb_create_window(xcbConnection,
|
||||||
|
XCB_COPY_FROM_PARENT,
|
||||||
|
view1WindowId,
|
||||||
|
rootWindowId,
|
||||||
|
10, 10, 310, 310,
|
||||||
|
0,
|
||||||
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||||
|
screen->root_visual,
|
||||||
|
mask, attributes);
|
||||||
|
|
||||||
|
xcb_create_window(xcbConnection,
|
||||||
|
XCB_COPY_FROM_PARENT,
|
||||||
|
view2WindowId,
|
||||||
|
rootWindowId,
|
||||||
|
330, 10, 310, 310,
|
||||||
|
0,
|
||||||
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||||
|
screen->root_visual,
|
||||||
|
mask, attributes);
|
||||||
|
|
||||||
|
// Map windows to screen.
|
||||||
|
xcb_map_window(xcbConnection, rootWindowId);
|
||||||
|
xcb_map_window(xcbConnection, view1WindowId);
|
||||||
|
xcb_map_window(xcbConnection, view2WindowId);
|
||||||
|
|
||||||
|
// Flush commands.
|
||||||
|
xcb_flush(xcbConnection);
|
||||||
|
|
||||||
// Create our SFML views
|
// Create our SFML views
|
||||||
sf::Window SFMLView1(view1);
|
sf::Window sfmlView1(view1WindowId);
|
||||||
sf::Window SFMLView2(view2);
|
sf::Window sfmlView2(view2WindowId);
|
||||||
|
|
||||||
// Create a clock for measuring elapsed time
|
// Create a clock for measuring elapsed time
|
||||||
sf::Clock clock;
|
sf::Clock clock;
|
||||||
|
|
||||||
// Initialize our views
|
// Initialize our views
|
||||||
initialize(SFMLView1);
|
initialize(sfmlView1);
|
||||||
initialize(SFMLView2);
|
initialize(sfmlView2);
|
||||||
|
|
||||||
// Start the event loop
|
// Start the event loop
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
xcb_generic_event_t* event = NULL;
|
||||||
|
|
||||||
while (running)
|
while (running)
|
||||||
{
|
{
|
||||||
while (XPending(display))
|
while (event = xcb_poll_for_event(xcbConnection))
|
||||||
{
|
{
|
||||||
// Get the next pending event
|
running = false;
|
||||||
XEvent event;
|
|
||||||
XNextEvent(display, &event);
|
|
||||||
|
|
||||||
// Process it
|
|
||||||
switch (event.type)
|
|
||||||
{
|
|
||||||
// Any key is pressed: quit
|
|
||||||
case KeyPress:
|
|
||||||
running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw something into our views
|
// Draw something into our views
|
||||||
draw(SFMLView1, clock.getElapsedTime().asSeconds());
|
draw(sfmlView1, clock.getElapsedTime().asSeconds());
|
||||||
draw(SFMLView2, clock.getElapsedTime().asSeconds() * 0.3f);
|
draw(sfmlView2, clock.getElapsedTime().asSeconds() * 0.3f);
|
||||||
|
|
||||||
// Display the views on screen
|
// Display the views on screen
|
||||||
SFMLView1.display();
|
sfmlView1.display();
|
||||||
SFMLView2.display();
|
sfmlView2.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the display
|
|
||||||
XCloseDisplay(display);
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,6 @@ 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
|
||||||
@ -195,7 +193,7 @@ 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(XCB COMPONENTS xlib_xcb atom icccm image randr REQUIRED)
|
find_package(XCB COMPONENTS xlib_xcb icccm image randr util REQUIRED)
|
||||||
if(NOT LIBXCB_FOUND)
|
if(NOT LIBXCB_FOUND)
|
||||||
message(FATAL_ERROR "Xcb library not found")
|
message(FATAL_ERROR "Xcb library not found")
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// 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
|
|
@ -1,132 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// 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
|
|
@ -28,7 +28,6 @@
|
|||||||
#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 <SFML/Window/Linux/AutoPointer.hpp>
|
|
||||||
#include <X11/Xlib-xcb.h>
|
#include <X11/Xlib-xcb.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -158,13 +157,16 @@ bool InputImpl::isKeyPressed(Keyboard::Key key)
|
|||||||
if (keycode != 0)
|
if (keycode != 0)
|
||||||
{
|
{
|
||||||
// Get the whole keyboard state
|
// Get the whole keyboard state
|
||||||
AutoPointer<xcb_query_keymap_reply_t> keymap = xcb_query_keymap_reply(connection, xcb_query_keymap(connection), NULL);
|
xcb_query_keymap_reply_t* keymap = xcb_query_keymap_reply(connection, xcb_query_keymap(connection), NULL);
|
||||||
|
|
||||||
// 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 (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0;
|
bool isPressed = (keymap->keys[keycode / 8] & (1 << (keycode % 8))) != 0;
|
||||||
|
|
||||||
|
free(keymap);
|
||||||
|
return isPressed;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -191,21 +193,25 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button)
|
|||||||
xcb_connection_t* connection = XGetXCBConnection(display);
|
xcb_connection_t* connection = XGetXCBConnection(display);
|
||||||
|
|
||||||
// Get pointer mask
|
// Get pointer mask
|
||||||
AutoPointer<xcb_query_pointer_reply_t> pointer =
|
xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL);
|
||||||
xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL);
|
|
||||||
|
|
||||||
// Close the connection with the X server
|
// Close the connection with the X server
|
||||||
CloseDisplay(display);
|
CloseDisplay(display);
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
switch (button)
|
switch (button)
|
||||||
{
|
{
|
||||||
case Mouse::Left: return pointer->mask & XCB_BUTTON_MASK_1;
|
case Mouse::Left: result = pointer->mask & XCB_BUTTON_MASK_1;
|
||||||
case Mouse::Right: return pointer->mask & XCB_BUTTON_MASK_3;
|
case Mouse::Right: result = pointer->mask & XCB_BUTTON_MASK_3;
|
||||||
case Mouse::Middle: return pointer->mask & XCB_BUTTON_MASK_2;
|
case Mouse::Middle: result = pointer->mask & XCB_BUTTON_MASK_2;
|
||||||
case Mouse::XButton1: // not supported by X
|
case Mouse::XButton1: // not supported by X
|
||||||
case Mouse::XButton2: // not supported by X
|
case Mouse::XButton2: // not supported by X
|
||||||
default: return false;
|
default: result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(pointer);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -216,13 +222,16 @@ Vector2i InputImpl::getMousePosition()
|
|||||||
Display* display = OpenDisplay();
|
Display* display = OpenDisplay();
|
||||||
xcb_connection_t* connection = XGetXCBConnection(display);
|
xcb_connection_t* connection = XGetXCBConnection(display);
|
||||||
|
|
||||||
AutoPointer<xcb_query_pointer_reply_t> pointer =
|
xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL);
|
||||||
xcb_query_pointer_reply(connection, xcb_query_pointer(connection, XDefaultRootWindow(display)), NULL);
|
|
||||||
|
|
||||||
// Close the connection with the X server
|
// Close the connection with the X server
|
||||||
CloseDisplay(display);
|
CloseDisplay(display);
|
||||||
|
|
||||||
return Vector2i(pointer->root_x, pointer->root_y);
|
// Prepare result.
|
||||||
|
Vector2i result(pointer->root_x, pointer->root_y);
|
||||||
|
free(pointer);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -235,13 +244,16 @@ Vector2i InputImpl::getMousePosition(const Window& relativeTo)
|
|||||||
// Open a connection with the X server
|
// Open a connection with the X server
|
||||||
xcb_connection_t* connection = OpenConnection();
|
xcb_connection_t* connection = OpenConnection();
|
||||||
|
|
||||||
AutoPointer<xcb_query_pointer_reply_t> pointer =
|
xcb_query_pointer_reply_t* pointer = xcb_query_pointer_reply(connection, xcb_query_pointer(connection, handle), NULL);
|
||||||
xcb_query_pointer_reply(connection, xcb_query_pointer(connection, handle), NULL);
|
|
||||||
|
|
||||||
// Close the connection with the X server
|
// Close the connection with the X server
|
||||||
CloseConnection(connection);
|
CloseConnection(connection);
|
||||||
|
|
||||||
return Vector2i(pointer->win_x, pointer->win_y);
|
// Prepare result.
|
||||||
|
Vector2i result(pointer->win_x, pointer->win_y);
|
||||||
|
free(pointer);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -28,20 +28,25 @@
|
|||||||
#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/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
#include <xcb/xcb_atom.h>
|
#include <xcb/xcb_atom.h>
|
||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
#include <xcb/xcb_image.h>
|
#include <xcb/xcb_image.h>
|
||||||
|
#include <xcb/xcb_util.h>
|
||||||
#include <xcb/randr.h>
|
#include <xcb/randr.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#ifdef SFML_OPENGL_ES
|
#ifdef SFML_OPENGL_ES
|
||||||
#include <SFML/Window/EglContext.hpp>
|
#include <SFML/Window/EglContext.hpp>
|
||||||
@ -106,6 +111,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);
|
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);
|
||||||
|
|
||||||
// Save the window handle
|
// Save the window handle
|
||||||
@ -114,7 +127,12 @@ m_useSizeHints(false)
|
|||||||
if (m_window)
|
if (m_window)
|
||||||
{
|
{
|
||||||
// Make sure the window is listening to all the required events
|
// Make sure the window is listening to all the required events
|
||||||
XSelectInput(m_display, m_window, eventMask & ~ButtonPressMask);
|
const uint32_t value_list[] = {eventMask};
|
||||||
|
|
||||||
|
xcb_change_window_attributes(m_connection,
|
||||||
|
m_window,
|
||||||
|
XCB_CW_EVENT_MASK,
|
||||||
|
value_list);
|
||||||
|
|
||||||
// Do some common initializations
|
// Do some common initializations
|
||||||
initialize();
|
initialize();
|
||||||
@ -188,8 +206,11 @@ m_useSizeHints(false)
|
|||||||
XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT,
|
XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT,
|
||||||
value_list);
|
value_list);
|
||||||
|
|
||||||
ErrorPointer errptr(m_connection, cookie);
|
xcb_generic_error_t* errptr = xcb_request_check(m_connection, cookie);
|
||||||
if(! errptr.isNull())
|
bool createWindowFailed = (errptr != NULL);
|
||||||
|
free(errptr);
|
||||||
|
|
||||||
|
if (createWindowFailed)
|
||||||
{
|
{
|
||||||
err() << "Failed to create window" << std::endl;
|
err() << "Failed to create window" << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -201,8 +222,20 @@ 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)
|
||||||
{
|
{
|
||||||
xcb_atom_t WMHintsAtom = xcb_atom_get(m_connection, "_MOTIF_WM_HINTS");
|
static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS";
|
||||||
if (WMHintsAtom)
|
xcb_intern_atom_cookie_t hintsAtomRequest = xcb_intern_atom(
|
||||||
|
m_connection,
|
||||||
|
0,
|
||||||
|
MOTIF_WM_HINTS.size(),
|
||||||
|
MOTIF_WM_HINTS.c_str()
|
||||||
|
);
|
||||||
|
xcb_intern_atom_reply_t* hintsAtomReply = xcb_intern_atom_reply(
|
||||||
|
m_connection,
|
||||||
|
hintsAtomRequest,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hintsAtomReply)
|
||||||
{
|
{
|
||||||
static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0;
|
static const unsigned long MWM_HINTS_FUNCTIONS = 1 << 0;
|
||||||
static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1;
|
static const unsigned long MWM_HINTS_DECORATIONS = 1 << 1;
|
||||||
@ -254,17 +287,18 @@ m_useSizeHints(false)
|
|||||||
|
|
||||||
const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&hints);
|
const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&hints);
|
||||||
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
|
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
|
||||||
WMHintsAtom, WM_HINTS, 32, 5, ptr);
|
hintsAtomReply->atom, XA_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;
|
xcb_size_hints_t sizeHints;
|
||||||
sizeHints.flags = XCB_SIZE_HINT_P_MIN_SIZE | XCB_SIZE_HINT_P_MAX_SIZE;
|
sizeHints.flags = XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE;
|
||||||
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);
|
xcb_icccm_set_wm_normal_hints(m_connection, m_window, &sizeHints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,10 +366,61 @@ WindowHandle WindowImplX11::getSystemHandle() const
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void WindowImplX11::processEvents()
|
void WindowImplX11::processEvents()
|
||||||
{
|
{
|
||||||
while(xcb_generic_event_t* event = xcb_poll_for_event(m_connection))
|
// Key repeat workaround: If key repeat is enabled, XCB will spawn two
|
||||||
|
// events for each repeat interval: key release and key press. Both have
|
||||||
|
// the same timestamp and key code. We are holding back the release event
|
||||||
|
// to check for the matching key press event and if so, discard the release
|
||||||
|
// event.
|
||||||
|
|
||||||
|
xcb_generic_event_t* event = NULL;
|
||||||
|
xcb_key_release_event_t* lastKeyReleaseEvent = NULL;
|
||||||
|
uint8_t eventType = 0;
|
||||||
|
|
||||||
|
while(event = xcb_poll_for_event(m_connection))
|
||||||
{
|
{
|
||||||
processEvent(event);
|
eventType = event->response_type & ~0x80;
|
||||||
free(event);
|
|
||||||
|
// Key was pressed and one has been released prior to that.
|
||||||
|
if (eventType == XCB_KEY_PRESS && lastKeyReleaseEvent)
|
||||||
|
{
|
||||||
|
// If the key press event matches the held back key release event,
|
||||||
|
// then we have a key repeat and discard the held back release
|
||||||
|
// event.
|
||||||
|
if (lastKeyReleaseEvent->time == reinterpret_cast<xcb_key_press_event_t*>(event)->time &&
|
||||||
|
lastKeyReleaseEvent->detail == reinterpret_cast<xcb_key_press_event_t*>(event)->detail)
|
||||||
|
{
|
||||||
|
free(lastKeyReleaseEvent);
|
||||||
|
lastKeyReleaseEvent = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's still a key release event held back, process it now.
|
||||||
|
if (lastKeyReleaseEvent)
|
||||||
|
{
|
||||||
|
processEvent(reinterpret_cast<xcb_generic_event_t*>(lastKeyReleaseEvent));
|
||||||
|
free(lastKeyReleaseEvent);
|
||||||
|
lastKeyReleaseEvent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventType == XCB_KEY_RELEASE)
|
||||||
|
{
|
||||||
|
// Remember this key release event.
|
||||||
|
lastKeyReleaseEvent = reinterpret_cast<xcb_key_release_event_t*>(event);
|
||||||
|
event = NULL; // For safety reasons.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
processEvent(event);
|
||||||
|
free(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any held back release event.
|
||||||
|
if (lastKeyReleaseEvent)
|
||||||
|
{
|
||||||
|
processEvent(reinterpret_cast<xcb_generic_event_t*>(lastKeyReleaseEvent));
|
||||||
|
free(lastKeyReleaseEvent);
|
||||||
|
lastKeyReleaseEvent = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,9 +428,11 @@ void WindowImplX11::processEvents()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Vector2i WindowImplX11::getPosition() const
|
Vector2i WindowImplX11::getPosition() const
|
||||||
{
|
{
|
||||||
AutoPointer<xcb_get_geometry_reply_t> reply =
|
xcb_get_geometry_reply_t* reply = xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL);
|
||||||
xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL);
|
Vector2i result(reply->x, reply->y);
|
||||||
return Vector2i(reply->x, reply->y);
|
free(reply);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -363,15 +450,26 @@ void WindowImplX11::setPosition(const Vector2i& position)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Vector2u WindowImplX11::getSize() const
|
Vector2u WindowImplX11::getSize() const
|
||||||
{
|
{
|
||||||
AutoPointer<xcb_get_geometry_reply_t> reply =
|
xcb_get_geometry_reply_t* reply = xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL);
|
||||||
xcb_get_geometry_reply(m_connection, xcb_get_geometry(m_connection, m_window), NULL);
|
Vector2u result(reply->width, reply->height);
|
||||||
return Vector2u(reply->width, reply->height);
|
free(reply);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void WindowImplX11::setSize(const Vector2u& size)
|
void WindowImplX11::setSize(const Vector2u& size)
|
||||||
{
|
{
|
||||||
|
// If resizing is disable for the window we have to update the size hints (required by some window managers).
|
||||||
|
if( m_useSizeHints ) {
|
||||||
|
xcb_size_hints_t sizeHints;
|
||||||
|
sizeHints.flags = XCB_ICCCM_SIZE_HINT_P_MIN_SIZE | XCB_ICCCM_SIZE_HINT_P_MAX_SIZE;
|
||||||
|
sizeHints.min_width = sizeHints.max_width = size.x;
|
||||||
|
sizeHints.min_height = sizeHints.max_height = size.y;
|
||||||
|
xcb_icccm_set_wm_normal_hints(m_connection, m_window, &sizeHints);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t values[] = {size.x, size.y};
|
uint32_t values[] = {size.x, size.y};
|
||||||
xcb_configure_window(m_connection, m_window,
|
xcb_configure_window(m_connection, m_window,
|
||||||
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
||||||
@ -383,10 +481,16 @@ void WindowImplX11::setSize(const Vector2u& size)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void WindowImplX11::setTitle(const String& title)
|
void WindowImplX11::setTitle(const String& title)
|
||||||
{
|
{
|
||||||
const char* c_title = title.c_str();
|
// XCB takes UTF-8-encoded strings.
|
||||||
|
std::basic_string<sf::Uint8> utf8String;
|
||||||
|
sf::Utf<32>::toUtf8(
|
||||||
|
title.begin(), title.end(),
|
||||||
|
std::back_inserter( utf8String )
|
||||||
|
);
|
||||||
|
|
||||||
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
|
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_window,
|
||||||
WM_NAME, STRING,
|
XA_WM_NAME, XA_STRING,
|
||||||
8, title.length(), c_title);
|
8, utf8String.length(), utf8String.c_str());
|
||||||
xcb_flush(m_connection);
|
xcb_flush(m_connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,8 +522,11 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
|
|||||||
width, height, 0, 0, 0, defDepth, sizeof(iconPixels), iconPixels);
|
width, height, 0, 0, 0, defDepth, sizeof(iconPixels), iconPixels);
|
||||||
xcb_free_gc(m_connection, iconGC);
|
xcb_free_gc(m_connection, iconGC);
|
||||||
|
|
||||||
ErrorPointer errptr(m_connection, cookie);
|
xcb_generic_error_t* errptr = xcb_request_check(m_connection, cookie);
|
||||||
if (! errptr.isNull())
|
bool setWindowIconFailed = (errptr != NULL);
|
||||||
|
free(errptr);
|
||||||
|
|
||||||
|
if (setWindowIconFailed)
|
||||||
{
|
{
|
||||||
err() << "Failed to set the window's icon: Error code " << (int)errptr->error_code << std::endl;
|
err() << "Failed to set the window's icon: Error code " << (int)errptr->error_code << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -445,11 +552,11 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
|
|||||||
xcb_pixmap_t maskPixmap = xcb_create_pixmap_from_bitmap_data(m_connection, m_window, (Uint8*)&maskPixels[0], width, height, 1, 0, 1, NULL);
|
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
|
||||||
xcb_wm_hints_t hints;
|
xcb_icccm_wm_hints_t hints;
|
||||||
hints.flags = XCB_WM_HINT_ICON_PIXMAP | XCB_WM_HINT_ICON_MASK;
|
hints.flags = XCB_ICCCM_WM_HINT_ICON_PIXMAP | XCB_ICCCM_WM_HINT_ICON_MASK;
|
||||||
hints.icon_pixmap = iconPixmap;
|
hints.icon_pixmap = iconPixmap;
|
||||||
hints.icon_mask = maskPixmap;
|
hints.icon_mask = maskPixmap;
|
||||||
xcb_set_wm_hints(m_connection, m_window, &hints);
|
xcb_icccm_set_wm_hints(m_connection, m_window, &hints);
|
||||||
|
|
||||||
xcb_flush(m_connection);
|
xcb_flush(m_connection);
|
||||||
}
|
}
|
||||||
@ -607,15 +714,52 @@ void WindowImplX11::switchToFullscreen(const VideoMode& mode)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void WindowImplX11::initialize()
|
void WindowImplX11::initialize()
|
||||||
{
|
{
|
||||||
// Make sure the "last key release" is initialized with invalid values
|
// Get the atoms for registering the close event
|
||||||
m_lastKeyReleaseEvent.response_type = -1;
|
static const std::string WM_DELETE_WINDOW_NAME = "WM_DELETE_WINDOW";
|
||||||
m_lastKeyReleaseEvent.detail = 0;
|
|
||||||
m_lastKeyReleaseEvent.time = 0;
|
|
||||||
|
|
||||||
// Get the atom defining the close event
|
xcb_intern_atom_cookie_t deleteWindowAtomRequest = xcb_intern_atom(
|
||||||
m_atomClose = xcb_atom_get(m_connection, "WM_DELETE_WINDOW");
|
m_connection,
|
||||||
xcb_atom_t wmprotocolsAtom = xcb_atom_get(m_connection, "WM_PROTOCOLS");
|
0,
|
||||||
xcb_set_wm_protocols(m_connection, wmprotocolsAtom, m_window, 1, &m_atomClose);
|
WM_DELETE_WINDOW_NAME.size(),
|
||||||
|
WM_DELETE_WINDOW_NAME.c_str()
|
||||||
|
);
|
||||||
|
xcb_intern_atom_reply_t* deleteWindowAtomReply = xcb_intern_atom_reply(
|
||||||
|
m_connection,
|
||||||
|
deleteWindowAtomRequest,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
static const std::string WM_PROTOCOLS_NAME = "WM_PROTOCOLS";
|
||||||
|
|
||||||
|
xcb_intern_atom_cookie_t protocolsAtomRequest = xcb_intern_atom(
|
||||||
|
m_connection,
|
||||||
|
0,
|
||||||
|
WM_PROTOCOLS_NAME.size(),
|
||||||
|
WM_PROTOCOLS_NAME.c_str()
|
||||||
|
);
|
||||||
|
xcb_intern_atom_reply_t* protocolsAtomReply = xcb_intern_atom_reply(
|
||||||
|
m_connection,
|
||||||
|
protocolsAtomRequest,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (protocolsAtomReply && deleteWindowAtomReply)
|
||||||
|
{
|
||||||
|
xcb_icccm_set_wm_protocols(
|
||||||
|
m_connection,
|
||||||
|
m_window,
|
||||||
|
protocolsAtomReply->atom,
|
||||||
|
1,
|
||||||
|
&deleteWindowAtomReply->atom
|
||||||
|
);
|
||||||
|
|
||||||
|
m_atomClose = deleteWindowAtomReply->atom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Should not happen, but better safe than sorry.
|
||||||
|
std::cerr << "Failed to request WM_PROTOCOLS/WM_DELETE_WINDOW_NAME atoms." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the input context
|
// Create the input context
|
||||||
m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL);
|
m_inputMethod = XOpenIM(m_display, NULL, NULL, NULL);
|
||||||
@ -708,49 +852,6 @@ void WindowImplX11::cleanup()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
bool WindowImplX11::processEvent(xcb_generic_event_t* 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
|
|
||||||
if ((windowEvent->response_type == XCB_KEY_PRESS) ||
|
|
||||||
(windowEvent->response_type == XCB_KEY_RELEASE))
|
|
||||||
{
|
|
||||||
xcb_key_press_event_t* press = reinterpret_cast<xcb_key_press_event_t*>(windowEvent);
|
|
||||||
if (press->detail < 256)
|
|
||||||
{
|
|
||||||
// To detect if it is a repeated key event, we check the current state of the key.
|
|
||||||
// - If the state is "down", KeyReleased events must obviously be discarded.
|
|
||||||
// - KeyPress events are a little bit harder to handle: they depend on the EnableKeyRepeat state,
|
|
||||||
// and we need to properly forward the first one.
|
|
||||||
xcb_query_keymap_cookie_t cookie = xcb_query_keymap(m_connection);
|
|
||||||
AutoPointer<xcb_query_keymap_reply_t> keymap = xcb_query_keymap_reply(m_connection,
|
|
||||||
cookie, NULL);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the X11 event to a sf::Event
|
// Convert the X11 event to a sf::Event
|
||||||
switch (windowEvent->response_type & ~0x80)
|
switch (windowEvent->response_type & ~0x80)
|
||||||
{
|
{
|
||||||
@ -827,6 +928,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
|||||||
case XCB_KEY_PRESS:
|
case XCB_KEY_PRESS:
|
||||||
{
|
{
|
||||||
xcb_key_press_event_t* e = reinterpret_cast<xcb_key_press_event_t*>(windowEvent);
|
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];
|
||||||
@ -895,9 +997,10 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Key up event
|
// Key up event
|
||||||
case KeyRelease:
|
case XCB_KEY_RELEASE:
|
||||||
{
|
{
|
||||||
xcb_key_release_event_t* e = reinterpret_cast<xcb_key_release_event_t*>(windowEvent);
|
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;
|
||||||
@ -1000,7 +1103,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
|||||||
// Mouse entered
|
// Mouse entered
|
||||||
case XCB_ENTER_NOTIFY:
|
case XCB_ENTER_NOTIFY:
|
||||||
{
|
{
|
||||||
if (windowEvent.xcrossing.mode == NotifyNormal)
|
xcb_enter_notify_event_t* enterNotifyEvent = reinterpret_cast<xcb_enter_notify_event_t*>(windowEvent);
|
||||||
|
|
||||||
|
if (enterNotifyEvent->mode == NotifyNormal)
|
||||||
{
|
{
|
||||||
Event event;
|
Event event;
|
||||||
event.type = Event::MouseEntered;
|
event.type = Event::MouseEntered;
|
||||||
@ -1012,7 +1117,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
|||||||
// Mouse left
|
// Mouse left
|
||||||
case XCB_LEAVE_NOTIFY:
|
case XCB_LEAVE_NOTIFY:
|
||||||
{
|
{
|
||||||
if (windowEvent.xcrossing.mode == NotifyNormal)
|
xcb_leave_notify_event_t* leaveNotifyEvent = reinterpret_cast<xcb_leave_notify_event_t*>(windowEvent);
|
||||||
|
|
||||||
|
if (leaveNotifyEvent->mode == NotifyNormal)
|
||||||
{
|
{
|
||||||
Event event;
|
Event event;
|
||||||
event.type = Event::MouseLeft;
|
event.type = Event::MouseLeft;
|
||||||
|
@ -228,19 +228,19 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// 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
|
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 hidding, 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?
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
Loading…
Reference in New Issue
Block a user