Hi everyone,
I use QMainWindow::restoreGeometry and restoreState, fed with QByteArray's from QSettings to restore the arrangement of QDockWidegt's. It works great when all docks are saved in docked state. If a dock was saved floating and is thus restored floating strange things happen: On the first glance everything looks OK (position and state), but the floating window(s) behave strange:
  1. If you have more than one floating dock their relative stacking is unpredictable and does not follow mouse clicks on the dock title bar (thus window activation or raise commands).
  2. A floating dock may be in front of _any_ other window on the screen. Yes, even in front of other applications. No way to get it into background.
  3. Resizing of the dock does not work. After moving it, resize works. (but not the stacking)

The faulty dockwindows can be healed by docking and undocking them.
Seen on Ubuntu 20.04.3 LTS, GNOME 3.36.8, Qt 5.15. I can reproduce this behavior in a skeleton application, source at the end of this post.

I think that it should work to call restoreGeometry and restoreState before creating the docks and using restoreDockWidget later on - what else would be the use of restoreDockWidget? Still, I turned it around, which means create the docks and call restoreGeometry and restoreState afterwards (and no restoreDockWidget at all). Surprise, surprise, the stacking order is fine, resize is possible! So, problem solved? Well, not completely. The problem is that I have no possibility to find out which docks were restored and which not. Sure, i can call addDockWidget (with some default position) for all docks right after creation. The saved ones will be re-positioned later on. (For example, docks may not be saved because this is the first start of the program or the user added a plugin which creates a hitherto unknown dock.) But I would like to know which docks are "new"... Btw, just omitting addDockWidget is a bad idea - un-saved docks will have no valid layout and are rendered somehow overlapping the central widget.

So my question: Is the strange stacking behavior really a bug or is something wrong with my code?


Qt Code:
  1. #include "mainwindow.h"
  2. #include <QApplication>
  3. int main(int argc, char *argv[])
  4. {
  5. QCoreApplication::setOrganizationName("me");
  6. QCoreApplication::setOrganizationDomain("mydomain.at");
  7. QCoreApplication::setApplicationName("MainWinTest");
  8. QApplication a(argc, argv);
  9. MainWindow w;
  10. w.show();
  11. return a.exec();
  12. }
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. QT_BEGIN_NAMESPACE
  5. namespace Ui { class MainWindow; }
  6. QT_END_NAMESPACE
  7. class MainWindow : public QMainWindow
  8. {
  9. Q_OBJECT
  10. public:
  11. MainWindow(QWidget *parent = nullptr);
  12. ~MainWindow();
  13. protected:
  14. virtual void closeEvent(QCloseEvent *event);
  15. private:
  16. void createDock(QString name);
  17. Ui::MainWindow *ui;
  18. };
  19. #endif // MAINWINDOW_H
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include <QtDebug>
  4. #include <QDockWidget>
  5. #include <QLabel>
  6. #include <QSettings>
  7.  
  8. MainWindow::MainWindow(QWidget *parent)
  9. : QMainWindow(parent)
  10. , ui(new Ui::MainWindow)
  11. {
  12. qInfo()<<"setup MainWindow";
  13. ui->setupUi(this);
  14.  
  15. qInfo()<<"restore";
  16. QSettings settings;
  17. if(!restoreGeometry(settings.value("layout/geometry").toByteArray()))
  18. qWarning()<<"unable to restore geometry";
  19. if(!restoreState(settings.value("layout/windowState").toByteArray()))
  20. qWarning()<<"unable to restore state";
  21.  
  22. qInfo()<<"dynamic widgets";
  23. setCentralWidget(new QLabel(QStringLiteral("central"), this));
  24. createDock(QStringLiteral("Dock1"));
  25. createDock(QStringLiteral("Dock2"));
  26. createDock(QStringLiteral("Dock3"));
  27. }
  28.  
  29. MainWindow::~MainWindow()
  30. {
  31. delete ui;
  32. }
  33.  
  34. void MainWindow::closeEvent(QCloseEvent *event)
  35. {
  36. qInfo()<<"save";
  37. QSettings settings;
  38. settings.setValue("layout/geometry", saveGeometry());
  39. settings.setValue("layout/windowState", saveState());
  40. qInfo()<<"closing MainWindow";
  41. QMainWindow::closeEvent(event);
  42. }
  43.  
  44. void MainWindow::createDock(QString name)
  45. {
  46. QDockWidget *dock = new QDockWidget(name, this);
  47. dock->setObjectName(name);
  48. dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea);
  49. dock->setStyleSheet("QDockWidget{border: 4px solid #d00000} QDockWidget::title{background: #ffd8c0}");
  50. dock->setWidget(new QLabel(name, dock));
  51. if(restoreDockWidget(dock))
  52. qInfo()<<"restored layout of"<<name;
  53. else
  54. {
  55. qWarning()<<"unable to restore layout of"<<name;
  56. addDockWidget(Qt::RightDockWidgetArea, dock);
  57. }
  58. }
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. QT += core gui
  2. greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  3. CONFIG += c++11
  4. SOURCES += \
  5. main.cpp \
  6. mainwindow.cpp
  7.  
  8. HEADERS += \
  9. mainwindow.h
  10.  
  11. FORMS += \
  12. mainwindow.ui
  13.  
  14. # Default rules for deployment.
  15. qnx: target.path = /tmp/$${TARGET}/bin
  16. else: unix:!android: target.path = /opt/$${TARGET}/bin
  17. !isEmpty(target.path): INSTALLS += target
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ui version="4.0">
  3. <class>MainWindow</class>
  4. <widget class="QMainWindow" name="MainWindow">
  5. <property name="geometry">
  6. <rect>
  7. <x>0</x>
  8. <y>0</y>
  9. <width>800</width>
  10. <height>600</height>
  11. </rect>
  12. </property>
  13. <property name="windowTitle">
  14. <string>MainWindow</string>
  15. </property>
  16. <widget class="QWidget" name="centralwidget">
  17. <layout class="QHBoxLayout" name="horizontalLayout">
  18. <item>
  19. <widget class="QLabel" name="label">
  20. <property name="text">
  21. <string>central wid</string>
  22. </property>
  23. <property name="alignment">
  24. <set>Qt::AlignCenter</set>
  25. </property>
  26. </widget>
  27. </item>
  28. </layout>
  29. </widget>
  30. <widget class="QMenuBar" name="menubar">
  31. <property name="geometry">
  32. <rect>
  33. <x>0</x>
  34. <y>0</y>
  35. <width>800</width>
  36. <height>22</height>
  37. </rect>
  38. </property>
  39. </widget>
  40. <widget class="QStatusBar" name="statusbar"/>
  41. </widget>
  42. <resources/>
  43. <connections/>
  44. </ui>
To copy to clipboard, switch view to plain text mode