From 3faf2a93d635eb982417836d85f910efddd335fa Mon Sep 17 00:00:00 2001 From: binary1248 Date: Thu, 12 Mar 2015 20:27:01 +0100 Subject: [PATCH] Reverted back to hard switching the fullscreen video mode when necessary on Unix systems, added support for automatically choosing between EWMH fullscreen setting when supported and manual fullscreen setting as the fallback, added support for window responsiveness checks. --- src/SFML/Window/Unix/WindowImplX11.cpp | 678 ++++++++++++++++++++----- src/SFML/Window/Unix/WindowImplX11.hpp | 44 +- 2 files changed, 572 insertions(+), 150 deletions(-) diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index ea10256d..568f0d2e 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,104 @@ namespace //Default fallback name return "sfml"; } + + // Check if Extended Window Manager Hints are supported + bool ewmhSupported() + { + xcb_connection_t* connection = sf::priv::OpenConnection(); + + static const std::string NET_SUPPORTING_WM_CHECK = "_NET_SUPPORTING_WM_CHECK"; + sf::priv::ScopedXcbPtr supportingWmAtomReply(xcb_intern_atom_reply( + connection, + xcb_intern_atom( + connection, + 0, + NET_SUPPORTING_WM_CHECK.size(), + NET_SUPPORTING_WM_CHECK.c_str() + ), + NULL + )); + + if (!supportingWmAtomReply) + { + sf::priv::CloseConnection(connection); + return false; + } + + static const std::string NET_SUPPORTED = "_NET_SUPPORTED"; + sf::priv::ScopedXcbPtr supportedAtomReply(xcb_intern_atom_reply( + connection, + xcb_intern_atom( + connection, + 0, + NET_SUPPORTED.size(), + NET_SUPPORTED.c_str() + ), + NULL + )); + + if (!supportedAtomReply) + { + sf::priv::CloseConnection(connection); + return false; + } + + sf::priv::ScopedXcbPtr error(NULL); + + sf::priv::ScopedXcbPtr rootSupportingWindow(xcb_get_property_reply( + connection, + xcb_get_property( + connection, + 0, + sf::priv::XCBDefaultRootWindow(connection), + supportingWmAtomReply->atom, + XCB_ATOM_WINDOW, + 0, + 0x7fffffff + ), + &error + )); + + if (!rootSupportingWindow) + { + sf::priv::CloseConnection(connection); + return false; + } + + xcb_window_t rootWindow = *reinterpret_cast(xcb_get_property_value(rootSupportingWindow.get())); + + sf::priv::ScopedXcbPtr childSupportingWindow(xcb_get_property_reply( + connection, + xcb_get_property( + connection, + 0, + rootWindow, + supportingWmAtomReply->atom, + XCB_ATOM_WINDOW, + 0, + 0x7fffffff + ), + &error + )); + + if (!childSupportingWindow) + { + sf::priv::CloseConnection(connection); + return false; + } + + xcb_window_t childWindow = *reinterpret_cast(xcb_get_property_value(childSupportingWindow.get())); + + // Conforming window managers should return the same window for both queries + if (rootSupportingWindow != childSupportingWindow) + { + sf::priv::CloseConnection(connection); + return false; + } + + sf::priv::CloseConnection(connection); + return true; + } } @@ -95,17 +194,19 @@ namespace priv { //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(WindowHandle handle) : -m_window (0), -m_inputMethod (NULL), -m_inputContext(NULL), -m_isExternal (true), -m_atomClose (0), -m_oldVideoMode(-1), -m_hiddenCursor(0), -m_keyRepeat (true), -m_previousSize(-1, -1), -m_useSizeHints(false), -m_fullscreen (false) +m_window (0), +m_inputMethod (NULL), +m_inputContext (NULL), +m_isExternal (true), +m_atomWmProtocols(0), +m_atomClose (0), +m_atomPing (0), +m_oldVideoMode (-1), +m_hiddenCursor (0), +m_keyRepeat (true), +m_previousSize (-1, -1), +m_useSizeHints (false), +m_fullscreen (false) { // Open a connection with the X server m_display = OpenDisplay(); @@ -143,17 +244,19 @@ m_fullscreen (false) //////////////////////////////////////////////////////////// WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) : -m_window (0), -m_inputMethod (NULL), -m_inputContext(NULL), -m_isExternal (false), -m_atomClose (0), -m_oldVideoMode(-1), -m_hiddenCursor(0), -m_keyRepeat (true), -m_previousSize(-1, -1), -m_useSizeHints(false), -m_fullscreen ((style & Style::Fullscreen) != 0) +m_window (0), +m_inputMethod (NULL), +m_inputContext (NULL), +m_isExternal (false), +m_atomWmProtocols(0), +m_atomClose (0), +m_atomPing (0), +m_oldVideoMode (-1), +m_hiddenCursor (0), +m_keyRepeat (true), +m_previousSize (-1, -1), +m_useSizeHints (false), +m_fullscreen ((style & Style::Fullscreen) != 0) { // Open a connection with the X server m_display = OpenDisplay(); @@ -174,13 +277,17 @@ m_fullscreen ((style & Style::Fullscreen) != 0) int width = mode.width; int height = mode.height; + // Set fullscreen video mode if necessary + if (m_fullscreen) + setVideoMode(mode); + // Choose the visual according to the context settings XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings); // Define the window attributes xcb_colormap_t colormap = xcb_generate_id(m_connection); xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, m_screen->root, visualInfo.visualid); - const uint32_t value_list[] = {static_cast(eventMask), colormap}; + const uint32_t value_list[] = {m_fullscreen && !ewmhSupported(), static_cast(eventMask), colormap}; // Create the window m_window = xcb_generate_id(m_connection); @@ -197,7 +304,7 @@ m_fullscreen ((style & Style::Fullscreen) != 0) 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visualInfo.visualid, - XCB_CW_EVENT_MASK | XCB_CW_COLORMAP, + XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP, value_list ) )); @@ -276,16 +383,22 @@ m_fullscreen ((style & Style::Fullscreen) != 0) hints.functions |= MWM_FUNC_CLOSE; } - xcb_change_property( + ScopedXcbPtr propertyError(xcb_request_check( m_connection, - XCB_PROP_MODE_REPLACE, - m_window, - hintsAtomReply->atom, - XCB_ATOM_WM_HINTS, - sizeof(hints.flags) * 8, - sizeof(hints) / sizeof(hints.flags), - reinterpret_cast(&hints) - ); + xcb_change_property_checked( + m_connection, + XCB_PROP_MODE_REPLACE, + m_window, + hintsAtomReply->atom, + hintsAtomReply->atom, + sizeof(hints.flags) * 8, + sizeof(hints) / sizeof(hints.flags), + reinterpret_cast(&hints) + ) + )); + + if (propertyError) + err() << "xcb_change_property failed, could not set window hints" << std::endl; } // This is a hack to force some windows managers to disable resizing @@ -307,7 +420,7 @@ m_fullscreen ((style & Style::Fullscreen) != 0) // Do some common initializations initialize(); - // Switch to fullscreen. + // Switch to fullscreen if necessary if (m_fullscreen) switchToFullscreen(); } @@ -377,11 +490,11 @@ void WindowImplX11::setPointerGrabbed(bool grabbed) )); if (grabReply && grabReply->status != 0) - sf::err() << "Grabbing the pointer failed." << std::endl + err() << "Grabbing the pointer failed." << std::endl << " Status: " << static_cast(grabReply->status) << std::endl; else if (!grabReply) - sf::err() << "Grabbing the pointer failed." << std::endl; + err() << "Grabbing the pointer failed." << std::endl; } else { @@ -685,7 +798,7 @@ void WindowImplX11::requestFocus() break; } } - + // Check if window is viewable (not on other desktop, ...) // TODO: Check also if minimized ScopedXcbPtr attributes(xcb_get_window_attributes_reply( @@ -699,12 +812,12 @@ void WindowImplX11::requestFocus() if (!attributes) { - sf::err() << "Failed to check if window is viewable while requesting focus" << std::endl; + err() << "Failed to check if window is viewable while requesting focus" << std::endl; return; // error getting attribute } bool windowViewable = (attributes->map_state == XCB_MAP_STATE_VIEWABLE); - + if (sfmlWindowFocused && windowViewable) { // Another SFML window of this application has the focus and the current window is viewable: @@ -750,93 +863,283 @@ bool WindowImplX11::hasFocus() const } +//////////////////////////////////////////////////////////// +void WindowImplX11::setVideoMode(const VideoMode& mode) +{ + // Skip mode switching if the new mode is equal to the desktop mode + if (mode == VideoMode::getDesktopMode()) + return; + + // Check if the XRandR extension is present + static const std::string RANDR = "RANDR"; + ScopedXcbPtr randr_ext(xcb_query_extension_reply( + m_connection, + xcb_query_extension( + m_connection, + RANDR.size(), + RANDR.c_str() + ), + NULL + )); + + if (randr_ext->present) + { + // Get the current configuration + ScopedXcbPtr error(NULL); + ScopedXcbPtr config(xcb_randr_get_screen_info_reply( + m_connection, + xcb_randr_get_screen_info( + m_connection, + m_screen->root + ), + &error + )); + + if (!error) + { + // Save the current video mode before we switch to fullscreen + m_oldVideoMode = config->sizeID; + + // Get the available screen sizes + xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get()); + if (sizes && (config->nSizes > 0)) + { + // Search a matching size + for (int i = 0; i < config->nSizes; ++i) + { + if ((sizes[i].width == static_cast(mode.width)) && + (sizes[i].height == static_cast(mode.height))) + { + // Switch to fullscreen mode + xcb_randr_set_screen_config( + m_connection, + m_screen->root, + config->timestamp, + config->config_timestamp, + i, + config->rotation, + config->rate + ); + + // Set "this" as the current fullscreen window + fullscreenWindow = this; + break; + } + } + } + } + else + { + // Failed to get the screen configuration + err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl; + } + } + else + { + // XRandR extension is not supported: we cannot use fullscreen mode + err() << "Fullscreen is not supported, switching to window mode" << std::endl; + } +} + + +//////////////////////////////////////////////////////////// +void WindowImplX11::resetVideoMode() +{ + if (fullscreenWindow == this) + { + // Get current screen info + ScopedXcbPtr error(NULL); + ScopedXcbPtr config(xcb_randr_get_screen_info_reply( + m_connection, + xcb_randr_get_screen_info( + m_connection, + m_screen->root + ), + &error + )); + + if (!error) + { + // Reset the video mode + xcb_randr_set_screen_config( + m_connection, + m_screen->root, + CurrentTime, + config->config_timestamp, + m_oldVideoMode, + config->rotation, + config->rate + ); + } + + // Reset the fullscreen window + fullscreenWindow = NULL; + } +} + + //////////////////////////////////////////////////////////// void WindowImplX11::switchToFullscreen() { - // Create atom for _NET_WM_STATE. - static const std::string netWmState = "_NET_WM_STATE"; - ScopedXcbPtr stateReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - 0, - netWmState.size(), - netWmState.c_str() - ), - 0 - )); - - // Create atom for _NET_WM_STATE_FULLSCREEN. - static const std::string netWmStateFullscreen = "_NET_WM_STATE_FULLSCREEN"; - ScopedXcbPtr fullscreenReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - 0, - netWmStateFullscreen.size(), - netWmStateFullscreen.c_str() - ), - 0 - )); - - // Set fullscreen property. - ScopedXcbPtr fullscreenError(xcb_request_check( - m_connection, - xcb_change_property_checked( - m_connection, - XCB_PROP_MODE_REPLACE, - m_window, - stateReply->atom, - XCB_ATOM_ATOM, - 32, - 1, - &fullscreenReply->atom - ) - )); - - if (fullscreenError) + // Try EWMH method if supported or fallback to manual + if (ewmhSupported()) { - sf::err() << "Setting fullscreen failed." << std::endl; - return; + // Create atom for _NET_WM_BYPASS_COMPOSITOR. + static const std::string netWmStateBypassCompositor = "_NET_WM_BYPASS_COMPOSITOR"; + ScopedXcbPtr compReply(xcb_intern_atom_reply( + m_connection, + xcb_intern_atom( + m_connection, + 0, + netWmStateBypassCompositor.size(), + netWmStateBypassCompositor.c_str() + ), + 0 + )); + + static const Uint32 bypassCompositor = 1; + + // Disable compositor. + ScopedXcbPtr compositorError(xcb_request_check( + m_connection, + xcb_change_property_checked( + m_connection, + XCB_PROP_MODE_REPLACE, + m_window, + compReply->atom, + XCB_ATOM_CARDINAL, + 32, + 1, + &bypassCompositor + ) + )); + + // Not being able to bypass the compositor is not a fatal error + if (compositorError) + err() << "xcb_change_property failed, setting fullscreen not possible" << std::endl; + + // Create atom for _NET_ACTIVE_WINDOW. + static const std::string netActiveWindow = "_NET_ACTIVE_WINDOW"; + ScopedXcbPtr activeWindowReply(xcb_intern_atom_reply( + m_connection, + xcb_intern_atom( + m_connection, + 0, + netActiveWindow.size(), + netActiveWindow.c_str() + ), + 0 + )); + + if (!activeWindowReply) + { + err() << "Setting fullscreen failed, could not get \"_NET_ACTIVE_WINDOW\" atom" << std::endl; + return; + } + + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.window = m_window; + event.format = 32; + event.sequence = 0; + event.type = activeWindowReply->atom; + event.data.data32[0] = 1; + event.data.data32[1] = XCB_CURRENT_TIME; + + ScopedXcbPtr activeWindowError(xcb_request_check( + m_connection, + xcb_send_event_checked( + m_connection, + 0, + XCBDefaultRootWindow(m_connection), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + reinterpret_cast(&event) + ) + )); + + if (activeWindowError) + { + err() << "Setting fullscreen failed, could not send \"_NET_ACTIVE_WINDOW\" event" << std::endl; + return; + } + + // Create atom for _NET_WM_STATE. + static const std::string netWmState = "_NET_WM_STATE"; + ScopedXcbPtr stateReply(xcb_intern_atom_reply( + m_connection, + xcb_intern_atom( + m_connection, + 0, + netWmState.size(), + netWmState.c_str() + ), + 0 + )); + + if (!stateReply) + { + err() << "Setting fullscreen failed. Could not get \"_NET_WM_STATE\" atom" << std::endl; + return; + } + + // Create atom for _NET_WM_STATE_FULLSCREEN. + static const std::string netWmStateFullscreen = "_NET_WM_STATE_FULLSCREEN"; + ScopedXcbPtr fullscreenReply(xcb_intern_atom_reply( + m_connection, + xcb_intern_atom( + m_connection, + 0, + netWmStateFullscreen.size(), + netWmStateFullscreen.c_str() + ), + 0 + )); + + if (!fullscreenReply) + { + err() << "Setting fullscreen failed. Could not get \"_NET_WM_STATE_FULLSCREEN\" atom" << std::endl; + return; + } + + event.response_type = XCB_CLIENT_MESSAGE; + event.window = m_window; + event.format = 32; + event.sequence = 0; + event.type = stateReply->atom; + event.data.data32[0] = 1; // _NET_WM_STATE_ADD + event.data.data32[1] = fullscreenReply->atom; + event.data.data32[2] = 0; + event.data.data32[3] = 1; + + ScopedXcbPtr wmStateError(xcb_request_check( + m_connection, + xcb_send_event_checked( + m_connection, + 0, + XCBDefaultRootWindow(m_connection), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + reinterpret_cast(&event) + ) + )); + + if (wmStateError) + err() << "Setting fullscreen failed. Could not send \"_NET_WM_STATE\" event" << std::endl; + } + else + { + // If WM fullscreen setting is not available, we need to do it manually + const uint32_t values[] = {XCB_STACK_MODE_ABOVE}; + xcb_configure_window(m_connection, m_window, XCB_CONFIG_WINDOW_STACK_MODE, values); + xcb_set_input_focus(m_connection, XCB_INPUT_FOCUS_POINTER_ROOT, m_window, XCB_CURRENT_TIME); } - - // Create atom for _NET_WM_BYPASS_COMPOSITOR. - static const std::string netWmStateBypassCompositor = "_NET_WM_BYPASS_COMPOSITOR"; - ScopedXcbPtr compReply(xcb_intern_atom_reply( - m_connection, - xcb_intern_atom( - m_connection, - 0, - netWmStateBypassCompositor.size(), - netWmStateBypassCompositor.c_str() - ), - 0 - )); - - // Disable compositor. - ScopedXcbPtr compositorError(xcb_request_check( - m_connection, - xcb_change_property_checked( - m_connection, - XCB_PROP_MODE_REPLACE, - m_window, - stateReply->atom, - XCB_ATOM_ATOM, - 32, - 1, - &compReply->atom - ) - )); - - if (compositorError) - sf::err() << "xcb_change_property failed, setting fullscreen not possible." << std::endl; } //////////////////////////////////////////////////////////// void WindowImplX11::initialize() { - // Get the atoms for registering the close event + // Get the atom for registering the close event static const std::string WM_DELETE_WINDOW_NAME = "WM_DELETE_WINDOW"; ScopedXcbPtr deleteWindowAtomReply(xcb_intern_atom_reply( m_connection, @@ -849,6 +1152,7 @@ void WindowImplX11::initialize() NULL )); + // Get the atom for setting the window protocols we support static const std::string WM_PROTOCOLS_NAME = "WM_PROTOCOLS"; ScopedXcbPtr protocolsAtomReply(xcb_intern_atom_reply( m_connection, @@ -861,22 +1165,104 @@ void WindowImplX11::initialize() NULL )); - if (protocolsAtomReply && deleteWindowAtomReply) - { - xcb_icccm_set_wm_protocols( + // Get the atom for registering the ping event + static const std::string NET_WM_PING = "_NET_WM_PING"; + sf::priv::ScopedXcbPtr wmPingReply(xcb_intern_atom_reply( + m_connection, + xcb_intern_atom( m_connection, - m_window, - protocolsAtomReply->atom, - 1, - &deleteWindowAtomReply->atom - ); + 0, + NET_WM_PING.size(), + NET_WM_PING.c_str() + ), + NULL + )); - m_atomClose = deleteWindowAtomReply->atom; + // Get the atom for setting the process ID of the window + static const std::string NET_WM_PID = "_NET_WM_PID"; + sf::priv::ScopedXcbPtr wmPidReply(xcb_intern_atom_reply( + m_connection, + xcb_intern_atom( + m_connection, + 0, + NET_WM_PID.size(), + NET_WM_PID.c_str() + ), + NULL + )); + + if (protocolsAtomReply) + { + m_atomWmProtocols = protocolsAtomReply->atom; + + xcb_atom_t atoms[2]; + Uint32 atomCount = 0; + + if (deleteWindowAtomReply && ewmhSupported() && wmPingReply && wmPidReply) + { + atoms[0] = deleteWindowAtomReply->atom; + atomCount = 1; + + m_atomClose = deleteWindowAtomReply->atom; + + Uint32 pid = getpid(); + + // Set PID. + ScopedXcbPtr pidError(xcb_request_check( + m_connection, + xcb_change_property_checked( + m_connection, + XCB_PROP_MODE_REPLACE, + m_window, + wmPidReply->atom, + XCB_ATOM_CARDINAL, + 32, + 1, + &pid + ) + )); + + if (!pidError) + { + atoms[1] = wmPingReply->atom; + atomCount = 2; + + m_atomPing = wmPingReply->atom; + } + } + else if (deleteWindowAtomReply) + { + atoms[0] = deleteWindowAtomReply->atom; + atomCount = 1; + + m_atomClose = deleteWindowAtomReply->atom; + } + + if (atomCount) + { + ScopedXcbPtr setProtocolsError(xcb_request_check( + m_connection, + xcb_icccm_set_wm_protocols( + m_connection, + m_window, + protocolsAtomReply->atom, + atomCount, + atoms + ) + )); + + if (setProtocolsError) + err() << "Failed to set window protocols" << std::endl; + } + else + { + err() << "Didn't set any window protocols" << std::endl; + } } else { // Should not happen, but better safe than sorry. - std::cerr << "Failed to request WM_PROTOCOLS/WM_DELETE_WINDOW_NAME atoms." << std::endl; + err() << "Failed to request WM_PROTOCOLS atoms." << std::endl; } // Create the input context @@ -888,7 +1274,7 @@ void WindowImplX11::initialize() m_inputMethod, XNClientWindow, m_window, - XNFocusWindow, + XNFocusWindow, m_window, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, @@ -947,12 +1333,7 @@ void WindowImplX11::createHiddenCursor() void WindowImplX11::cleanup() { // Restore the previous video mode (in case we were running in fullscreen) - if (fullscreenWindow == this) - { - - // Reset the fullscreen window - fullscreenWindow = NULL; - } + resetVideoMode(); // Unhide the mouse cursor (in case it was hidden) setMouseCursorVisible(true); @@ -1040,11 +1421,36 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) case XCB_CLIENT_MESSAGE: { xcb_client_message_event_t* e = reinterpret_cast(windowEvent); - if ((e->format == 32) && (e->data.data32[0]) == static_cast(m_atomClose)) + + // Handle window manager protocol messages we support + if (e->type == m_atomWmProtocols) { - Event event; - event.type = Event::Closed; - pushEvent(event); + if ((e->format == 32) && (e->data.data32[0]) == static_cast(m_atomClose)) + { + // Handle the WM_DELETE_WINDOW message + Event event; + event.type = Event::Closed; + pushEvent(event); + } + else if ((e->format == 32) && (e->data.data32[0]) == static_cast(m_atomPing)) + { + // Handle the _NET_WM_PING message, send pong back to WM to show that we are responsive + e->window = XCBDefaultRootWindow(m_connection); + + ScopedXcbPtr pongError(xcb_request_check( + m_connection, + xcb_send_event_checked( + m_connection, + 0, + XCBDefaultRootWindow(m_connection), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + reinterpret_cast(e) + ) + )); + + if (pongError) + err() << "Could not send pong event back to WM" << std::endl; + } } break; } diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index 2960ee07..b5aa1900 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -179,6 +179,20 @@ protected: private: + //////////////////////////////////////////////////////////// + /// \brief Set fullscreen video mode + /// + /// \param Mode video mode to switch to + /// + //////////////////////////////////////////////////////////// + void setVideoMode(const VideoMode& mode); + + //////////////////////////////////////////////////////////// + /// \brief Reset to desktop video mode + /// + //////////////////////////////////////////////////////////// + void resetVideoMode(); + //////////////////////////////////////////////////////////// /// \brief Switch to fullscreen mode /// @@ -234,20 +248,22 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - ::Window m_window; ///< X11 structure defining our window - ::Display* m_display; ///< Pointer to the display - xcb_connection_t* m_connection; ///< Pointer to the xcb connection - xcb_screen_t* m_screen; ///< Screen identifier - XIM m_inputMethod; ///< Input method linked to the X display - XIC m_inputContext; ///< Input context used to get unicode input in our window - bool m_isExternal; ///< Tell whether the window has been created externally or by SFML - Atom m_atomClose; ///< Atom used to identify the close event - int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen - Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one - bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? - Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) - bool m_useSizeHints; ///< Is the size of the window fixed with size hints? - bool m_fullscreen; ///< Is window in fullscreen? + ::Window m_window; ///< X11 structure defining our window + ::Display* m_display; ///< Pointer to the display + xcb_connection_t* m_connection; ///< Pointer to the xcb connection + xcb_screen_t* m_screen; ///< Screen identifier + XIM m_inputMethod; ///< Input method linked to the X display + XIC m_inputContext; ///< Input context used to get unicode input in our window + bool m_isExternal; ///< Tell whether the window has been created externally or by SFML + Atom m_atomWmProtocols; ///< Atom used to identify WM protocol messages + Atom m_atomClose; ///< Atom used to identify the close event + Atom m_atomPing; ///< Atom used to identify the ping event + 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 + bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? + Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) + bool m_useSizeHints; ///< Is the size of the window fixed with size hints? + bool m_fullscreen; ///< Is window in fullscreen? }; } // namespace priv