summaryrefslogtreecommitdiff
path: root/src/SFML/Window/Unix/WindowImplX11.cpp
diff options
context:
space:
mode:
authorJames Cowgill <james410@cowgill.org.uk>2015-07-04 22:12:30 +0100
committerJames Cowgill <james410@cowgill.org.uk>2015-07-04 22:12:30 +0100
commit232f6c9906817eee494907d7bbe8ddf2dacf8fbf (patch)
tree086a0fa3a2dc8a97e68e12f76c6982340a6b58c9 /src/SFML/Window/Unix/WindowImplX11.cpp
parentc8f7e7bae794277dfa6599b67001b1e9499f0132 (diff)
Imported Upstream version 2.3.1+dfsg
Diffstat (limited to 'src/SFML/Window/Unix/WindowImplX11.cpp')
-rw-r--r--src/SFML/Window/Unix/WindowImplX11.cpp112
1 files changed, 93 insertions, 19 deletions
diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp
index d8c26e0..8387975 100644
--- a/src/SFML/Window/Unix/WindowImplX11.cpp
+++ b/src/SFML/Window/Unix/WindowImplX11.cpp
@@ -28,6 +28,7 @@
#include <SFML/Window/WindowStyle.hpp> // important to be included first (conflict with None)
#include <SFML/Window/Unix/WindowImplX11.hpp>
#include <SFML/Window/Unix/Display.hpp>
+#include <SFML/Window/Unix/InputImpl.hpp>
#include <SFML/Window/Unix/ScopedXcbPtr.hpp>
#include <SFML/System/Utf.hpp>
#include <SFML/System/Err.hpp>
@@ -50,6 +51,10 @@
#define XCB_DRI2_BUFFER_SWAP_COMPLETE 0
#define XCB_DRI2_INVALIDATE_BUFFERS 1
+// So we don't have to require xcb xkb to be present
+#define XCB_XKB_NEW_KEYBOARD_NOTIFY 0
+#define XCB_XKB_MAP_NOTIFY 1
+
#ifdef SFML_OPENGL_ES
#include <SFML/Window/EglContext.hpp>
typedef sf::priv::EglContext ContextType;
@@ -230,28 +235,27 @@ namespace
sf::priv::CloseConnection(connection);
- const char* name = reinterpret_cast<const char*>(xcb_get_property_value(wmName.get()));
-
- windowManagerName = name;
+ // It seems the wm name string reply is not necessarily
+ // null-terminated. The work around is to get its actual
+ // length to build a proper string
+ const char* begin = reinterpret_cast<const char*>(xcb_get_property_value(wmName.get()));
+ const char* end = begin + xcb_get_property_value_length(wmName.get());
+ windowManagerName = sf::String::fromUtf8(begin, end);
return true;
}
- xcb_query_extension_reply_t getDriExtension()
+ xcb_query_extension_reply_t getXExtension(const std::string& name)
{
xcb_connection_t* connection = sf::priv::OpenConnection();
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
-
- // Check if the DRI2 extension is present
- // We don't use xcb_get_extension_data here to avoid having to link to xcb_dri2
- static const std::string DRI2 = "DRI2";
- sf::priv::ScopedXcbPtr<xcb_query_extension_reply_t> driExt(xcb_query_extension_reply(
+ sf::priv::ScopedXcbPtr<xcb_query_extension_reply_t> extension(xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
- DRI2.size(),
- DRI2.c_str()
+ name.size(),
+ name.c_str()
),
&error
));
@@ -259,14 +263,14 @@ namespace
// Close the connection with the X server
sf::priv::CloseConnection(connection);
- if (error || !driExt || !driExt->present)
+ if (error || !extension || !extension->present)
{
xcb_query_extension_reply_t reply;
std::memset(&reply, 0, sizeof(reply));
return reply;
}
- return *driExt.get();
+ return *extension.get();
}
void dumpXcbExtensions()
@@ -1926,12 +1930,21 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
if (passEvent(windowEvent, reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent)->window))
return false;
+ // X notifies about "window configuration events", which also includes moving a window only. Check
+ // for a different size and only spawn a Resized event when it differs.
xcb_configure_notify_event_t* e = reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent);
- Event event;
- event.type = Event::Resized;
- event.size.width = e->width;
- event.size.height = e->height;
- pushEvent(event);
+
+ if (e->width != m_previousSize.x || e->height != m_previousSize.y)
+ {
+ m_previousSize.x = e->width;
+ m_previousSize.y = e->height;
+
+ Event event;
+ event.type = Event::Resized;
+ event.size.width = e->width;
+ event.size.height = e->height;
+ pushEvent(event);
+ }
break;
}
@@ -2251,8 +2264,18 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
// Handle any extension events first
+ // SHAPE
+ // Ubuntu's Unity desktop environment makes use of the
+ // Compiz compositing window manager
+ // Compiz seems to send SHAPE events to windows even if they
+ // did not specifically select those events
+ // We ignore those events here in order to not generate warnings
+ static xcb_query_extension_reply_t shapeExtension = getXExtension("SHAPE");
+ if (shapeExtension.present && (responseType == shapeExtension.first_event))
+ break;
+
// DRI2
- static xcb_query_extension_reply_t driExtension = getDriExtension();
+ static xcb_query_extension_reply_t driExtension = getXExtension("DRI2");
if (driExtension.present)
{
// Because we are using the XCB event queue instead of the Xlib event
@@ -2302,6 +2325,57 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
}
}
+ // XKEYBOARD
+ // When the X server sends us XKEYBOARD events, it means that
+ // the user probably changed the layout of their keyboard
+ // We update our keymaps in that case
+ static xcb_query_extension_reply_t xkeyboardExtension = getXExtension("XKEYBOARD");
+ if (xkeyboardExtension.present && (responseType == xkeyboardExtension.first_event))
+ {
+ // We do this so we don't have to include the xkb header for the struct declaration
+ uint8_t xkbType = reinterpret_cast<const uint8_t*>(windowEvent)[1];
+
+ // We only bother rebuilding our maps if the xkb mapping actually changes
+ if ((xkbType == XCB_XKB_NEW_KEYBOARD_NOTIFY) || (xkbType == XCB_XKB_MAP_NOTIFY))
+ {
+ // keysym map
+ buildKeysymMap();
+
+ // keycode to SFML
+ buildMap();
+
+ // SFML to keycode
+ InputImpl::buildMap();
+
+ // XInputMethod expects keyboard mapping changes to be propagated to it
+ // Same idea here as with the DRI2 events above
+
+ // We lock/unlock the display to protect against concurrent access
+ XLockDisplay(m_display);
+
+ typedef Bool (*wireEventHandler)(Display*, XEvent*, xEvent*);
+
+ // Probe for any handlers that are registered for this event type
+ wireEventHandler handler = XESetWireToEvent(m_display, responseType, 0);
+
+ if (handler)
+ {
+ // Restore the previous handler if one was registered
+ XESetWireToEvent(m_display, responseType, handler);
+
+ XEvent event;
+ windowEvent->sequence = LastKnownRequestProcessed(m_display);
+
+ // Pretend to be the Xlib event queue
+ handler(m_display, &event, reinterpret_cast<xEvent*>(windowEvent));
+ }
+
+ XUnlockDisplay(m_display);
+ }
+
+ break;
+ }
+
// Print any surprises to stderr (would be nice if people report when this happens)
dumpUnhandledEvent(responseType);