mirror of
https://github.com/SFML/SFML.git
synced 2024-12-01 15:51:04 +08:00
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:
parent
427ce77d4e
commit
6f3273b7a6
@ -69,7 +69,8 @@ namespace
|
|||||||
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION |
|
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION |
|
||||||
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS |
|
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS |
|
||||||
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
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)
|
// Filter the events received by windows (only allow those matching a specific window)
|
||||||
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
|
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
|
||||||
@ -367,7 +368,8 @@ m_keyRepeat (true),
|
|||||||
m_previousSize (-1, -1),
|
m_previousSize (-1, -1),
|
||||||
m_useSizeHints (false),
|
m_useSizeHints (false),
|
||||||
m_fullscreen (false),
|
m_fullscreen (false),
|
||||||
m_cursorGrabbed (false)
|
m_cursorGrabbed (false),
|
||||||
|
m_windowMapped (false)
|
||||||
{
|
{
|
||||||
// Open a connection with the X server
|
// Open a connection with the X server
|
||||||
m_display = OpenDisplay();
|
m_display = OpenDisplay();
|
||||||
@ -422,7 +424,8 @@ m_keyRepeat (true),
|
|||||||
m_previousSize (-1, -1),
|
m_previousSize (-1, -1),
|
||||||
m_useSizeHints (false),
|
m_useSizeHints (false),
|
||||||
m_fullscreen ((style & Style::Fullscreen) != 0),
|
m_fullscreen ((style & Style::Fullscreen) != 0),
|
||||||
m_cursorGrabbed (m_fullscreen)
|
m_cursorGrabbed (m_fullscreen),
|
||||||
|
m_windowMapped (false)
|
||||||
{
|
{
|
||||||
// Open a connection with the X server
|
// Open a connection with the X server
|
||||||
m_display = OpenDisplay();
|
m_display = OpenDisplay();
|
||||||
@ -913,6 +916,13 @@ void WindowImplX11::setVisible(bool visible)
|
|||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
err() << "Failed to change window visibility" << std::endl;
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -926,9 +936,14 @@ void WindowImplX11::setVisible(bool visible)
|
|||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
err() << "Failed to change window visibility" << std::endl;
|
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)
|
if (grabbed)
|
||||||
{
|
{
|
||||||
// TODO XGrabPointer(m_display, m_window, true, 0, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
|
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
|
||||||
m_cursorGrabbed = true;
|
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
// TODO XUngrabPointer(m_display, CurrentTime);
|
ScopedXcbPtr<xcb_generic_error_t> error(xcb_request_check(
|
||||||
m_cursorGrabbed = false;
|
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
|
// Grab cursor
|
||||||
if (m_cursorGrabbed)
|
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 event;
|
||||||
event.type = Event::GainedFocus;
|
event.type = Event::GainedFocus;
|
||||||
@ -1731,7 +1809,18 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
|||||||
|
|
||||||
// Release cursor
|
// Release cursor
|
||||||
if (m_cursorGrabbed)
|
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 event;
|
||||||
event.type = Event::LostFocus;
|
event.type = Event::LostFocus;
|
||||||
@ -2007,16 +2096,33 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent window changed
|
// Window unmapped
|
||||||
case ReparentNotify:
|
case UnmapNotify:
|
||||||
{
|
{
|
||||||
// Catch reparent events to properly apply fullscreen on
|
if (windowEvent.xunmap.window == m_window)
|
||||||
// some "strange" window managers (like Awesome) which
|
m_windowMapped = false;
|
||||||
// seem to make use of temporary parents during mapping
|
|
||||||
if (m_fullscreen)
|
break;
|
||||||
switchToFullscreen();
|
}
|
||||||
|
|
||||||
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,6 +328,7 @@ private:
|
|||||||
bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
|
bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
|
||||||
bool m_fullscreen; ///< Is the window in fullscreen?
|
bool m_fullscreen; ///< Is the window in fullscreen?
|
||||||
bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
|
bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
|
||||||
|
bool m_windowMapped; ///< Has the window been mapped by the window manager?
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
Loading…
Reference in New Issue
Block a user