KConfig

kwindowconfig.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2012 Benjamin Port <benjamin.port@ben2367.fr>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include "kwindowconfig.h"
9#include "ksharedconfig.h"
10
11#include <QGuiApplication>
12#include <QScreen>
13#include <QWindow>
14
15static const char s_initialSizePropertyName[] = "_kconfig_initial_size";
16static const char s_initialScreenSizePropertyName[] = "_kconfig_initial_screen_size";
17
18// Convenience function to get a space-separated list of all connected screens
19static QString allConnectedScreens()
20{
21 QStringList names;
22 const auto screens = QGuiApplication::screens();
23 names.reserve(screens.length());
24 for (auto screen : screens) {
25 names << screen->name();
26 }
27 // A string including the connector names is used in the config file key for
28 // storing per-screen-arrangement size and position data, which means we
29 // need this string to be consistent for the same screen arrangement. But
30 // connector order is non-deterministic. We need to sort the list to keep a
31 // consistent order and avoid losing multi-screen size and position data.
32 names.sort();
33 return names.join(QLatin1Char(' '));
34}
35
36// Convenience function to return screen by its name from window screen siblings
37// returns current window screen if not found
38static QScreen *findScreenByName(const QWindow *window, const QString screenName)
39{
40 if (screenName == window->screen()->name()) {
41 return window->screen();
42 }
43 for (QScreen *s : window->screen()->virtualSiblings()) {
44 if (s->name() == screenName) {
45 return s;
46 }
47 }
48 return window->screen();
49}
50
51// Convenience function to get an appropriate config file key under which to
52// save window size, position, or maximization information.
53static QString configFileString(const QString &key)
54{
55 QString returnString;
56 const int numberOfScreens = QGuiApplication::screens().length();
57
58 if (numberOfScreens == 1) {
59 // For single-screen setups, we save data on a per-resolution basis.
60 const QRect screenGeometry = QGuiApplication::primaryScreen()->geometry();
61 returnString = QStringLiteral("%1x%2 screen: %3").arg(QString::number(screenGeometry.width()), QString::number(screenGeometry.height()), key);
62 } else {
63 // For multi-screen setups, we save data based on the number of screens.
64 // Distinguishing individual screens based on their names is unreliable
65 // due to name strings being inherently volatile.
66 returnString = QStringLiteral("%1 screens: %2").arg(QString::number(numberOfScreens), key);
67 }
68 return returnString;
69}
70
71// Convenience function for "window is maximized" string
72static QString screenMaximizedString()
73{
74 return configFileString(QStringLiteral("Window-Maximized"));
75}
76// Convenience function for window width string
77static QString windowWidthString()
78{
79 return configFileString(QStringLiteral("Width"));
80}
81// Convenience function for window height string
82static QString windowHeightString()
83{
84 return configFileString(QStringLiteral("Height"));
85}
86// Convenience function for window X position string
87static QString windowXPositionString()
88{
89 return configFileString(QStringLiteral("XPosition"));
90}
91// Convenience function for window Y position string
92static QString windowYPositionString()
93{
94 return configFileString(QStringLiteral("YPosition"));
95}
96static QString windowScreenPositionString()
97{
98 return QStringLiteral("%1").arg(allConnectedScreens());
99}
100
102{
103 // QWindow::screen() shouldn't return null, but it sometimes does due to bugs.
104 if (!window || !window->screen()) {
105 return;
106 }
107 const QScreen *screen = window->screen();
108
109 const QSize sizeToSave = window->size();
110 const bool isMaximized = window->windowState() & Qt::WindowMaximized;
111
112 // Save size only if window is not maximized
113 if (!isMaximized) {
114 const QSize defaultSize(window->property(s_initialSizePropertyName).toSize());
115 const QSize defaultScreenSize(window->property(s_initialScreenSizePropertyName).toSize());
116 const bool sizeValid = defaultSize.isValid() && defaultScreenSize.isValid();
117 if (!sizeValid || (sizeValid && (defaultSize != sizeToSave || defaultScreenSize != screen->geometry().size()))) {
118 config.writeEntry(windowWidthString(), sizeToSave.width(), options);
119 config.writeEntry(windowHeightString(), sizeToSave.height(), options);
120 // Don't keep the maximized string in the file since the window is
121 // no longer maximized at this point
122 config.deleteEntry(screenMaximizedString());
123 }
124 }
125 if ((isMaximized == false) && !config.hasDefault(screenMaximizedString())) {
126 config.revertToDefault(screenMaximizedString());
127 } else {
128 config.writeEntry(screenMaximizedString(), isMaximized, options);
129 }
130}
131
133{
134 return config.hasKey(windowWidthString()) || config.hasKey(windowHeightString()) || config.hasKey(screenMaximizedString());
135}
136
138{
139 if (!window) {
140 return;
141 }
142
143 const QString screenName = config.readEntry(windowScreenPositionString(), window->screen()->name());
144
145 const int width = config.readEntry(windowWidthString(), -1);
146 const int height = config.readEntry(windowHeightString(), -1);
147 const bool isMaximized = config.readEntry(configFileString(QStringLiteral("Window-Maximized")), false);
148
149 // Check default size
150 const QSize defaultSize(window->property(s_initialSizePropertyName).toSize());
151 const QSize defaultScreenSize(window->property(s_initialScreenSizePropertyName).toSize());
152 if (!defaultSize.isValid() || !defaultScreenSize.isValid()) {
153 const QScreen *screen = findScreenByName(window, screenName);
154 window->setProperty(s_initialSizePropertyName, window->size());
155 window->setProperty(s_initialScreenSizePropertyName, screen->geometry().size());
156 }
157
158 if (width > 0 && height > 0) {
159 window->resize(width, height);
160 }
161
162 if (isMaximized) {
164 }
165}
166
168{
169 // On Wayland, the compositor is solely responsible for window positioning,
170 // So this needs to be a no-op
171 if (!window || QGuiApplication::platformName() == QLatin1String{"wayland"}) {
172 return;
173 }
174
175 // If the window is maximized, saving the position will only serve to mis-position
176 // it once de-maximized, so let's not do that
177 if (window->windowState() & Qt::WindowMaximized) {
178 return;
179 }
180
181 config.writeEntry(windowXPositionString(), window->x(), options);
182 config.writeEntry(windowYPositionString(), window->y(), options);
183 config.writeEntry(windowScreenPositionString(), window->screen()->name(), options);
184}
185
187{
188 // Window position save/restore features outside of the compositor are not
189 // supported on Wayland
190 if (QGuiApplication::platformName() == QLatin1String{"wayland"}) {
191 return false;
192 }
193
194 return config.hasKey(windowXPositionString()) || config.hasKey(windowYPositionString()) || config.hasKey(windowScreenPositionString());
195}
196
198{
199 // On Wayland, the compositor is solely responsible for window positioning,
200 // So this needs to be a no-op
201 if (!window || QGuiApplication::platformName() == QLatin1String{"wayland"}) {
202 return;
203 }
204
205 const bool isMaximized = config.readEntry(configFileString(QStringLiteral("Window-Maximized")), false);
206
207 // Don't need to restore position if the window was maximized
208 if (isMaximized) {
210 return;
211 }
212
213 // Move window to proper screen
214 const QScreen *screen = window->screen();
215 const QString screenName = config.readEntry(windowScreenPositionString(), screen->name());
216 if (screenName != screen->name()) {
217 QScreen *screenConf = findScreenByName(window, screenName);
218 window->setScreen(screenConf);
219 restoreWindowScreenPosition(window, screenConf, config);
220 return;
221 }
222 restoreWindowScreenPosition(window, screen, config);
223}
224
226{
227 Q_UNUSED(screen);
228 const int xPos = config.readEntry(windowXPositionString(), -1);
229 const int yPos = config.readEntry(windowYPositionString(), -1);
230
231 if (xPos == -1 || yPos == -1) {
232 return;
233 }
234
235 window->setX(xPos);
236 window->setY(yPos);
237}
A class for one specific group in a KConfig object.
T readEntry(const QString &key, const T &aDefault) const
Reads the value of an entry specified by pKey in the current group.
bool hasDefault(const QString &key) const
Whether a default is specified for an entry in either the system wide configuration file or the globa...
bool hasKey(const QString &key) const
Checks whether the key has an entry in this group.
void revertToDefault(const QString &key, WriteConfigFlags pFlag=WriteConfigFlags())
Reverts an entry to the default settings.
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
Writes a value to the configuration object.
void deleteEntry(const QString &pKey, WriteConfigFlags pFlags=Normal)
Deletes the entry specified by pKey in the current group.
QWidget * window(QObject *job)
KCONFIGGUI_EXPORT void saveWindowSize(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options=KConfigGroup::Normal)
Saves the window's size dependent on the screen dimension either to the global or application config ...
KCONFIGGUI_EXPORT bool hasSavedWindowSize(KConfigGroup &config)
Returns whether a given KConfig group has any saved window size data.
KCONFIGGUI_EXPORT void restoreWindowScreenPosition(QWindow *window, const QScreen *screen, const KConfigGroup &config)
Restores the window's position on provided screen from the configuration.
KCONFIGGUI_EXPORT bool hasSavedWindowPosition(KConfigGroup &config)
Returns whether a given KConfig group has any saved window position data.
KCONFIGGUI_EXPORT void saveWindowPosition(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options=KConfigGroup::Normal)
Saves the window's position either to the global or application config file.
KCONFIGGUI_EXPORT void restoreWindowSize(QWindow *window, const KConfigGroup &config)
Restores the dialog's size from the configuration according to the screen size.
KCONFIGGUI_EXPORT void restoreWindowPosition(QWindow *window, const KConfigGroup &config)
Restores the window's screen position from the configuration and calls restoreWindowScreenPosition.
QList< QScreen * > screens()
void reserve(qsizetype size)
QVariant property(const char *name) const const
bool setProperty(const char *name, QVariant &&value)
int height() const const
int width() const const
int height() const const
bool isValid() const const
int width() const const
QString arg(Args &&... args) const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString join(QChar separator) const const
void sort(Qt::CaseSensitivity cs)
WindowMaximized
QSize toSize() const const
QScreen * screen() const const
void setScreen(QScreen *screen)
void setWindowState(Qt::WindowStates windowState)
Qt::WindowStates windowState() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:27 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.