xcb: Properly process enter/leave events
Ignore enter/leave events when there is a window under mouse button. Unset window under mouse button if other window is grabbed. Smarter ignoring (un)grab ancestor enter/leave event. Ignore ungrab inferior leave event. Amends: b9f76db30d261421e4da58f29053181af04ceb4d Task-number: QTBUG-46576 Task-number: QTBUG-51573 Task-number: QTBUG-52332 Task-number: QTBUG-52488 Change-Id: I8d926309aa60bb8929728691c31ecf93d1e299ad Reviewed-by: Dmitry Shachnev <mitya57@gmail.com> Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com> Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
This commit is contained in:
parent
1b9d082bb8
commit
c511466d74
@ -560,6 +560,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
|
|||||||
, m_buttons(0)
|
, m_buttons(0)
|
||||||
, m_focusWindow(0)
|
, m_focusWindow(0)
|
||||||
, m_mouseGrabber(0)
|
, m_mouseGrabber(0)
|
||||||
|
, m_mousePressWindow(0)
|
||||||
, m_clientLeader(0)
|
, m_clientLeader(0)
|
||||||
, m_systemTrayTracker(0)
|
, m_systemTrayTracker(0)
|
||||||
, m_glIntegration(Q_NULLPTR)
|
, m_glIntegration(Q_NULLPTR)
|
||||||
@ -1367,6 +1368,11 @@ void QXcbConnection::setFocusWindow(QXcbWindow *w)
|
|||||||
void QXcbConnection::setMouseGrabber(QXcbWindow *w)
|
void QXcbConnection::setMouseGrabber(QXcbWindow *w)
|
||||||
{
|
{
|
||||||
m_mouseGrabber = w;
|
m_mouseGrabber = w;
|
||||||
|
m_mousePressWindow = Q_NULLPTR;
|
||||||
|
}
|
||||||
|
void QXcbConnection::setMousePressWindow(QXcbWindow *w)
|
||||||
|
{
|
||||||
|
m_mousePressWindow = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXcbConnection::grabServer()
|
void QXcbConnection::grabServer()
|
||||||
|
@ -475,6 +475,8 @@ public:
|
|||||||
void setFocusWindow(QXcbWindow *);
|
void setFocusWindow(QXcbWindow *);
|
||||||
QXcbWindow *mouseGrabber() const { return m_mouseGrabber; }
|
QXcbWindow *mouseGrabber() const { return m_mouseGrabber; }
|
||||||
void setMouseGrabber(QXcbWindow *);
|
void setMouseGrabber(QXcbWindow *);
|
||||||
|
QXcbWindow *mousePressWindow() const { return m_mousePressWindow; }
|
||||||
|
void setMousePressWindow(QXcbWindow *);
|
||||||
|
|
||||||
QByteArray startupId() const { return m_startupId; }
|
QByteArray startupId() const { return m_startupId; }
|
||||||
void setStartupId(const QByteArray &nextId) { m_startupId = nextId; }
|
void setStartupId(const QByteArray &nextId) { m_startupId = nextId; }
|
||||||
@ -658,6 +660,7 @@ private:
|
|||||||
|
|
||||||
QXcbWindow *m_focusWindow;
|
QXcbWindow *m_focusWindow;
|
||||||
QXcbWindow *m_mouseGrabber;
|
QXcbWindow *m_mouseGrabber;
|
||||||
|
QXcbWindow *m_mousePressWindow;
|
||||||
|
|
||||||
xcb_window_t m_clientLeader;
|
xcb_window_t m_clientLeader;
|
||||||
QByteArray m_startupId;
|
QByteArray m_startupId;
|
||||||
|
@ -616,8 +616,12 @@ QXcbWindow::~QXcbWindow()
|
|||||||
{
|
{
|
||||||
if (window()->type() != Qt::ForeignWindow)
|
if (window()->type() != Qt::ForeignWindow)
|
||||||
destroy();
|
destroy();
|
||||||
else if (connection()->mouseGrabber() == this)
|
else {
|
||||||
|
if (connection()->mouseGrabber() == this)
|
||||||
connection()->setMouseGrabber(Q_NULLPTR);
|
connection()->setMouseGrabber(Q_NULLPTR);
|
||||||
|
if (connection()->mousePressWindow() == this)
|
||||||
|
connection()->setMousePressWindow(Q_NULLPTR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXcbWindow::destroy()
|
void QXcbWindow::destroy()
|
||||||
@ -875,6 +879,16 @@ void QXcbWindow::hide()
|
|||||||
|
|
||||||
if (connection()->mouseGrabber() == this)
|
if (connection()->mouseGrabber() == this)
|
||||||
connection()->setMouseGrabber(Q_NULLPTR);
|
connection()->setMouseGrabber(Q_NULLPTR);
|
||||||
|
if (QPlatformWindow *w = connection()->mousePressWindow()) {
|
||||||
|
// Unset mousePressWindow when it (or one of its parents) is unmapped
|
||||||
|
while (w) {
|
||||||
|
if (w == this) {
|
||||||
|
connection()->setMousePressWindow(Q_NULLPTR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
w = w->parent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_mapped = false;
|
m_mapped = false;
|
||||||
|
|
||||||
@ -2214,6 +2228,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connection()->setMousePressWindow(this);
|
||||||
|
|
||||||
handleMouseEvent(timestamp, local, global, modifiers, source);
|
handleMouseEvent(timestamp, local, global, modifiers, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2228,19 +2244,44 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (connection()->buttons() == Qt::NoButton)
|
||||||
|
connection()->setMousePressWindow(Q_NULLPTR);
|
||||||
|
|
||||||
handleMouseEvent(timestamp, local, global, modifiers, source);
|
handleMouseEvent(timestamp, local, global, modifiers, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ignoreLeaveEvent(quint8 mode, quint8 detail)
|
static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
|
||||||
{
|
{
|
||||||
return (mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM
|
/* Checking for XCB_NOTIFY_MODE_GRAB and XCB_NOTIFY_DETAIL_ANCESTOR prevents unwanted
|
||||||
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|
* enter/leave events on AwesomeWM on mouse button press. It also ignores duplicated
|
||||||
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL;
|
* enter/leave events on Alt+Tab switching on some WMs with XInput2 events.
|
||||||
|
* Without XInput2 events the (Un)grabAncestor cannot be checked when mouse button is
|
||||||
|
* not pressed, otherwise (e.g. on Alt+Tab) it can igonre important enter/leave events.
|
||||||
|
*/
|
||||||
|
if (conn) {
|
||||||
|
const bool mouseButtonsPressed = (conn->buttons() != Qt::NoButton);
|
||||||
|
#ifdef XCB_USE_XINPUT22
|
||||||
|
return mouseButtonsPressed || (conn->isAtLeastXI22() && conn->xi2MouseEvents());
|
||||||
|
#else
|
||||||
|
return mouseButtonsPressed;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ignoreEnterEvent(quint8 mode, quint8 detail)
|
static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
|
||||||
{
|
{
|
||||||
return ((mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM
|
return ((doCheckUnGrabAncestor(conn)
|
||||||
|
&& mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
|
||||||
|
|| (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR)
|
||||||
|
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|
||||||
|
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
|
||||||
|
{
|
||||||
|
return ((doCheckUnGrabAncestor(conn)
|
||||||
|
&& mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
|
||||||
|| (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB)
|
|| (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB)
|
||||||
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|
||||||
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
|
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
|
||||||
@ -2274,9 +2315,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
|
|||||||
|
|
||||||
const QPoint global = QPoint(root_x, root_y);
|
const QPoint global = QPoint(root_x, root_y);
|
||||||
|
|
||||||
if (ignoreEnterEvent(mode, detail)
|
if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
|
||||||
|| (connection()->buttons() != Qt::NoButton
|
|
||||||
&& QGuiApplicationPrivate::lastCursorPosition != global))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QPoint local(event_x, event_y);
|
const QPoint local(event_x, event_y);
|
||||||
@ -2288,11 +2327,7 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
|
|||||||
{
|
{
|
||||||
connection()->setTime(timestamp);
|
connection()->setTime(timestamp);
|
||||||
|
|
||||||
const QPoint global(root_x, root_y);
|
if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow())
|
||||||
|
|
||||||
if (ignoreLeaveEvent(mode, detail)
|
|
||||||
|| (connection()->buttons() != Qt::NoButton
|
|
||||||
&& QGuiApplicationPrivate::lastCursorPosition != global))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EnterEventChecker checker;
|
EnterEventChecker checker;
|
||||||
@ -2315,6 +2350,11 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i
|
|||||||
{
|
{
|
||||||
QPoint local(event_x, event_y);
|
QPoint local(event_x, event_y);
|
||||||
QPoint global(root_x, root_y);
|
QPoint global(root_x, root_y);
|
||||||
|
|
||||||
|
// "mousePressWindow" can be NULL i.e. if a window will be grabbed or umnapped, so set it again here
|
||||||
|
if (connection()->buttons() != Qt::NoButton && connection()->mousePressWindow() == Q_NULLPTR)
|
||||||
|
connection()->setMousePressWindow(this);
|
||||||
|
|
||||||
handleMouseEvent(timestamp, local, global, modifiers, source);
|
handleMouseEvent(timestamp, local, global, modifiers, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user