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

REGRESSION: QPalette::setBrush does not reliably detach

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P1: Critical
    • 6.2.3, 6.3.0 Alpha
    • 6.0.0, 6.1.0, 6.2.0
    • GUI: Painting
    • None
    • All
    • 56bd1b76d2e81c58a80bf6b5d74219c6b1ab8499 (qt/qtbase/dev) 3bf23b71188e719b1eee4408b8d2a354901dbeae (qt/qtbase/6.2) 9334e06bdf (qt/qtbase/6.3) 9334e06bdf (qt/tqtc-qtbase/6.3) bd27707c20 (qt/tqtc-qtbase/6.2)

    Description

      Calling Palette::setBrush() with a brush for a role that is identical to the existing brush, will not detach the QPalettePrivate but it will change the resolve mask. Since QPalettePrivate is shared, this affects the resolve mask of all QPalette instances - in particular QGuiApplicationPrivate::app_pal.

      Check out the following patch to the calculator:

      diff --git a/examples/widgets/widgets/calculator/calculator.cpp b/examples/widgets/widgets/calculator/calculator.cpp
      index 2c3669b7a8..691a4771ff 100644
      --- a/examples/widgets/widgets/calculator/calculator.cpp
      +++ b/examples/widgets/widgets/calculator/calculator.cpp
      @@ -54,6 +54,7 @@
       #include <QGridLayout>
       #include <QLineEdit>
       #include <QtMath>
      +#include <QEvent>
       
       //! [0]
       Calculator::Calculator(QWidget *parent)
      @@ -140,6 +141,14 @@ Calculator::Calculator(QWidget *parent)
       }
       //! [6]
       
      +bool Calculator::event(QEvent *e)
      +{
      +    if (e->type() == QEvent::PaletteChange) {
      +        qDebug() << "palette changed. background" << palette().brush(QPalette::Window).color().rgba();
      +    }
      +    QWidget::event(e);
      +}
      +
       //! [7]
       void Calculator::digitClicked()
       {
      diff --git a/examples/widgets/widgets/calculator/calculator.h b/examples/widgets/widgets/calculator/calculator.h
      index 937de185e7..5082b32ef7 100644
      --- a/examples/widgets/widgets/calculator/calculator.h
      +++ b/examples/widgets/widgets/calculator/calculator.h
      @@ -66,6 +66,7 @@ class Calculator : public QWidget
       public:
           Calculator(QWidget *parent = nullptr);
       
      +    bool event(QEvent *) override;
       private slots:
           void digitClicked();
           void unaryOperatorClicked();
      diff --git a/examples/widgets/widgets/calculator/main.cpp b/examples/widgets/widgets/calculator/main.cpp
      index a034bb262e..cbfad39331 100644
      --- a/examples/widgets/widgets/calculator/main.cpp
      +++ b/examples/widgets/widgets/calculator/main.cpp
      @@ -56,6 +56,12 @@ int main(int argc, char *argv[])
       {
           QApplication app(argc, argv);
           Calculator calc;
      +    QPalette p = calc.palette();
      +    auto foo = p.brush(QPalette::Window);
      +    // This changes QGuiApplication::app_pal because
      +    // setBrush() does not detach (brush is the same as set),
      +    // BUT it changes the resolve mask.
      +    p.setBrush(QPalette::Window, foo);
           calc.show();
           return app.exec();
       }
      

      If you run this for example on macOS and change the system appearance from dark to light (or vice-versa), you'll notice that the debug output does not show the new value.

      This used to work in Qt 5 because the resolve mask was part of QPalette itself, not the shared private. But commit 556511f9f39ddc887481e0cd5a877134ceb0da6b regressed this - there is a detach() call missing in setBrush() IMO.

      Attachments

        Issue Links

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

          Activity

            People

              vhilshei Volker Hilsheimer
              shausman Simon Hausmann
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: