aboutsummaryrefslogtreecommitdiff
path: root/src/gui/kwindowstatesaver.cpp
diff options
context:
space:
mode:
authorVolker Krause <vkrause@kde.org>2022-02-14 18:12:24 +0100
committerVolker Krause <vkrause@kde.org>2022-02-24 16:43:05 +0000
commitf446af2aa592997f6bc4aa3b5559cf477f9259f8 (patch)
tree884ce1c859da42351fd9b286680d5d15e916b6d8 /src/gui/kwindowstatesaver.cpp
parent1067eed52a8a1a93581744a5c9d4fc9f8a7d3661 (diff)
downloadkconfig-f446af2aa592997f6bc4aa3b5559cf477f9259f8.tar.gz
kconfig-f446af2aa592997f6bc4aa3b5559cf477f9259f8.tar.bz2
Add KWindowStateSaver
This is basically the C++ counter-part to https://invent.kde.org/frameworks/kconfig/-/merge_requests/94 and allows to easily retrofit window size persistence on existing windows/ dialogs, replacing e.g. code like https://invent.kde.org/pim/pimcommon/-/blob/master/src/pimcommon/widgets/kpimprintpreviewdialog.cpp. This is a bit more complicated than one might expect, as KWindowConfig works with QWindows, but that's something freshly created QWidget windows/ dialogs don't have yet. Additionally, we are in a library here that doesn't depend on Qt::Widgets. To overcome this we move the widget-dependent code (basically just a call to QWidget::windowHandle()) to inline template code (and thus into the consumer), use std::function's type erasure to pass it into the library code, and an event filter on the widget to wait for the QWindow to become available.
Diffstat (limited to 'src/gui/kwindowstatesaver.cpp')
-rw-r--r--src/gui/kwindowstatesaver.cpp136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/gui/kwindowstatesaver.cpp b/src/gui/kwindowstatesaver.cpp
new file mode 100644
index 00000000..d3eaa99e
--- /dev/null
+++ b/src/gui/kwindowstatesaver.cpp
@@ -0,0 +1,136 @@
+/*
+ SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org>
+ SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kwindowstatesaver.h"
+#include "ksharedconfig.h"
+#include "kwindowconfig.h"
+
+#include <QWindow>
+
+class KWindowStateSaverPrivate
+{
+public:
+ QWindow *window = nullptr;
+ KConfigGroup configGroup;
+ std::function<QWindow *()> windowHandleCallback;
+ int timerId = 0;
+
+ void init(KWindowStateSaver *q);
+ void initWidget(QObject *widget, KWindowStateSaver *q);
+};
+
+void KWindowStateSaverPrivate::init(KWindowStateSaver *q)
+{
+ if (!window) {
+ return;
+ }
+
+ KWindowConfig::restoreWindowSize(window, configGroup);
+ KWindowConfig::restoreWindowPosition(window, configGroup);
+
+ const auto deferredSave = [q, this]() {
+ if (!timerId) {
+ timerId = q->startTimer(250);
+ }
+ };
+ QObject::connect(window, &QWindow::widthChanged, q, deferredSave);
+ QObject::connect(window, &QWindow::heightChanged, q, deferredSave);
+ QObject::connect(window, &QWindow::xChanged, q, deferredSave);
+ QObject::connect(window, &QWindow::yChanged, q, deferredSave);
+}
+
+void KWindowStateSaverPrivate::initWidget(QObject *widget, KWindowStateSaver *q)
+{
+ if (!window && windowHandleCallback) {
+ window = windowHandleCallback();
+ }
+ if (window) {
+ init(q);
+ } else {
+ widget->installEventFilter(q);
+ }
+}
+
+KWindowStateSaver::KWindowStateSaver(QWindow *window, const KConfigGroup &configGroup)
+ : QObject(window)
+ , d(new KWindowStateSaverPrivate)
+{
+ Q_ASSERT(window);
+ d->window = window;
+ d->configGroup = configGroup;
+ d->init(this);
+}
+
+KWindowStateSaver::KWindowStateSaver(QWindow *window, const QString &configGroupName)
+ : QObject(window)
+ , d(new KWindowStateSaverPrivate)
+{
+ Q_ASSERT(window);
+ d->window = window;
+ d->configGroup = KConfigGroup(KSharedConfig::openStateConfig(), configGroupName);
+ d->init(this);
+}
+
+KWindowStateSaver::KWindowStateSaver(QWindow *window, const char *configGroupName)
+ : QObject(window)
+ , d(new KWindowStateSaverPrivate)
+{
+ Q_ASSERT(window);
+ d->window = window;
+ d->configGroup = KConfigGroup(KSharedConfig::openStateConfig(), configGroupName);
+ d->init(this);
+}
+
+KWindowStateSaver::~KWindowStateSaver()
+{
+ delete d;
+}
+
+void KWindowStateSaver::timerEvent(QTimerEvent *event)
+{
+ killTimer(event->timerId());
+ KWindowConfig::saveWindowPosition(d->window, d->configGroup);
+ KWindowConfig::saveWindowSize(d->window, d->configGroup);
+ d->timerId = 0;
+}
+
+bool KWindowStateSaver::eventFilter(QObject *watched, QEvent *event)
+{
+ // QEvent::PlatformSurface would give us a valid window, but if there are
+ // intial resizings (explicitly or via layout constraints) those would then
+ // already overwrite our restored values. So wait until all that is done
+ // and only restore afterwards.
+ if (event->type() == QEvent::ShowToParent && !d->window) {
+ watched->removeEventFilter(this);
+ d->window = d->windowHandleCallback();
+ d->init(this);
+ }
+
+ return QObject::eventFilter(watched, event);
+}
+
+void KWindowStateSaver::initWidget(QObject *widget, const std::function<QWindow *()> &windowHandleCallback, const KConfigGroup &configGroup)
+{
+ d = new KWindowStateSaverPrivate;
+ d->windowHandleCallback = windowHandleCallback;
+ d->configGroup = configGroup;
+ d->initWidget(widget, this);
+}
+
+void KWindowStateSaver::initWidget(QObject *widget, const std::function<QWindow *()> &windowHandleCallback, const QString &configGroupName)
+{
+ d = new KWindowStateSaverPrivate;
+ d->windowHandleCallback = windowHandleCallback;
+ d->configGroup = KConfigGroup(KSharedConfig::openStateConfig(), configGroupName);
+ d->initWidget(widget, this);
+}
+
+void KWindowStateSaver::initWidget(QObject *widget, const std::function<QWindow *()> &windowHandleCallback, const char *configGroupName)
+{
+ d = new KWindowStateSaverPrivate;
+ d->windowHandleCallback = windowHandleCallback;
+ d->configGroup = KConfigGroup(KSharedConfig::openStateConfig(), configGroupName);
+ d->initWidget(widget, this);
+}