Avoid setting the active window to null when there is a FocusIn queued.

This commit is contained in:
Laszlo Agocs 2011-06-06 10:02:06 +02:00
parent 4f1a6ac732
commit 78264f333e
4 changed files with 42 additions and 1 deletions

View File

@ -483,6 +483,11 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
printXcbEvent("Unhandled XCB event", event); printXcbEvent("Unhandled XCB event", event);
} }
void QXcbConnection::addPeekFunc(PeekFunc f)
{
m_peekFuncs.append(f);
}
void QXcbConnection::processXcbEvents() void QXcbConnection::processXcbEvents()
{ {
while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection()))
@ -498,6 +503,15 @@ void QXcbConnection::processXcbEvents()
if (!response_type) { if (!response_type) {
handleXcbError((xcb_generic_error_t *)event); handleXcbError((xcb_generic_error_t *)event);
} else { } 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); handleXcbEvent(event);
} }
@ -506,6 +520,12 @@ void QXcbConnection::processXcbEvents()
eventqueue.clear(); 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()); xcb_flush(xcb_connection());
} }

View File

@ -284,6 +284,9 @@ public:
QXcbWindow *platformWindowFromId(xcb_window_t id); QXcbWindow *platformWindowFromId(xcb_window_t id);
typedef bool (*PeekFunc)(xcb_generic_event_t *);
void addPeekFunc(PeekFunc f);
private slots: private slots:
void processXcbEvents(); void processXcbEvents();
@ -335,6 +338,8 @@ private:
QVector<xcb_generic_event_t *> eventqueue; QVector<xcb_generic_event_t *> eventqueue;
WindowMapper m_mapper; WindowMapper m_mapper;
QVector<PeekFunc> m_peekFuncs;
}; };
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))

View File

@ -1087,9 +1087,23 @@ void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
QWindowSystemInterface::handleWindowActivated(window()); 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 *) 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() void QXcbWindow::updateSyncRequestCounter()

View File

@ -161,6 +161,8 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
Q_UNUSED(previous); Q_UNUSED(previous);
Q_Q(QApplication); Q_Q(QApplication);
QWindow *wnd = QGuiApplicationPrivate::active_window; QWindow *wnd = QGuiApplicationPrivate::active_window;
if (inPopupMode()) // some delayed focus event to ignore
return;
QWidget *tlw = qt_tlw_for_window(wnd); QWidget *tlw = qt_tlw_for_window(wnd);
q->setActiveWindow(tlw); q->setActiveWindow(tlw);
} }