Added Unix implementation of sf::Window::setCursorGrabbed (#394), fixed xcb_set_input_focus being called on a window before it is viewable on some window managers (#991).

This commit is contained in:
binary1248 2016-03-12 11:46:26 +01:00 committed by Lukas Dürrenberger
parent 427ce77d4e
commit 6f3273b7a6
2 changed files with 126 additions and 19 deletions

View File

@ -69,7 +69,8 @@ namespace
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION |
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS |
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW;
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
XCB_EVENT_MASK_VISIBILITY_CHANGE;
// Filter the events received by windows (only allow those matching a specific window)
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
@ -367,7 +368,8 @@ m_keyRepeat (true),
m_previousSize (-1, -1),
m_useSizeHints (false),
m_fullscreen (false),
m_cursorGrabbed (false)
m_cursorGrabbed (false),
m_windowMapped (false)
{
// Open a connection with the X server
m_display = OpenDisplay();
@ -422,7 +424,8 @@ m_keyRepeat (true),
m_previousSize (-1, -1),
m_useSizeHints (false),
m_fullscreen ((style & Style::Fullscreen) != 0),
m_cursorGrabbed (m_fullscreen)
m_cursorGrabbed (m_fullscreen),
m_windowMapped (false)
{
// Open a connection with the X server
m_display = OpenDisplay();
@ -913,6 +916,13 @@ void WindowImplX11::setVisible(bool visible)
if (error)
err() << "Failed to change window visibility" << std::endl;
xcb_flush(m_connection);
// Before continuing, make sure the WM has
// internally marked the window as viewable
while (!m_windowMapped)
processEvents();
}
else
{
@ -926,9 +936,14 @@ void WindowImplX11::setVisible(bool visible)
if (error)
err() << "Failed to change window visibility" << std::endl;
}
xcb_flush(m_connection);
xcb_flush(m_connection);
// Before continuing, make sure the WM has
// internally marked the window as unviewable
while (m_windowMapped)
processEvents();
}
}
@ -963,13 +978,51 @@ void WindowImplX11::setMouseCursorGrabbed(bool grabbed)
if (grabbed)
{
// TODO XGrabPointer(m_display, m_window, true, 0, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
m_cursorGrabbed = true;
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
sf::priv::ScopedXcbPtr<xcb_grab_pointer_reply_t> grabPointerReply(xcb_grab_pointer_reply(
m_connection,
xcb_grab_pointer(
m_connection,
true,
m_window,
XCB_NONE,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
m_window,
XCB_NONE,
XCB_CURRENT_TIME
),
&error
));
if (!error && grabPointerReply && (grabPointerReply->status == XCB_GRAB_STATUS_SUCCESS))
{
m_cursorGrabbed = true;
}
else
{
err() << "Failed to grab mouse cursor" << std::endl;
}
}
else
{
// TODO XUngrabPointer(m_display, CurrentTime);
m_cursorGrabbed = false;
ScopedXcbPtr<xcb_generic_error_t> error(xcb_request_check(
m_connection,
xcb_ungrab_pointer_checked(
m_connection,
XCB_CURRENT_TIME
)
));
if (!error)
{
m_cursorGrabbed = false;
}
else
{
err() << "Failed to ungrab mouse cursor" << std::endl;
}
}
}
@ -1685,7 +1738,32 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
// Grab cursor
if (m_cursorGrabbed)
;// TODO XGrabPointer(m_display, m_window, true, 0, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
{
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
sf::priv::ScopedXcbPtr<xcb_grab_pointer_reply_t> grabPointerReply(xcb_grab_pointer_reply(
m_connection,
xcb_grab_pointer(
m_connection,
true,
m_window,
XCB_NONE,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
m_window,
XCB_NONE,
XCB_CURRENT_TIME
),
&error
));
if (error || !grabPointerReply || (grabPointerReply->status != XCB_GRAB_STATUS_SUCCESS))
{
err() << "Failed to grab mouse cursor" << std::endl;
m_cursorGrabbed = false;
}
}
Event event;
event.type = Event::GainedFocus;
@ -1731,7 +1809,18 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
// Release cursor
if (m_cursorGrabbed)
;// TODO XUngrabPointer(m_display, CurrentTime);
{
ScopedXcbPtr<xcb_generic_error_t> error(xcb_request_check(
m_connection,
xcb_ungrab_pointer_checked(
m_connection,
XCB_CURRENT_TIME
)
));
if (error)
err() << "Failed to ungrab mouse cursor" << std::endl;
}
Event event;
event.type = Event::LostFocus;
@ -2007,16 +2096,33 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
break;
}
// Parent window changed
case ReparentNotify:
// Window unmapped
case UnmapNotify:
{
// Catch reparent events to properly apply fullscreen on
// some "strange" window managers (like Awesome) which
// seem to make use of temporary parents during mapping
if (m_fullscreen)
switchToFullscreen();
if (windowEvent.xunmap.window == m_window)
m_windowMapped = false;
break;
}
// Window visibility change
case VisibilityNotify:
{
// We prefer using VisibilityNotify over MapNotify because
// some window managers like awesome don't internally flag a
// window as viewable even after it is mapped but before it
// is visible leading to certain function calls failing with
// an unviewable error if called before VisibilityNotify arrives
// Empirical testing on most widely used window managers shows
// that mapping a window will always lead to a VisibilityNotify
// event that is not VisibilityFullyObscured
if (windowEvent.xvisibility.window == m_window)
{
if (windowEvent.xvisibility.state != VisibilityFullyObscured)
m_windowMapped = true;
}
XSync(m_display, True); // Discard remaining events
break;
}
}

View File

@ -328,6 +328,7 @@ private:
bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
bool m_fullscreen; ///< Is the window in fullscreen?
bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
bool m_windowMapped; ///< Has the window been mapped by the window manager?
};
} // namespace priv