From e6ea00dce8c74bf0d48e769734958a741ca46ef9 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 3 Aug 2026 16:00:38 +0200 Subject: feat: persist window, splitter and column widths Resizing the window, the splitter or a thread-list column was undone by the next launch. State now round-trips through a separate settings file at ~/.local/state/qtmaildir/uistate.conf, written on close and read at startup. The state file is deliberately not the user's config: a base64 geometry blob does not belong in a hand-edited file, and rewriting that file on exit would drop its comments and key order, which QSettings does not preserve. Two details that are easy to get wrong: QStandardPaths::StateLocation appends both the organization and the application name, and both are "qtmaildir" here, so it resolves to ~/.local/state/qtmaildir/qtmaildir. The path is built from GenericStateLocation instead, matching Config::defaultPath(). Restore runs after buildMenus() rather than at the end of buildUi(): QMainWindow::restoreState() matches toolbars by object name and silently drops the position of one that does not exist yet. Every restore is conditional on a non-empty blob, so a missing or rejected state file leaves the built-in defaults instead of producing a zero-size window. Co-Authored-By: Claude Opus 5 --- src/mainwindow.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/mainwindow.h') diff --git a/src/mainwindow.h b/src/mainwindow.h index 4445894..f4186ff 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -38,6 +38,7 @@ class QLabel; class QPushButton; class QComboBox; class QPlainTextEdit; +class QSplitter; class ThreadListModel; class MessageView; @@ -63,6 +64,15 @@ public: /// cid: references from resolving to another's. static QString cidPrefixForIndex(int index); + /// Path of the machine-written UI state file. Deliberately not + /// Config::defaultPath(): the config is hand-edited and must never gain a + /// base64 geometry blob, nor be rewritten on exit (QSettings does not + /// preserve comments or key order). + static QString uiStatePath(); + +protected: + void closeEvent(QCloseEvent *event) override; + private slots: void runCurrentQuery(); void onThreadsReady(const QVector &threads, quint64 generation); @@ -74,6 +84,12 @@ private slots: private: void buildUi(); + + /// Restores window geometry, splitter and thread-list header widths. + /// A missing or rejected blob leaves the buildUi() defaults in place. + void restoreUiState(); + void saveUiState() const; + void registerActions(); void buildMenus(); void wireWorker(); @@ -116,6 +132,7 @@ private: QLineEdit *m_queryEdit = nullptr; QTableView *m_threadView = nullptr; + QSplitter *m_splitter = nullptr; QComboBox *m_accountBox = nullptr; QPushButton *m_syncButton = nullptr; QLabel *m_statusLabel = nullptr; -- cgit v1.2.3