summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp20
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp16
-rw-r--r--src/widgets/kernel/qapplication_qpa.cpp2
4 files changed, 42 insertions, 1 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 1d7611533a..6acc42208d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -483,6 +483,11 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
printXcbEvent("Unhandled XCB event", event);
}
+void QXcbConnection::addPeekFunc(PeekFunc f)
+{
+ m_peekFuncs.append(f);
+}
+
void QXcbConnection::processXcbEvents()
{
while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection()))
@@ -498,6 +503,15 @@ void QXcbConnection::processXcbEvents()
if (!response_type) {
handleXcbError((xcb_generic_error_t *)event);
} else {
+ QVector<PeekFunc>::iterator it = m_peekFuncs.begin();
+ while (it != m_peekFuncs.end()) {
+ // These callbacks return true if the event is what they were
+ // waiting for, remove them from the list in that case.
+ if ((*it)(event))
+ it = m_peekFuncs.erase(it);
+ else
+ ++it;
+ }
handleXcbEvent(event);
}
@@ -506,6 +520,12 @@ void QXcbConnection::processXcbEvents()
eventqueue.clear();
+ // Indicate with a null event that the event the callbacks are waiting for
+ // is not in the queue currently.
+ Q_FOREACH (PeekFunc f, m_peekFuncs)
+ f(0);
+ m_peekFuncs.clear();
+
xcb_flush(xcb_connection());
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index e0cb1d954e..51aa09fcef 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -284,6 +284,9 @@ public:
QXcbWindow *platformWindowFromId(xcb_window_t id);
+ typedef bool (*PeekFunc)(xcb_generic_event_t *);
+ void addPeekFunc(PeekFunc f);
+
private slots:
void processXcbEvents();
@@ -335,6 +338,8 @@ private:
QVector<xcb_generic_event_t *> eventqueue;
WindowMapper m_mapper;
+
+ QVector<PeekFunc> m_peekFuncs;
};
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 9d6f3e01ad..3b70968dfc 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -1087,9 +1087,23 @@ void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
QWindowSystemInterface::handleWindowActivated(window());
}
+static bool focusInPeeker(xcb_generic_event_t *event)
+{
+ if (!event) {
+ // FocusIn event is not in the queue, proceed with FocusOut normally.
+ QWindowSystemInterface::handleWindowActivated(0);
+ return true;
+ }
+ uint response_type = event->response_type & ~0x80;
+ return response_type == XCB_FOCUS_IN;
+}
+
void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
{
- QWindowSystemInterface::handleWindowActivated(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()->addPeekFunc(focusInPeeker);
}
void QXcbWindow::updateSyncRequestCounter()
diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp
index 65aca42cd3..aef8f5ae58 100644
--- a/src/widgets/kernel/qapplication_qpa.cpp
+++ b/src/widgets/kernel/qapplication_qpa.cpp
@@ -161,6 +161,8 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
Q_UNUSED(previous);
Q_Q(QApplication);
QWindow *wnd = QGuiApplicationPrivate::active_window;
+ if (inPopupMode()) // some delayed focus event to ignore
+ return;
QWidget *tlw = qt_tlw_for_window(wnd);
q->setActiveWindow(tlw);
}