summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@qt.io>2017-03-13 20:35:24 +0100
committerGatis Paeglis <gatis.paeglis@qt.io>2017-04-03 10:20:53 +0000
commite0e6cbdacb7520a6d9906e16a517c9932702d1aa (patch)
treefeacd73536d1ce0c97f09357795e1fdb3eaed9d3
parenta03390a8b0318e30ae3b6dc9954093c137a20c32 (diff)
xcb: prevent dangling pointer when window focus changes
With the current implementation, the QXcbConnection::m_focusWindow was holding a dangling pointer during the focus transition from a dying modal window to other modal window. 1) QXcbConnection::m_focusWindow holds a pointer to A; 2) A is closed; 3) relayFocusToModalWindow B; => m_focusWindow now points to a dead window. 4) We get a reply back from WM in a respone to relayFocusToModalWindow (_NET_ACTIVE_WINDOW) => m_focusWindow now points to a valid window. The fix is to update m_focusWindow to nullptr, when the current focus window was destroyed and the new focus window has not been set yet by WM. This patch actually solves a more general case - whenever we get a focus-out event, we should set m_focusWindow to nullptr. It is ok for none of the windows to be in-focus while focus transition is happening. The focusInPeeker will make sure to "optimize out" (when possible) this no-window-in-focus state, and GUI won't be bothered by this extra event. This is how things were working before relayFocusToModalWindow was introduced. Having a focus-relay mechanism in-between is ok, but it should not have changed the original behavior. Task-number: QTBUG-48391 Task-number: QTBUG-55197 Change-Id: I6fdda9de73f999dad84000059ce4b89c0d1a964c Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp20
3 files changed, 12 insertions, 14 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 5e600c740b..5e52d4d80f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1382,9 +1382,9 @@ void QXcbEventReader::unlock()
m_mutex.unlock();
}
-void QXcbConnection::setFocusWindow(QXcbWindow *w)
+void QXcbConnection::setFocusWindow(QWindow *w)
{
- m_focusWindow = w;
+ m_focusWindow = w ? static_cast<QXcbWindow *>(w->handle()) : nullptr;
}
void QXcbConnection::setMouseGrabber(QXcbWindow *w)
{
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 01a97a187a..22c7d1aa8e 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -480,7 +480,7 @@ public:
Qt::MouseButton translateMouseButton(xcb_button_t s);
QXcbWindow *focusWindow() const { return m_focusWindow; }
- void setFocusWindow(QXcbWindow *);
+ void setFocusWindow(QWindow *);
QXcbWindow *mouseGrabber() const { return m_mouseGrabber; }
void setMouseGrabber(QXcbWindow *);
QXcbWindow *mousePressWindow() const { return m_mousePressWindow; }
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 15ca68c663..509bc9b038 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -941,7 +941,7 @@ void QXcbWindow::doFocusIn()
if (relayFocusToModalWindow())
return;
QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
- connection()->setFocusWindow(static_cast<QXcbWindow *>(w->handle()));
+ connection()->setFocusWindow(w);
QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
}
@@ -949,7 +949,7 @@ static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event
{
if (!event) {
// FocusIn event is not in the queue, proceed with FocusOut normally.
- QWindowSystemInterface::handleWindowActivated(0, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
return true;
}
uint response_type = event->response_type & ~0x80;
@@ -974,12 +974,10 @@ static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event
void QXcbWindow::doFocusOut()
{
- if (relayFocusToModalWindow())
- return;
- connection()->setFocusWindow(0);
- // Do not set the active window to 0 if there is a FocusIn coming.
- // There is however no equivalent for XPutBackEvent so register a
- // callback for QXcbConnection instead.
+ connection()->setFocusWindow(nullptr);
+ relayFocusToModalWindow();
+ // Do not set the active window to nullptr if there is a FocusIn coming.
+ // The FocusIn handler will update QXcbConnection::setFocusWindow() accordingly.
connection()->addPeekFunc(focusInPeeker);
}
@@ -2834,14 +2832,14 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
reason = Qt::OtherFocusReason;
break;
}
- connection()->setFocusWindow(static_cast<QXcbWindow*>(window()->handle()));
+ connection()->setFocusWindow(window());
QWindowSystemInterface::handleWindowActivated(window(), reason);
break;
case XEMBED_FOCUS_OUT:
if (window() == QGuiApplication::focusWindow()
&& !activeWindowChangeQueued(window())) {
- connection()->setFocusWindow(0);
- QWindowSystemInterface::handleWindowActivated(0);
+ connection()->setFocusWindow(nullptr);
+ QWindowSystemInterface::handleWindowActivated(nullptr);
}
break;
}