diff options
author | Gatis Paeglis <gatis.paeglis@qt.io> | 2017-03-13 20:35:24 +0100 |
---|---|---|
committer | Gatis Paeglis <gatis.paeglis@qt.io> | 2017-04-03 10:20:53 +0000 |
commit | e0e6cbdacb7520a6d9906e16a517c9932702d1aa (patch) | |
tree | feacd73536d1ce0c97f09357795e1fdb3eaed9d3 /src/plugins/platforms/xcb/qxcbwindow.cpp | |
parent | a03390a8b0318e30ae3b6dc9954093c137a20c32 (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>
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbwindow.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 20 |
1 files changed, 9 insertions, 11 deletions
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; } |