Prevent XSetInputFocus BadMatch errors.
authorSamuel Rødal <samuel.rodal@nokia.com>
Wed, 1 Jun 2011 11:02:57 +0000 (13:02 +0200)
committerSamuel Rødal <samuel.rodal@nokia.com>
Wed, 1 Jun 2011 11:37:44 +0000 (13:37 +0200)
The BadMatch errors are generated if XSetInputFocus is called before the
window has been mapped, so we need to set a flag when we get the map
notify event.

src/plugins/platforms/xcb/qxcbconnection.cpp
src/plugins/platforms/xcb/qxcbwindow.cpp
src/plugins/platforms/xcb/qxcbwindow.h
tests/auto/qwidget/tst_qwidget.cpp

index 89b5072..5b0d9d8 100644 (file)
@@ -442,6 +442,8 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
         HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
     case XCB_CONFIGURE_NOTIFY:
         HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
+    case XCB_MAP_NOTIFY:
+        HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent);
     case XCB_CLIENT_MESSAGE:
         HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent);
     case XCB_ENTER_NOTIFY:
index d46e140..e4f4fd7 100644 (file)
@@ -94,6 +94,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
     , m_window(0)
     , m_context(0)
     , m_syncCounter(0)
+    , m_mapped(false)
 {
     m_screen = static_cast<QXcbScreen *>(QGuiApplicationPrivate::platformIntegration()->screens().at(0));
 
@@ -278,6 +279,7 @@ void QXcbWindow::destroy()
         connection()->removeWindow(m_window);
         Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
     }
+    m_mapped = false;
 }
 
 void QXcbWindow::setGeometry(const QRect &rect)
@@ -367,6 +369,8 @@ void QXcbWindow::hide()
                               XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
 
     xcb_flush(xcb_connection());
+
+    m_mapped = false;
 }
 
 struct QtMotifWmHints {
@@ -877,8 +881,10 @@ void QXcbWindow::propagateSizeHints()
 
 void QXcbWindow::requestActivateWindow()
 {
-    Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME));
-    connection()->sync();
+    if (m_mapped){
+        Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME));
+        connection()->sync();
+    }
 }
 
 QPlatformGLContext *QXcbWindow::glContext() const
@@ -968,6 +974,12 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
 #endif
 }
 
+void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
+{
+    if (event->window == m_window)
+        m_mapped = true;
+}
+
 static Qt::MouseButtons translateMouseButtons(int s)
 {
     Qt::MouseButtons ret = 0;
index 2260832..40d21f4 100644 (file)
@@ -83,6 +83,7 @@ public:
     void handleExposeEvent(const xcb_expose_event_t *event);
     void handleClientMessageEvent(const xcb_client_message_event_t *event);
     void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event);
+    void handleMapNotifyEvent(const xcb_map_notify_event_t *event);
     void handleButtonPressEvent(const xcb_button_press_event_t *event);
     void handleButtonReleaseEvent(const xcb_button_release_event_t *event);
     void handleMotionNotifyEvent(const xcb_motion_notify_event_t *event);
@@ -127,6 +128,8 @@ private:
 
     bool m_hasReceivedSyncRequest;
     Qt::WindowState m_windowState;
+
+    bool m_mapped;
 };
 
 #endif
index 7c0042a..1d3591d 100644 (file)
@@ -10226,18 +10226,26 @@ void tst_QWidget::nativeChildFocus()
     QLineEdit *p2 = new QLineEdit;
     layout->addWidget(p1);
     layout->addWidget(p2);
+#if 1
     p1->setObjectName("p1");
     p2->setObjectName("p2");
+#endif
     w.show();
+#if 1
     w.activateWindow();
     p1->setFocus();
     p1->setAttribute(Qt::WA_NativeWindow);
     p2->setAttribute(Qt::WA_NativeWindow);
     QApplication::processEvents();
     QTest::qWaitForWindowShown(&w);
+    QTest::qWait(10);
 
+    qDebug() << "checking active window:" << QApplication::activeWindow();
     QCOMPARE(QApplication::activeWindow(), &w);
     QCOMPARE(QApplication::focusWidget(), static_cast<QWidget*>(p1));
+#endif
+
+    QTest::qWait(1000);
 }
 
 QTEST_MAIN(tst_QWidget)