Changeset View
Standalone View
kcmkwin/kwindesktop/desktopsmodel.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright (C) 2018 Eike Hein <hein@kde.org> | ||||
3 | * Copyright (C) 2018 Marco Martin <mart@kde.org> | ||||
4 | * | ||||
5 | * This program is free software; you can redistribute it and/or modify | ||||
6 | * it under the terms of the GNU General Public License as published by | ||||
7 | * the Free Software Foundation; either version 2 of the License, or | ||||
8 | * (at your option) any later version. | ||||
9 | * | ||||
10 | * This program is distributed in the hope that it will be useful, | ||||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
13 | * GNU General Public License for more details. | ||||
14 | * | ||||
15 | * You should have received a copy of the GNU General Public License | ||||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
17 | */ | ||||
18 | | ||||
19 | #include "desktopsmodel.h" | ||||
20 | | ||||
21 | #include <cmath> | ||||
22 | | ||||
23 | #include <KLocalizedString> | ||||
24 | | ||||
25 | #include <QDebug> | ||||
26 | #include <QDBusArgument> | ||||
27 | #include <QDBusConnection> | ||||
28 | #include <QDBusMessage> | ||||
29 | #include <QDBusMetaType> | ||||
30 | #include <QDBusPendingCall> | ||||
31 | #include <QDBusPendingCallWatcher> | ||||
32 | #include <QDBusPendingReply> | ||||
33 | #include <QDBusVariant> | ||||
34 | #include <QMetaEnum> | ||||
35 | #include <QUuid> | ||||
36 | | ||||
37 | namespace KWin | ||||
38 | { | ||||
zzagUnsubmitted Not Done zzag: ```lang=cpp
namespace KWin
{
``` | |||||
39 | | ||||
40 | static const QString s_serviceName(QStringLiteral("org.kde.KWin")); | ||||
41 | static const QString s_virtualDesktopsInterface(QStringLiteral("org.kde.KWin.VirtualDesktopManager")); | ||||
42 | static const QString s_virtDesktopsPath(QStringLiteral("/VirtualDesktopManager")); | ||||
43 | static const QString s_fdoPropertiesInterface(QStringLiteral("org.freedesktop.DBus.Properties")); | ||||
44 | | ||||
45 | DesktopsModel::DesktopsModel(QObject *parent) | ||||
46 | : QAbstractListModel(parent) | ||||
47 | , m_userModified(false) | ||||
48 | , m_serverModified(false) | ||||
49 | , m_serverSideRows(-1) | ||||
50 | , m_synchronizing(false) | ||||
51 | { | ||||
52 | qDBusRegisterMetaType<KWin::DBusDesktopDataStruct>(); | ||||
53 | qDBusRegisterMetaType<KWin::DBusDesktopDataVector>(); | ||||
54 | | ||||
55 | auto initializeCall = QDBusMessage::createMethodCall( | ||||
56 | s_serviceName, | ||||
57 | s_virtDesktopsPath, | ||||
58 | s_fdoPropertiesInterface, | ||||
59 | QStringLiteral("GetAll")); | ||||
60 | | ||||
61 | initializeCall.setArguments({s_virtualDesktopsInterface}); | ||||
62 | | ||||
63 | QDBusConnection::sessionBus().callWithCallback( | ||||
64 | initializeCall, | ||||
65 | this, | ||||
66 | SLOT(initialize(QDBusMessage)), | ||||
67 | SLOT(handleCallError())); | ||||
68 | } | ||||
69 | | ||||
70 | DesktopsModel::~DesktopsModel() | ||||
71 | { | ||||
72 | } | ||||
73 | | ||||
74 | QHash<int, QByteArray> DesktopsModel::roleNames() const | ||||
75 | { | ||||
76 | QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); | ||||
77 | | ||||
78 | QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles")); | ||||
79 | | ||||
80 | for (int i = 0; i < e.keyCount(); ++i) { | ||||
81 | roles.insert(e.value(i), e.key(i)); | ||||
82 | } | ||||
83 | | ||||
84 | return roles; | ||||
85 | } | ||||
86 | | ||||
87 | QVariant DesktopsModel::data(const QModelIndex &index, int role) const | ||||
88 | { | ||||
89 | if (!index.isValid() || index.row() < 0 || index.row() > (m_desktops.count() - 1)) { | ||||
90 | return QVariant(); | ||||
91 | } | ||||
92 | | ||||
93 | if (role == Qt::DisplayRole) { | ||||
94 | return m_names.value(m_desktops.at(index.row())); | ||||
95 | } else if (role == Id) { | ||||
96 | return m_desktops.at(index.row()); | ||||
97 | } else if (role == DesktopRow) { | ||||
98 | const int rows = std::max(m_rows, 1); | ||||
99 | const int perRow = std::ceil((qreal)m_desktops.count() / (qreal)rows); | ||||
100 | | ||||
101 | return (index.row() / perRow) + 1; | ||||
102 | | ||||
103 | } | ||||
104 | | ||||
105 | return QVariant(); | ||||
106 | } | ||||
107 | | ||||
108 | int DesktopsModel::rowCount(const QModelIndex &parent) const | ||||
109 | { | ||||
110 | if (parent.isValid()) { | ||||
111 | return 0; | ||||
112 | } | ||||
113 | | ||||
114 | return m_desktops.count(); | ||||
115 | } | ||||
116 | | ||||
117 | bool DesktopsModel::ready() const | ||||
118 | { | ||||
119 | return !m_serverSideDesktops.isEmpty(); | ||||
120 | } | ||||
121 | | ||||
122 | QString DesktopsModel::error() const | ||||
123 | { | ||||
124 | return m_error; | ||||
125 | } | ||||
126 | | ||||
127 | bool DesktopsModel::userModified() const | ||||
128 | { | ||||
129 | return m_userModified; | ||||
130 | } | ||||
131 | | ||||
132 | bool DesktopsModel::serverModified() const | ||||
133 | { | ||||
134 | return m_serverModified; | ||||
135 | } | ||||
136 | | ||||
137 | int DesktopsModel::rows() const | ||||
138 | { | ||||
139 | return m_rows; | ||||
140 | } | ||||
141 | | ||||
142 | void DesktopsModel::setRows(int rows) | ||||
143 | { | ||||
144 | if (!ready()) { | ||||
145 | return; | ||||
146 | } | ||||
147 | | ||||
148 | if (m_rows != rows) { | ||||
149 | m_rows = rows; | ||||
150 | | ||||
151 | emit rowsChanged(); | ||||
152 | emit dataChanged(index(0, 0), index(m_desktops.count() - 1, 0), QVector<int>{DesktopRow}); | ||||
153 | | ||||
154 | checkModifiedState(); | ||||
155 | } | ||||
156 | } | ||||
157 | | ||||
158 | void DesktopsModel::createDesktop(const QString &name) | ||||
159 | { | ||||
160 | if (!ready()) { | ||||
161 | return; | ||||
162 | } | ||||
163 | | ||||
164 | beginInsertRows(QModelIndex(), m_serverSideDesktops.count(), m_serverSideDesktops.count()); | ||||
165 | | ||||
166 | const QString &dummyId = QUuid::createUuid().toString(QUuid::WithoutBraces); | ||||
167 | | ||||
168 | m_desktops.append(dummyId); | ||||
169 | m_names[dummyId] = name; | ||||
170 | | ||||
171 | endInsertRows(); | ||||
172 | | ||||
173 | checkModifiedState(); | ||||
174 | } | ||||
175 | | ||||
176 | void DesktopsModel::removeDesktop(const QString &id) | ||||
177 | { | ||||
178 | if (!ready() || !m_desktops.contains(id)) { | ||||
179 | return; | ||||
180 | } | ||||
181 | | ||||
182 | const int desktopIndex = m_desktops.indexOf(id); | ||||
183 | | ||||
184 | beginRemoveRows(QModelIndex(), desktopIndex, desktopIndex); | ||||
185 | | ||||
186 | m_desktops.removeAt(desktopIndex); | ||||
187 | m_names.remove(id); | ||||
188 | | ||||
189 | endRemoveRows(); | ||||
190 | | ||||
191 | checkModifiedState(); | ||||
192 | } | ||||
193 | | ||||
194 | void DesktopsModel::setDesktopName(const QString &id, const QString &name) | ||||
195 | { | ||||
196 | if (!ready() || !m_desktops.contains(id)) { | ||||
197 | return; | ||||
198 | } | ||||
199 | | ||||
200 | const int desktopIndex = m_desktops.indexOf(id); | ||||
201 | | ||||
202 | m_desktops[desktopIndex] = id; | ||||
203 | m_names[id] = name; | ||||
davidedmundson: this is setting it to the value it already is | |||||
204 | | ||||
205 | const QModelIndex &idx = index(desktopIndex, 0); | ||||
206 | | ||||
207 | dataChanged(idx, idx, QVector<int>{Qt::DisplayRole}); | ||||
208 | | ||||
209 | checkModifiedState(); | ||||
210 | } | ||||
211 | | ||||
212 | void DesktopsModel::syncWithServer() | ||||
213 | { | ||||
214 | m_synchronizing = true; | ||||
215 | | ||||
216 | auto callFinished = [this](QDBusPendingCallWatcher *call) { | ||||
217 | QDBusPendingReply<void> reply = *call; | ||||
218 | | ||||
219 | if (reply.isError()) { | ||||
220 | handleCallError(); | ||||
221 | } | ||||
222 | | ||||
223 | call->deleteLater(); | ||||
224 | }; | ||||
225 | | ||||
226 | if (m_desktops.count() > m_serverSideDesktops.count()) { | ||||
227 | auto call = QDBusMessage::createMethodCall( | ||||
228 | s_serviceName, | ||||
229 | s_virtDesktopsPath, | ||||
230 | s_virtualDesktopsInterface, | ||||
231 | QStringLiteral("createDesktop")); | ||||
232 | | ||||
233 | const int newIndex = m_serverSideDesktops.count(); | ||||
234 | | ||||
235 | call.setArguments({(uint)newIndex, m_names.value(m_desktops.at(newIndex))}); | ||||
236 | | ||||
237 | QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call); | ||||
238 | | ||||
239 | const auto *watcher = new QDBusPendingCallWatcher(pending, this); | ||||
240 | QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished); | ||||
241 | | ||||
242 | return; // The change-handling slot will call syncWithServer() again, | ||||
243 | // until everything is in sync. | ||||
244 | } | ||||
245 | | ||||
246 | if (m_desktops.count() < m_serverSideDesktops.count()) { | ||||
247 | auto call = QDBusMessage::createMethodCall( | ||||
248 | s_serviceName, | ||||
249 | s_virtDesktopsPath, | ||||
250 | s_virtualDesktopsInterface, | ||||
251 | QStringLiteral("removeDesktop")); | ||||
252 | | ||||
If I have 3 desktops with 3 IDs and I delete desktop2 Here I delete 3 and then sync the names, leaving me with: it looks fine within the confines of this KCM, but as soon as we rely on those IDs for external use (even just the fact that a user might have his windows on id3 and none on id2) it'll fall apart. When you make the change sending insert/remove instead of renaming we'll need to make sure we do removal before insertion. desktopCreated relies on the index of the newly created desktop to be in the same place as m_desktops has it. If we insert first, the position will be off as the server will still have the about-to-be-deleted entries davidedmundson:
If I have 3 desktops with 3 IDs
id1 -> desktop1
id2 -> desktop2
id3 -> desktop3
and I delete… | |||||
253 | call.setArguments({m_desktops.last()}); | ||||
254 | | ||||
Is m_desktops.last() the right one? It can be already deleted. For example, If user has two virtual desktops:
and he or she wants to delete virtual desktop called "Pizza", then Desktop 1 will be removed instead. zzag: Is m_desktops.last() the right one? It can be already deleted.
For example, If user has two… | |||||
255 | QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call); | ||||
256 | | ||||
257 | const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this); | ||||
258 | QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished); | ||||
259 | | ||||
260 | return; // The change-handling slot will call syncWithServer() again, | ||||
261 | // until everything is in sync. | ||||
262 | } | ||||
263 | | ||||
264 | // Sync names. | ||||
265 | if (m_names != m_serverSideNames) { | ||||
266 | QHashIterator<QString, QString> i(m_names); | ||||
267 | | ||||
268 | while (i.hasNext()) { | ||||
269 | i.next(); | ||||
270 | | ||||
271 | if (i.value() != m_serverSideNames.value(i.key())) { | ||||
272 | auto call = QDBusMessage::createMethodCall( | ||||
273 | s_serviceName, | ||||
274 | s_virtDesktopsPath, | ||||
275 | s_virtualDesktopsInterface, | ||||
276 | QStringLiteral("setDesktopName")); | ||||
277 | | ||||
278 | call.setArguments({i.key(), i.value()}); | ||||
279 | | ||||
280 | QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call); | ||||
281 | | ||||
282 | const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this); | ||||
283 | QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished); | ||||
284 | | ||||
285 | break; | ||||
286 | } | ||||
287 | } | ||||
288 | | ||||
289 | return; // The change-handling slot will call syncWithServer() again, | ||||
290 | // until everything is in sync.. | ||||
291 | } | ||||
292 | | ||||
zzag: Please indent it. | |||||
293 | // Sync rows. | ||||
294 | if (m_rows != m_serverSideRows) { | ||||
295 | auto call = QDBusMessage::createMethodCall( | ||||
296 | s_serviceName, | ||||
297 | s_virtDesktopsPath, | ||||
298 | s_fdoPropertiesInterface, | ||||
299 | QStringLiteral("Set")); | ||||
300 | | ||||
301 | call.setArguments({s_virtualDesktopsInterface, | ||||
302 | QStringLiteral("rows"), QVariant::fromValue(QDBusVariant(QVariant((uint)m_rows)))}); | ||||
303 | | ||||
304 | QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call); | ||||
305 | | ||||
306 | const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this); | ||||
307 | QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished); | ||||
308 | } | ||||
309 | } | ||||
310 | | ||||
311 | void DesktopsModel::initialize(const QDBusMessage &msg) | ||||
312 | { | ||||
313 | beginResetModel(); | ||||
314 | | ||||
315 | const QVariantMap &data = qdbus_cast<QVariantMap>(msg.arguments().at(0).value<QDBusArgument>()); | ||||
316 | | ||||
317 | const KWin::DBusDesktopDataVector &desktops = qdbus_cast<KWin::DBusDesktopDataVector>( | ||||
318 | data.value(QStringLiteral("desktops")).value<QDBusArgument>() | ||||
zzag: You could also use `auto` here. ;-) | |||||
319 | ); | ||||
320 | | ||||
321 | m_serverSideRows = data.value(QStringLiteral("rows")).toUInt(); | ||||
322 | m_rows = m_serverSideRows; | ||||
323 | | ||||
324 | for (const KWin::DBusDesktopDataStruct &d : desktops) { | ||||
325 | m_serverSideDesktops.append(d.id); | ||||
326 | m_desktops = m_serverSideDesktops; | ||||
327 | m_serverSideNames[d.id] = d.name; | ||||
328 | m_names = m_serverSideNames; | ||||
329 | } | ||||
330 | | ||||
331 | endResetModel(); | ||||
332 | | ||||
333 | emit readyChanged(); | ||||
334 | | ||||
335 | auto handleConnectionError = [this]() { | ||||
336 | m_error = i18n("There was an error connecting to the compositor."); | ||||
337 | emit errorChanged(); | ||||
338 | }; | ||||
339 | | ||||
340 | bool connected = QDBusConnection::sessionBus().connect( | ||||
341 | s_serviceName, | ||||
342 | s_virtDesktopsPath, | ||||
343 | s_virtualDesktopsInterface, | ||||
344 | QStringLiteral("desktopCreated"), | ||||
345 | this, | ||||
346 | SLOT(desktopCreated(QString,KWin::DBusDesktopDataStruct))); | ||||
347 | | ||||
348 | if (!connected) { | ||||
349 | handleConnectionError(); | ||||
350 | | ||||
351 | return; | ||||
352 | } | ||||
353 | | ||||
354 | connected = QDBusConnection::sessionBus().connect( | ||||
355 | s_serviceName, | ||||
356 | s_virtDesktopsPath, | ||||
357 | s_virtualDesktopsInterface, | ||||
358 | QStringLiteral("desktopRemoved"), | ||||
359 | this, | ||||
360 | SLOT(desktopRemoved(QString))); | ||||
361 | | ||||
362 | if (!connected) { | ||||
363 | handleConnectionError(); | ||||
364 | | ||||
365 | return; | ||||
366 | } | ||||
367 | | ||||
368 | connected = QDBusConnection::sessionBus().connect( | ||||
369 | s_serviceName, | ||||
370 | s_virtDesktopsPath, | ||||
371 | s_virtualDesktopsInterface, | ||||
372 | QStringLiteral("desktopDataChanged"), | ||||
373 | this, | ||||
374 | SLOT(desktopDataChanged(QString,KWin::DBusDesktopDataStruct))); | ||||
375 | | ||||
376 | if (!connected) { | ||||
377 | handleConnectionError(); | ||||
378 | | ||||
379 | return; | ||||
Minor nitpick: In order to construct QString, we'll copy the QLatin1String (source). Maybe, use QStringLiteral instead? (Same with the QLatin1String down below) zzag: Minor nitpick: In order to construct QString, we'll copy the QLatin1String ([source](https… | |||||
380 | } | ||||
381 | | ||||
382 | connected = QDBusConnection::sessionBus().connect( | ||||
383 | s_serviceName, | ||||
384 | s_virtDesktopsPath, | ||||
385 | s_virtualDesktopsInterface, | ||||
Minor nitpick: because that's a new code, maybe use range based for loop instead? zzag: Minor nitpick: because that's a new code, maybe use range based for loop instead? | |||||
386 | QStringLiteral("rowsChanged"), | ||||
387 | this, | ||||
388 | SLOT(desktopRowsChanged(uint))); | ||||
389 | | ||||
390 | if (!connected) { | ||||
391 | handleConnectionError(); | ||||
392 | | ||||
393 | return; | ||||
394 | } | ||||
395 | } | ||||
396 | | ||||
397 | void DesktopsModel::desktopCreated(const QString &id, const KWin::DBusDesktopDataStruct &data) | ||||
398 | { | ||||
399 | m_serverSideDesktops.insert(data.position, id); | ||||
400 | m_serverSideNames[data.id] = data.name; | ||||
401 | | ||||
402 | // If the user didn't make any changes, we can just stay in sync. | ||||
403 | if (!m_userModified) { | ||||
but if it is userModified don't we need to update the ID to be the non-dummy value in case that entry is then later removed? davidedmundson: but if it is userModified don't we need to update the ID to be the non-dummy value in case that… | |||||
404 | beginInsertRows(QModelIndex(), data.position, data.position); | ||||
405 | | ||||
406 | m_desktops = m_serverSideDesktops; | ||||
407 | m_names = m_serverSideNames; | ||||
408 | | ||||
409 | endInsertRows(); | ||||
410 | } else { | ||||
411 | // Swap dummyId inserted in `createDesktop()` for real id, | ||||
412 | // so we can determine when we are in sync. | ||||
413 | const QString &dummyId = m_desktops.at(data.position); | ||||
414 | m_names.remove(dummyId); | ||||
Is this right? If I remove a desktop in the KCM(without applying settings) and create a new one using the d-bus interface, the KCM will crash. zzag: Is this right?
If I remove a desktop in the KCM(without applying settings) and create a new… | |||||
415 | m_desktops.insert(data.position, id); | ||||
416 | m_names[data.id] = data.name; | ||||
417 | | ||||
davidedmundson: needs a guard.
could be emitted before the first load finishes | |||||
hein: I'll move the other connnects to the initialize slot. | |||||
Sorry for the above, I wrote it before updating the review but forgot to submit. hein: Sorry for the above, I wrote it before updating the review but forgot to submit. | |||||
418 | checkModifiedState(/* server */ true); | ||||
419 | } | ||||
420 | } | ||||
421 | | ||||
422 | void DesktopsModel::desktopRemoved(const QString &id) | ||||
423 | { | ||||
424 | const int desktopIndex = m_serverSideDesktops.indexOf(id); | ||||
425 | | ||||
426 | m_serverSideDesktops.removeAt(desktopIndex); | ||||
427 | m_serverSideNames.remove(id); | ||||
428 | | ||||
429 | // If the user didn't make any changes, we can just stay in sync. | ||||
430 | if (!m_userModified) { | ||||
431 | beginRemoveRows(QModelIndex(), desktopIndex, desktopIndex); | ||||
432 | | ||||
433 | m_desktops = m_serverSideDesktops; | ||||
434 | m_names = m_serverSideNames; | ||||
435 | | ||||
436 | endRemoveRows(); | ||||
437 | } else { | ||||
438 | checkModifiedState(/* server */ true); | ||||
439 | } | ||||
440 | } | ||||
441 | | ||||
442 | void DesktopsModel::desktopDataChanged(const QString &id, const KWin::DBusDesktopDataStruct &data) | ||||
443 | { | ||||
444 | const int desktopIndex = m_serverSideDesktops.indexOf(id); | ||||
445 | | ||||
446 | m_serverSideDesktops[desktopIndex] = id; | ||||
447 | m_serverSideNames[id] = data.name; | ||||
448 | | ||||
449 | // If the user didn't make any changes, we can just stay in sync. | ||||
450 | if (!m_userModified) { | ||||
451 | m_desktops = m_serverSideDesktops; | ||||
452 | m_names = m_serverSideNames; | ||||
453 | | ||||
454 | const QModelIndex &idx = index(desktopIndex, 0); | ||||
455 | | ||||
456 | dataChanged(idx, idx, QVector<int>{Qt::DisplayRole}); | ||||
457 | } else { | ||||
458 | checkModifiedState(/* server */ true); | ||||
459 | } | ||||
460 | } | ||||
461 | | ||||
462 | void DesktopsModel::desktopRowsChanged(uint rows) | ||||
463 | { | ||||
464 | m_serverSideRows = rows; | ||||
465 | | ||||
466 | // If the user didn't make any changes, we can just stay in sync. | ||||
467 | if (!m_userModified) { | ||||
468 | m_rows = m_serverSideRows; | ||||
469 | | ||||
470 | emit rowsChanged(); | ||||
471 | emit dataChanged(index(0, 0), index(m_desktops.count() - 1, 0), QVector<int>{DesktopRow}); | ||||
472 | } else { | ||||
473 | checkModifiedState(/* server */ true); | ||||
474 | } | ||||
475 | } | ||||
476 | | ||||
477 | void DesktopsModel::checkModifiedState(bool server) | ||||
478 | { | ||||
479 | if (m_desktops == m_serverSideDesktops | ||||
480 | && m_names == m_serverSideNames | ||||
481 | && m_rows == m_serverSideRows) { | ||||
482 | m_userModified = false; | ||||
483 | emit userModifiedChanged(); | ||||
484 | | ||||
485 | m_serverModified = false; | ||||
486 | emit serverModifiedChanged(); | ||||
487 | | ||||
488 | emit needsSaving(false); | ||||
489 | | ||||
490 | m_synchronizing = false; | ||||
491 | } else { | ||||
492 | if (m_synchronizing) { | ||||
493 | m_serverModified = false; | ||||
494 | emit serverModifiedChanged(); | ||||
495 | | ||||
496 | syncWithServer(); | ||||
497 | } else if (server) { | ||||
498 | m_serverModified = true; | ||||
499 | emit serverModifiedChanged(); | ||||
500 | } else { | ||||
501 | m_userModified = true; | ||||
502 | emit userModifiedChanged(); | ||||
503 | | ||||
504 | emit needsSaving(true); | ||||
505 | } | ||||
506 | } | ||||
507 | } | ||||
508 | | ||||
509 | void DesktopsModel::handleCallError() | ||||
510 | { | ||||
511 | if (m_synchronizing) { | ||||
512 | m_synchronizing = false; | ||||
513 | | ||||
514 | m_serverModified = false; | ||||
515 | emit serverModifiedChanged(); | ||||
516 | | ||||
517 | m_error = i18n("There was an error saving the settings to the compositor."); | ||||
518 | emit errorChanged(); | ||||
519 | } else { | ||||
520 | m_error = i18n("There was an error requesting information from the compositor."); | ||||
521 | emit errorChanged(); | ||||
522 | } | ||||
523 | } | ||||
524 | | ||||
525 | } |