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

QWindowPrivate::setVisible does not appropriately handle recursive calls to itself

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 5.14.1, 5.15.2
    • QPA
    • None
    • All

    Description

      QWindowPrivate::setVisible emits a visibleChanged signal before actually applying the changes on the window. This means that if an application has a signal handler that calls QWindow::setVisible, it will be called recursively.

      void QWindowPrivate::setVisible(bool visible)
      {
          Q_Q(QWindow);
          if (this->visible != visible) {
              this->visible = visible;
              emit q->visibleChanged(visible); // <--- may cause recursive calls
              updateVisibility();
          } else if (platformWindow) {
              // Visibility hasn't changed, and the platform window is in sync
              return;
          }
          // ...  lots of code that uses the stack variable "visible", which may be different from "this->visible"
      

      This means that if the platformWindow is not yet created, or if the value of visible is different from the outer call, the recursive call will do the actual work, and then it will be redone or even partially reverted (if called with different values) once the stack is popped and the initial call resumes.

      Qml app to trigger some of the possible issues:

      import QtQuick 2.6
      import QtQuick.Window 2.2
      import QtQuick.Controls 2.14
      
      Window {
          id: window
          visible: true
          property int signalsReceived: 0
          property bool buttonClicked: false
          onVisibleChanged: {
              // We want to skip the initial events when the app is just starting up
              if (!buttonClicked) {
                  return;
              }
              ++signalsReceived;
              console.log(`Signal ${signalsReceived}: visible changed to ${visible}`);
              if (signalsReceived === 1) { // only do it on the first signal
                  console.log("setting visible to true in signal handler");
                  visible = true;
              }
          }
          Column {
              Button {
                  text: "Trigger bugs?"
                  onClicked: {
                      buttonClicked = true;
                      window.visible = false;
                  }
              }
              Text { text: `Visible: ${visible}` }
          }
      }
      

      On xcb, this causes a crash:

      qml: Signal 1: visible changed to false
      qml: setting visible to true in signal handler
      qml: Signal 2: visible changed to true
      qt.qpa.xcb: internal error:  void QXcbWindow::setNetWmStateOnUnmappedWindow() called on mapped window
      

      And on Wayland as well:

      QSocketNotifier: Can only be used with threads started with QThread
      qml: Signal 1: visible changed to false
      qml: setting visible to true in signal handler
      qml: Signal 2: visible changed to true
      [destroyed object]: error 0: xdg_wm_base::get_xdg_surface already requested
      The Wayland connection experienced a fatal error: Protocol error
      fish: “qml visibility-bug.qml -platfor…” terminated by signal SIGABRT (Abort)
      

      There are less obscure cases that are affected by this as well, i.e. the following causes a crash on startup on Wayland:

      import QtQuick 2.6
      import QtQuick.Window 2.2
      import QtQuick.Controls 2.14
      
      Window {
          id: window
          visible: true
          CheckBox {
              text: "Window visible"
              checked: window.visible
              onCheckedChanged: window.visible = checked
          }
      }
      
      QSocketNotifier: Can only be used with threads started with QThread
      wl_surface@20: error 0: xdg_wm_base::get_xdg_surface already requested
      The Wayland connection experienced a fatal error: Protocol error
      fish: “qml visibility-bug-2.qml -platf…” terminated by signal SIGABRT (Abort)
      

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              vestbo Tor Arne Vestbø
              johanhelsing Johan Helsing
              Veli-Pekka Heinonen Veli-Pekka Heinonen
              Votes:
              3 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

                Created:
                Updated:

                Gerrit Reviews

                  There are no open Gerrit changes