Changeset View
Changeset View
Standalone View
Standalone View
kcm/config_handler.cpp
- This file was added.
1 | /******************************************************************** | ||||
---|---|---|---|---|---|
2 | Copyright © 2019 Roman Gilg <subdiff@gmail.com> | ||||
3 | | ||||
4 | This program is free software; you can redistribute it and/or modify | ||||
5 | it under the terms of the GNU General Public License as published by | ||||
6 | the Free Software Foundation; either version 2 of the License, or | ||||
7 | (at your option) any later version. | ||||
8 | | ||||
9 | This program is distributed in the hope that it will be useful, | ||||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
12 | GNU General Public License for more details. | ||||
13 | | ||||
14 | You should have received a copy of the GNU General Public License | ||||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
16 | *********************************************************************/ | ||||
17 | #include "config_handler.h" | ||||
18 | | ||||
19 | #include "kcm_screen_debug.h" | ||||
20 | #include "output_model.h" | ||||
21 | | ||||
22 | #include <kscreen/configmonitor.h> | ||||
23 | #include <kscreen/getconfigoperation.h> | ||||
24 | #include <kscreen/output.h> | ||||
25 | | ||||
26 | #include <QRect> | ||||
27 | | ||||
28 | using namespace KScreen; | ||||
29 | | ||||
30 | ConfigHandler::ConfigHandler(QObject *parent) | ||||
31 | : QObject(parent) | ||||
32 | { | ||||
33 | } | ||||
34 | | ||||
35 | void ConfigHandler::setConfig(KScreen::ConfigPtr config) | ||||
36 | { | ||||
37 | m_config = config; | ||||
38 | m_initialConfig = m_config->clone(); | ||||
39 | KScreen::ConfigMonitor::instance()->addConfig(m_config); | ||||
40 | m_control.reset(new ControlConfig(config)); | ||||
41 | | ||||
42 | m_outputs = new OutputModel(this); | ||||
43 | connect(m_outputs, &OutputModel::positionChanged, | ||||
44 | this, &ConfigHandler::checkScreenNormalization); | ||||
45 | connect(m_outputs, &OutputModel::sizeChanged, | ||||
46 | this, &ConfigHandler::checkScreenNormalization); | ||||
47 | connect(m_outputs, &OutputModel::changed, | ||||
48 | this, [this]() { | ||||
49 | checkNeedsSave(); | ||||
50 | Q_EMIT changed(); | ||||
51 | }); | ||||
52 | | ||||
53 | for (const KScreen::OutputPtr &output : config->outputs()) { | ||||
54 | initOutput(output); | ||||
55 | } | ||||
56 | m_lastNormalizedScreenSize = screenSize(); | ||||
57 | m_initialRetention = getRetention(); | ||||
58 | Q_EMIT retentionChanged(); | ||||
59 | | ||||
60 | connect(m_config.data(), &KScreen::Config::outputAdded, | ||||
61 | this, [this]() { Q_EMIT outputConnect(true); }); | ||||
62 | connect(m_config.data(), &KScreen::Config::outputRemoved, | ||||
63 | this, [this]() { Q_EMIT outputConnect(false); }); | ||||
64 | connect(m_config.data(), &KScreen::Config::primaryOutputChanged, | ||||
65 | this, &ConfigHandler::primaryOutputChanged); | ||||
66 | | ||||
67 | Q_EMIT outputModelChanged(); | ||||
68 | } | ||||
69 | | ||||
70 | void ConfigHandler::initOutput(const KScreen::OutputPtr &output) | ||||
71 | { | ||||
72 | if (output->isConnected()) { | ||||
73 | m_outputs->add(output); | ||||
74 | } | ||||
75 | connect(output.data(), &KScreen::Output::isConnectedChanged, | ||||
76 | this, [this, output]() { | ||||
77 | Q_EMIT outputConnect(output->isConnected()); | ||||
78 | }); | ||||
79 | } | ||||
80 | | ||||
81 | void ConfigHandler::updateInitialConfig() | ||||
82 | { | ||||
83 | m_initialRetention = getRetention(); | ||||
84 | connect(new GetConfigOperation(), &GetConfigOperation::finished, | ||||
85 | this, [this](ConfigOperation *op) { | ||||
86 | if (op->hasError()) { | ||||
87 | return; | ||||
88 | } | ||||
89 | m_initialConfig = qobject_cast<GetConfigOperation*>(op)->config(); | ||||
90 | checkNeedsSave(); | ||||
91 | }); | ||||
92 | } | ||||
93 | | ||||
94 | void ConfigHandler::checkNeedsSave() | ||||
95 | { | ||||
96 | if (m_config->supportedFeatures() & | ||||
97 | KScreen::Config::Feature::PrimaryDisplay) { | ||||
98 | if (m_config->primaryOutput()->hashMd5() != | ||||
99 | m_initialConfig->primaryOutput()->hashMd5() ) { | ||||
100 | Q_EMIT needsSaveChecked(true); | ||||
101 | return; | ||||
102 | } | ||||
103 | } | ||||
104 | if (m_initialRetention != getRetention()) { | ||||
105 | Q_EMIT needsSaveChecked(true); | ||||
106 | return; | ||||
107 | } | ||||
108 | for (const auto &output : m_config->connectedOutputs()) { | ||||
109 | const QString hash = output->hashMd5(); | ||||
110 | for (const auto &initialOutput : m_initialConfig->outputs()) { | ||||
111 | if (hash != initialOutput->hashMd5()) { | ||||
112 | continue; | ||||
113 | } | ||||
114 | bool needsSave = false; | ||||
115 | if (output->isEnabled() != initialOutput->isEnabled()) { | ||||
116 | needsSave = true; | ||||
117 | } | ||||
118 | if (output->isEnabled()) { | ||||
119 | needsSave |= output->currentModeId() != | ||||
120 | initialOutput->currentModeId() | ||||
121 | || output->pos() != initialOutput->pos() | ||||
122 | || output->scale() != initialOutput->scale() | ||||
123 | || output->rotation() != initialOutput->rotation(); | ||||
124 | } | ||||
125 | if (needsSave) { | ||||
126 | Q_EMIT needsSaveChecked(true); | ||||
127 | return; | ||||
128 | } | ||||
129 | break; | ||||
130 | } | ||||
131 | } | ||||
132 | Q_EMIT needsSaveChecked(false); | ||||
133 | } | ||||
134 | | ||||
135 | QSize ConfigHandler::screenSize() const | ||||
136 | { | ||||
137 | int width = 0, height = 0; | ||||
138 | QSize size; | ||||
139 | | ||||
140 | for (const auto &output : m_config->connectedOutputs()) { | ||||
141 | const int outputRight = output->geometry().right(); | ||||
142 | const int outputBottom = output->geometry().bottom(); | ||||
143 | | ||||
144 | if (outputRight > width) { | ||||
145 | width = outputRight; | ||||
146 | } | ||||
147 | if (outputBottom > height) { | ||||
148 | height = outputBottom; | ||||
149 | } | ||||
150 | } | ||||
151 | if (width > 0 && height > 0) { | ||||
152 | size = QSize(width, height); | ||||
153 | } else { | ||||
154 | size = QSize(); | ||||
155 | } | ||||
156 | return size; | ||||
157 | } | ||||
158 | | ||||
159 | QSize ConfigHandler::normalizeScreen() | ||||
160 | { | ||||
161 | if (!m_config) { | ||||
162 | return QSize(); | ||||
163 | } | ||||
164 | bool changed = m_outputs->normalizePositions(); | ||||
165 | | ||||
166 | const auto currentScreenSize = screenSize(); | ||||
167 | changed |= m_lastNormalizedScreenSize != currentScreenSize; | ||||
168 | m_lastNormalizedScreenSize = currentScreenSize; | ||||
169 | | ||||
170 | Q_EMIT screenNormalizationUpdate(true); | ||||
171 | return currentScreenSize; | ||||
172 | } | ||||
173 | | ||||
174 | void ConfigHandler::checkScreenNormalization() | ||||
175 | { | ||||
176 | const bool normalized = !m_config || | ||||
177 | (m_lastNormalizedScreenSize == screenSize() && | ||||
178 | m_outputs->positionsNormalized()); | ||||
179 | | ||||
180 | Q_EMIT screenNormalizationUpdate(normalized); | ||||
181 | } | ||||
182 | | ||||
183 | void ConfigHandler::primaryOutputSelected(int index) | ||||
184 | { | ||||
185 | Q_UNUSED(index) | ||||
186 | // TODO | ||||
187 | } | ||||
188 | | ||||
189 | void ConfigHandler::primaryOutputChanged(const KScreen::OutputPtr &output) | ||||
190 | { | ||||
191 | Q_UNUSED(output) | ||||
192 | | ||||
193 | } | ||||
194 | | ||||
195 | Control::OutputRetention ConfigHandler::getRetention() const | ||||
196 | { | ||||
197 | using Retention = Control::OutputRetention; | ||||
198 | | ||||
199 | auto ret = Retention::Undefined; | ||||
200 | if (!m_control) { | ||||
201 | return ret; | ||||
202 | } | ||||
203 | const auto outputs = m_config->connectedOutputs(); | ||||
204 | if (outputs.isEmpty()) { | ||||
205 | return ret; | ||||
206 | } | ||||
207 | ret = m_control->getOutputRetention(outputs.first()); | ||||
208 | | ||||
209 | for (const auto &output : outputs) { | ||||
210 | const auto outputRet = m_control->getOutputRetention(output); | ||||
211 | if (ret != outputRet ) { | ||||
212 | // Control file with different retention values per output. | ||||
213 | return Retention::Undefined; | ||||
214 | } | ||||
215 | } | ||||
216 | | ||||
217 | if (ret == Retention::Undefined) { | ||||
218 | // If all outputs have undefined retention, | ||||
219 | // this should be displayed as global retention. | ||||
220 | return Retention::Global; | ||||
221 | } | ||||
222 | return ret; | ||||
223 | } | ||||
224 | | ||||
225 | int ConfigHandler::retention() const | ||||
226 | { | ||||
227 | return static_cast<int>(getRetention()); | ||||
228 | } | ||||
229 | | ||||
230 | void ConfigHandler::setRetention(int retention) | ||||
231 | { | ||||
232 | using Retention = Control::OutputRetention; | ||||
233 | | ||||
234 | if (!m_control) { | ||||
235 | return; | ||||
236 | } | ||||
237 | if (retention != static_cast<int>(Retention::Global) && | ||||
238 | retention != static_cast<int>(Retention::Individual)) { | ||||
239 | // We only allow setting to global or individual retention. | ||||
240 | return; | ||||
241 | } | ||||
242 | if (retention == ConfigHandler::retention()) { | ||||
243 | return; | ||||
244 | } | ||||
245 | auto ret = static_cast<Retention>(retention); | ||||
246 | for (const auto &output : m_config->connectedOutputs()) { | ||||
247 | m_control->setOutputRetention(output, ret); | ||||
248 | } | ||||
249 | checkNeedsSave(); | ||||
250 | Q_EMIT retentionChanged(); | ||||
251 | Q_EMIT changed(); | ||||
252 | } | ||||
253 | | ||||
254 | void ConfigHandler::writeControl() | ||||
255 | { | ||||
256 | if (!m_control) { | ||||
257 | return; | ||||
258 | } | ||||
259 | m_control->writeFile(); | ||||
260 | } |