diff options
author | Volker Krause <vkrause@kde.org> | 2022-02-14 18:12:24 +0100 |
---|---|---|
committer | Volker Krause <vkrause@kde.org> | 2022-02-24 16:43:05 +0000 |
commit | f446af2aa592997f6bc4aa3b5559cf477f9259f8 (patch) | |
tree | 884ce1c859da42351fd9b286680d5d15e916b6d8 /src/gui/kwindowstatesaver.cpp | |
parent | 1067eed52a8a1a93581744a5c9d4fc9f8a7d3661 (diff) | |
download | kconfig-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.cpp | 136 |
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); +} |