diff options
author | James Cowgill <james410@cowgill.org.uk> | 2015-07-04 22:12:30 +0100 |
---|---|---|
committer | James Cowgill <james410@cowgill.org.uk> | 2015-07-04 22:12:30 +0100 |
commit | 232f6c9906817eee494907d7bbe8ddf2dacf8fbf (patch) | |
tree | 086a0fa3a2dc8a97e68e12f76c6982340a6b58c9 /src/SFML/Window/Unix/WindowImplX11.cpp | |
parent | c8f7e7bae794277dfa6599b67001b1e9499f0132 (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.cpp | 112 |
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); |