Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-82342

X11: QWidget::windowState() ends up at rest out of sync with reality

    XMLWordPrintable

Details

    • Bug
    • Resolution: Duplicate
    • P2: Important
    • None
    • 5.13.2
    • QPA: X11/XCB
    • None
    • Linux/X11

    Description

      It is possible, with a quick succession of window state changes, for a Qt program to end up in a situation where (QWidget::windowState() & Qt::WindowMinized) == true even though the native window is not minimized. The following sample reproduces the problem with gnome (mutter):

      // Build. g++ -std=c++17 -Wall -Wextra -g -fPIC $(pkg-config --cflags --libs Qt5Core  Qt5Gui Qt5Widgets) -o example example.cc
      #include <iostream>
      #include <QApplication>
      #include <QLabel>
      #include <QTimer>
      
      int main(int argc, char **argv)
      {
          QApplication app(argc, argv);
          QLabel w(QLatin1String("Hello world"));
          w.show();
          QTimer::singleShot(1000, [&] {
              w.setWindowState(w.windowState() | Qt::WindowMinimized);
              w.activateWindow();
          });
          QTimer::singleShot(3000, [&] {
              std::cout << "Window state: " << w.windowState() << std::endl;
              app.quit();
          });
          return app.exec();
      }
      
      

      The program above shows a window with the text "Hello world". After a second it will minimize and then immediately activate the window causing it to not be minimized again. After three seconds it prints the window state and quits. With gnome/mutter this prints "Window state: 1" (minimized) which is incorrect. It should print "Window state: 0".

      I have also been able to reproduce the problem with metacity, though not as easily or reliably.

      While the example above is synthetic I have observed this problem in a real application.

      The problem is that w.setWindowState(w.windowState() | Qt::WindowMinimized); will update QWidget::windowState() directly and then effect the change via the platform QXcbWindow. QWidget::activateWindow() only affects the change via the platform QxcbWindow and relies on property notify events caused by the window manager updating WM_STATE and _NET_WM_STATE to feed the updated window state back to Qt. The problem is that QXcbWindow::handlePropertyNotifyEvent() ignores the updates because it determines that the new state reported is the same as the last update it reported by comparing it to QXcbWindow::m_lastWindowStateEvent.

      I believe what goes wrong here is that if window state changes happen fast enough the window manager has changed the WM_STATE/_NET_WM_STATE to minimized and back to unminimized before QXcbWindow::handlePropertyNotifyEvent() runs, which means that from QXcbWindow's point of view there is nothing new to report and we never clear the Qt::WindowMinimized bit that was set directly by QWidget::setWindowState().

      Attachments

        Issue Links

          Activity

            People

              liaqi Liang Qi
              ts Thomas Sondergaard
              Votes:
              1 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: