mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +08:00
Fixed XCB events being handled by the wrong windows in multi-window applications (#843).
This commit is contained in:
parent
c229877313
commit
bd34935f2a
@ -31,6 +31,8 @@
|
||||
#include <SFML/Window/Unix/ScopedXcbPtr.hpp>
|
||||
#include <SFML/System/Utf.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include <xcb/xcb_image.h>
|
||||
#include <xcb/randr.h>
|
||||
@ -55,6 +57,7 @@ namespace
|
||||
{
|
||||
sf::priv::WindowImplX11* fullscreenWindow = NULL;
|
||||
std::vector<sf::priv::WindowImplX11*> allWindows;
|
||||
sf::Mutex allWindowsMutex;
|
||||
unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS |
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION |
|
||||
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS |
|
||||
@ -429,6 +432,7 @@ WindowImplX11::~WindowImplX11()
|
||||
CloseDisplay(m_display);
|
||||
|
||||
// Remove this window from the global list of windows (required for focus request)
|
||||
Lock lock(allWindowsMutex);
|
||||
allWindows.erase(std::find(allWindows.begin(), allWindows.end(), this));
|
||||
}
|
||||
|
||||
@ -453,7 +457,17 @@ void WindowImplX11::processEvents()
|
||||
xcb_key_release_event_t* lastKeyReleaseEvent = NULL;
|
||||
uint8_t eventType = 0;
|
||||
|
||||
while((event = xcb_poll_for_event(m_connection)))
|
||||
if (!m_xcbEvents.empty())
|
||||
{
|
||||
event = m_xcbEvents.front();
|
||||
m_xcbEvents.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
event = xcb_poll_for_event(m_connection);
|
||||
}
|
||||
|
||||
while (event)
|
||||
{
|
||||
eventType = event->response_type & ~0x80;
|
||||
|
||||
@ -474,29 +488,45 @@ void WindowImplX11::processEvents()
|
||||
// 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);
|
||||
if (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.
|
||||
// Check if we're in charge of the key release
|
||||
if (!passEvent(event, reinterpret_cast<xcb_key_release_event_t*>(event)->event))
|
||||
{
|
||||
// Remember this key release event.
|
||||
lastKeyReleaseEvent = reinterpret_cast<xcb_key_release_event_t*>(event);
|
||||
event = NULL; // For safety reasons.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
processEvent(event);
|
||||
free(event);
|
||||
if (processEvent(event))
|
||||
free(event);
|
||||
}
|
||||
|
||||
if (!m_xcbEvents.empty())
|
||||
{
|
||||
event = m_xcbEvents.front();
|
||||
m_xcbEvents.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
event = xcb_poll_for_event(m_connection);
|
||||
}
|
||||
}
|
||||
|
||||
// Process any held back release event.
|
||||
if (lastKeyReleaseEvent)
|
||||
{
|
||||
processEvent(reinterpret_cast<xcb_generic_event_t*>(lastKeyReleaseEvent));
|
||||
free(lastKeyReleaseEvent);
|
||||
if (processEvent(reinterpret_cast<xcb_generic_event_t*>(lastKeyReleaseEvent)))
|
||||
free(lastKeyReleaseEvent);
|
||||
|
||||
lastKeyReleaseEvent = NULL;
|
||||
}
|
||||
}
|
||||
@ -917,12 +947,16 @@ void WindowImplX11::requestFocus()
|
||||
// Check the global list of windows to find out whether an SFML window has the focus
|
||||
// Note: can't handle console and other non-SFML windows belonging to the application.
|
||||
bool sfmlWindowFocused = false;
|
||||
for (std::vector<WindowImplX11*>::iterator itr = allWindows.begin(); itr != allWindows.end(); ++itr)
|
||||
|
||||
{
|
||||
if ((*itr)->hasFocus())
|
||||
Lock lock(allWindowsMutex);
|
||||
for (std::vector<WindowImplX11*>::iterator itr = allWindows.begin(); itr != allWindows.end(); ++itr)
|
||||
{
|
||||
sfmlWindowFocused = true;
|
||||
break;
|
||||
if ((*itr)->hasFocus())
|
||||
{
|
||||
sfmlWindowFocused = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1492,6 +1526,7 @@ void WindowImplX11::initialize()
|
||||
xcb_flush(m_connection);
|
||||
|
||||
// Add this window to the global list of windows (required for focus request)
|
||||
Lock lock(allWindowsMutex);
|
||||
allWindows.push_back(this);
|
||||
}
|
||||
|
||||
@ -1574,6 +1609,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Destroy event
|
||||
case XCB_DESTROY_NOTIFY:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_destroy_notify_event_t*>(windowEvent)->window))
|
||||
return false;
|
||||
|
||||
// The window is about to be destroyed: we must cleanup resources
|
||||
cleanup();
|
||||
break;
|
||||
@ -1582,6 +1620,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Gain focus event
|
||||
case XCB_FOCUS_IN:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_focus_in_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
// Update the input context
|
||||
if (m_inputContext)
|
||||
XSetICFocus(m_inputContext);
|
||||
@ -1632,6 +1673,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Lost focus event
|
||||
case XCB_FOCUS_OUT:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_focus_out_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
// Update the input context
|
||||
if (m_inputContext)
|
||||
XUnsetICFocus(m_inputContext);
|
||||
@ -1645,6 +1689,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Resize event
|
||||
case XCB_CONFIGURE_NOTIFY:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent)->window))
|
||||
return false;
|
||||
|
||||
xcb_configure_notify_event_t* e = reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent);
|
||||
Event event;
|
||||
event.type = Event::Resized;
|
||||
@ -1657,6 +1704,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Close event
|
||||
case XCB_CLIENT_MESSAGE:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_client_message_event_t*>(windowEvent)->window))
|
||||
return false;
|
||||
|
||||
xcb_client_message_event_t* e = reinterpret_cast<xcb_client_message_event_t*>(windowEvent);
|
||||
|
||||
// Handle window manager protocol messages we support
|
||||
@ -1695,6 +1745,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Key down event
|
||||
case XCB_KEY_PRESS:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_key_press_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_key_press_event_t* e = reinterpret_cast<xcb_key_press_event_t*>(windowEvent);
|
||||
|
||||
// Get the keysym of the key that has been pressed
|
||||
@ -1776,6 +1829,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Key up event
|
||||
case XCB_KEY_RELEASE:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_key_release_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_key_release_event_t* e = reinterpret_cast<xcb_key_release_event_t*>(windowEvent);
|
||||
|
||||
// Get the keysym of the key that has been pressed
|
||||
@ -1806,6 +1862,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Mouse button pressed
|
||||
case XCB_BUTTON_PRESS:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_button_press_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_button_press_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent);
|
||||
|
||||
// XXX: Why button 8 and 9?
|
||||
@ -1837,6 +1896,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Mouse button released
|
||||
case XCB_BUTTON_RELEASE:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_button_release_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_button_release_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent);
|
||||
|
||||
xcb_button_t button = e->detail;
|
||||
@ -1891,6 +1953,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Mouse moved
|
||||
case XCB_MOTION_NOTIFY:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_motion_notify_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_motion_notify_event_t* e = reinterpret_cast<xcb_motion_notify_event_t*>(windowEvent);
|
||||
Event event;
|
||||
event.type = Event::MouseMoved;
|
||||
@ -1903,6 +1968,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Mouse entered
|
||||
case XCB_ENTER_NOTIFY:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_enter_notify_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_enter_notify_event_t* enterNotifyEvent = reinterpret_cast<xcb_enter_notify_event_t*>(windowEvent);
|
||||
|
||||
if (enterNotifyEvent->mode == NotifyNormal)
|
||||
@ -1917,6 +1985,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Mouse left
|
||||
case XCB_LEAVE_NOTIFY:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_leave_notify_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_leave_notify_event_t* leaveNotifyEvent = reinterpret_cast<xcb_leave_notify_event_t*>(windowEvent);
|
||||
|
||||
if (leaveNotifyEvent->mode == NotifyNormal)
|
||||
@ -1931,6 +2002,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
// Parent window changed
|
||||
case XCB_REPARENT_NOTIFY:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_reparent_notify_event_t*>(windowEvent)->window))
|
||||
return false;
|
||||
|
||||
// Catch reparent events to properly apply fullscreen on
|
||||
// some "strange" window managers (like Awesome) which
|
||||
// seem to make use of temporary parents during mapping
|
||||
@ -1946,6 +2020,33 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool WindowImplX11::passEvent(xcb_generic_event_t* windowEvent, xcb_window_t window)
|
||||
{
|
||||
// Check if this is our event
|
||||
if (window == m_window)
|
||||
return false;
|
||||
|
||||
Lock lock(allWindowsMutex);
|
||||
|
||||
// If we are the only window, there is nobody else to pass to
|
||||
if (allWindows.size() == 1)
|
||||
return false;
|
||||
|
||||
for (std::vector<sf::priv::WindowImplX11*>::iterator i = allWindows.begin(); i != allWindows.end(); ++i)
|
||||
{
|
||||
if ((*i)->m_window == window)
|
||||
{
|
||||
(*i)->m_xcbEvents.push_back(windowEvent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// It seems nobody wants the event, we'll just handle it ourselves
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Keyboard::Key WindowImplX11::keysymToSF(xcb_keysym_t symbol)
|
||||
{
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include <SFML/System/String.hpp>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <xcb/xcb_ewmh.h>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -244,7 +244,18 @@ private:
|
||||
/// \return True if the event was processed, false if it was discarded
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool processEvent(xcb_generic_event_t *windowEvent);
|
||||
bool processEvent(xcb_generic_event_t* windowEvent);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Pass an incoming event to another window
|
||||
///
|
||||
/// \param windowEvent Event which is being processed
|
||||
/// \param window Window to pass to
|
||||
///
|
||||
/// \return True if the event was passed to another window, false if it is destined for the current window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool passEvent(xcb_generic_event_t* windowEvent, xcb_window_t window);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Convert a X11 keysym to SFML key code
|
||||
@ -259,22 +270,23 @@ 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_ewmh_connection_t m_ewmhConnection; ///< xcb EWMH 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
|
||||
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?
|
||||
xcb_window_t m_window; ///< xcb identifier defining our window
|
||||
::Display* m_display; ///< Pointer to the display
|
||||
xcb_connection_t* m_connection; ///< Pointer to the xcb connection
|
||||
xcb_ewmh_connection_t m_ewmhConnection; ///< xcb EWMH 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
|
||||
std::deque<xcb_generic_event_t*> m_xcbEvents; ///< Events that were received in another window's loop
|
||||
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
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user