diff options
author | Gatis Paeglis <gatis.paeglis@qt.io> | 2018-11-05 14:26:24 +0100 |
---|---|---|
committer | Gatis Paeglis <gatis.paeglis@qt.io> | 2019-01-04 20:11:52 +0000 |
commit | fe63900dc9891dd355ca1f10d6c7e5fd1516f5d5 (patch) | |
tree | ca2dde2d2e297b629843c7f79098edc9df46826f /src/plugins/platforms/xcb/qxcbwindow.cpp | |
parent | 03039979b5a643f9def38a73e19835bb69384202 (diff) |
xcb: rework focus-in peeker so we can drop PeekFunc API
The API for registering temporary peek function was added ~7 years
ago by 78264f333eb7c262380714ed6517562266f11a03. It was never been
used for anything else. The solution from 78264f333 also did not work
very well on KDE desktop, quoting Martin Flöser:
"In case the keyboard gets grabbed by another process and immediately
ungrabbed the active Qt application window receives a FocusOut and a
FocusIn event. FocusOut on the grab of keyboard, FocusIn on the ungrab.
Qt registers a peek function for checking the FocusIn event, but the
timespan is too short: the new event is not yet queued. This causes
a QEvent::WindowDeactivate being emitted, followed directly by a
QEvent::WindowActivate. This has quite some side effects, for example
rendering flickering in the GUI (switching to inactive/active in short
time frame), hooks on WindowDeactivate being run, etc.
Real world examples for such short keyboard grabs are global shortcut
listener applications like kglobalaccel5. It has e.g. a passive key
grab on the mute key, which is then turned into an active grab when
the key is grabbed. Kglobalaccel5 immediately ungrabs the keyboard
and flushes the connection if it gets a key event, but it of course
causes the sequence of FocusOut and FocusIn events in the active
Qt window."
Reworked the code to use QTimer instead, which is more elegant solution,
because it does not rely on race-conditions, but uses a concreate time
to wait instead. Also the need to write focusInPeeker() caused us to
duplicate event handlers that were present already elsewhere.
Change-Id: I647e52fb2634fdf55a640e19b13265c356f96c95
Reviewed-by: Mikhail Svetkin <mikhail.svetkin@qt.io>
Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbwindow.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 33 |
1 files changed, 4 insertions, 29 deletions
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3bfcbf2adb..9382488b74 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -843,40 +843,12 @@ void QXcbWindow::doFocusIn() QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason); } -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(nullptr, Qt::ActiveWindowFocusReason); - return true; - } - uint response_type = event->response_type & ~0x80; - if (response_type == XCB_FOCUS_IN) { - // Ignore focus events that are being sent only because the pointer is over - // our window, even if the input focus is in a different window. - xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) event; - if (e->detail != XCB_NOTIFY_DETAIL_POINTER) - return true; - } - - /* We are also interested in XEMBED_FOCUS_IN events */ - if (response_type == XCB_CLIENT_MESSAGE) { - xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event; - if (cme->type == connection->atom(QXcbAtom::_XEMBED) - && cme->data.data32[1] == XEMBED_FOCUS_IN) - return true; - } - - return false; -} - void QXcbWindow::doFocusOut() { 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); + connection()->focusInTimer().start(400); } struct QtMotifWmHints { @@ -2264,6 +2236,8 @@ void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *event) // our window, even if the input focus is in a different window. if (event->detail == XCB_NOTIFY_DETAIL_POINTER) return; + + connection()->focusInTimer().stop(); doFocusIn(); } @@ -2491,6 +2465,7 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event) xcbScreen()->windowShown(this); break; case XEMBED_FOCUS_IN: + connection()->focusInTimer().stop(); Qt::FocusReason reason; switch (event->data.data32[2]) { case XEMBED_FOCUS_FIRST: |