KWin
Loading...
Searching...
No Matches
virtualdesktops.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
6 SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9*/
10#include "virtualdesktops.h"
11#include "input.h"
13// KDE
14#include <KConfigGroup>
15#include <KGlobalAccel>
16#include <KLocalizedString>
17#include <NETWM>
18
19// Qt
20#include <QAction>
21#include <QDebug>
22#include <QUuid>
23
24#include <algorithm>
25
26namespace KWin
27{
28
29static bool s_loadingDesktopSettings = false;
30static const double GESTURE_SWITCH_THRESHOLD = .25;
31
32static QString generateDesktopId()
33{
34 return QUuid::createUuid().toString(QUuid::WithoutBraces);
35}
36
38 : QObject(parent)
39{
40}
41
46
48{
49 Q_ASSERT(!m_virtualDesktopManagement);
50 m_virtualDesktopManagement = management;
51
52 auto createPlasmaVirtualDesktop = [this](VirtualDesktop *desktop) {
53 PlasmaVirtualDesktopInterface *pvd = m_virtualDesktopManagement->createDesktop(desktop->id(), desktop->x11DesktopNumber() - 1);
54 pvd->setName(desktop->name());
55 pvd->sendDone();
56
57 connect(desktop, &VirtualDesktop::nameChanged, pvd, [desktop, pvd]() {
58 pvd->setName(desktop->name());
59 pvd->sendDone();
60 });
61 connect(pvd, &PlasmaVirtualDesktopInterface::activateRequested, this, [this, desktop]() {
62 setCurrent(desktop);
63 });
64 };
65
66 connect(this, &VirtualDesktopManager::desktopAdded, m_virtualDesktopManagement, createPlasmaVirtualDesktop);
67
68 connect(this, &VirtualDesktopManager::rowsChanged, m_virtualDesktopManagement, [this](uint rows) {
69 m_virtualDesktopManagement->setRows(rows);
70 m_virtualDesktopManagement->sendDone();
71 });
72
73 // handle removed: from VirtualDesktopManager to the wayland interface
74 connect(this, &VirtualDesktopManager::desktopRemoved, m_virtualDesktopManagement, [this](VirtualDesktop *desktop) {
75 m_virtualDesktopManagement->removeDesktop(desktop->id());
76 });
77
78 // create a new desktop when the client asks to
79 connect(m_virtualDesktopManagement, &PlasmaVirtualDesktopManagementInterface::desktopCreateRequested, this, [this](const QString &name, quint32 position) {
80 createVirtualDesktop(position, name);
81 });
82
83 // remove when the client asks to
84 connect(m_virtualDesktopManagement, &PlasmaVirtualDesktopManagementInterface::desktopRemoveRequested, this, [this](const QString &id) {
85 // here there can be some nice kauthorized check?
86 // remove only from VirtualDesktopManager, the other connections will remove it from m_virtualDesktopManagement as well
88 });
89
90 connect(this, &VirtualDesktopManager::currentChanged, m_virtualDesktopManagement, [this]() {
91 const QList<PlasmaVirtualDesktopInterface *> deskIfaces = m_virtualDesktopManagement->desktops();
92 for (auto *deskInt : deskIfaces) {
93 if (deskInt->id() == currentDesktop()->id()) {
94 deskInt->setActive(true);
95 } else {
96 deskInt->setActive(false);
97 }
98 }
99 });
100
101 std::for_each(m_desktops.constBegin(), m_desktops.constEnd(), createPlasmaVirtualDesktop);
102
103 m_virtualDesktopManagement->setRows(rows());
104 m_virtualDesktopManagement->sendDone();
105}
106
107void VirtualDesktop::setId(const QString &id)
108{
109 Q_ASSERT(m_id.isEmpty());
110 m_id = id;
111}
112
114{
115 // x11DesktopNumber can be changed now
116 if (static_cast<uint>(m_x11DesktopNumber) == number) {
117 return;
118 }
119
120 m_x11DesktopNumber = number;
121
122 if (m_x11DesktopNumber != 0) {
124 }
125}
126
127void VirtualDesktop::setName(const QString &name)
128{
129 if (m_name == name) {
130 return;
131 }
132 m_name = name;
133 Q_EMIT nameChanged();
134}
135
137 : m_size(1, 2) // Default to tow rows
138 , m_grid(QList<QList<VirtualDesktop *>>{QList<VirtualDesktop *>{}, QList<VirtualDesktop *>{}})
139{
140}
141
143
144void VirtualDesktopGrid::update(const QSize &size, const QList<VirtualDesktop *> &desktops)
145{
146 // Set private variables
147 m_size = size;
148 const uint width = size.width();
149 const uint height = size.height();
150
151 m_grid.clear();
152 auto it = desktops.begin();
153 auto end = desktops.end();
154 for (uint y = 0; y < height; ++y) {
155 QList<VirtualDesktop *> row;
156 for (uint x = 0; x < width && it != end; ++x) {
157 row << *it;
158 it++;
159 }
160 m_grid << row;
161 }
162}
163
165{
166 return gridCoords(VirtualDesktopManager::self()->desktopForX11Id(id));
167}
168
170{
171 for (int y = 0; y < m_grid.count(); ++y) {
172 const auto &row = m_grid.at(y);
173 for (int x = 0; x < row.count(); ++x) {
174 if (row.at(x) == vd) {
175 return QPoint(x, y);
176 }
177 }
178 }
179 return QPoint(-1, -1);
180}
181
182VirtualDesktop *VirtualDesktopGrid::at(const QPoint &coords) const
183{
184 if (coords.y() >= m_grid.count()) {
185 return nullptr;
186 }
187 const auto &row = m_grid.at(coords.y());
188 if (coords.x() >= row.count()) {
189 return nullptr;
190 }
191 return row.at(coords.x());
192}
193
195
196VirtualDesktopManager::VirtualDesktopManager(QObject *parent)
197 : QObject(parent)
198 , m_navigationWrapsAround(false)
199 , m_rootInfo(nullptr)
200 , m_swipeGestureReleasedY(new QAction(this))
201 , m_swipeGestureReleasedX(new QAction(this))
202{
203}
204
206{
207 s_manager = nullptr;
208}
209
211{
212 m_rootInfo = info;
213
214 // Nothing will be connected to rootInfo
215 if (m_rootInfo) {
217 m_rootInfo->setCurrentDesktop(currentDesktop()->x11DesktopNumber());
218 for (auto *vd : std::as_const(m_desktops)) {
219 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
220 }
221 }
222}
223
225{
226 switch (direction) {
227 case Direction::Up:
228 return above(desktop, wrap);
229 case Direction::Down:
230 return below(desktop, wrap);
231 case Direction::Right:
232 return toRight(desktop, wrap);
233 case Direction::Left:
234 return toLeft(desktop, wrap);
235 case Direction::Next:
236 return next(desktop, wrap);
238 return previous(desktop, wrap);
239 }
240 Q_UNREACHABLE();
241}
242
243uint VirtualDesktopManager::inDirection(uint desktop, Direction direction, bool wrap)
244{
245 return inDirection(desktopForX11Id(desktop), direction, wrap)->x11DesktopNumber();
246}
247
248void VirtualDesktopManager::moveTo(Direction direction, bool wrap)
249{
250 setCurrent(inDirection(nullptr, direction, wrap));
251}
252
254{
255 Q_ASSERT(m_current);
256 if (!desktop) {
257 desktop = m_current;
258 }
259 QPoint coords = m_grid.gridCoords(desktop);
260 Q_ASSERT(coords.x() >= 0);
261 while (true) {
262 coords.ry()--;
263 if (coords.y() < 0) {
264 if (wrap) {
265 coords.setY(m_grid.height() - 1);
266 } else {
267 return desktop; // Already at the top-most desktop
268 }
269 }
270 if (VirtualDesktop *vd = m_grid.at(coords)) {
271 return vd;
272 }
273 }
274 return nullptr;
275}
276
278{
279 Q_ASSERT(m_current);
280 if (!desktop) {
281 desktop = m_current;
282 }
283 QPoint coords = m_grid.gridCoords(desktop);
284 Q_ASSERT(coords.x() >= 0);
285 while (true) {
286 coords.rx()++;
287 if (coords.x() >= m_grid.width()) {
288 if (wrap) {
289 coords.setX(0);
290 } else {
291 return desktop; // Already at the right-most desktop
292 }
293 }
294 if (VirtualDesktop *vd = m_grid.at(coords)) {
295 return vd;
296 }
297 }
298 return nullptr;
299}
300
302{
303 Q_ASSERT(m_current);
304 if (!desktop) {
305 desktop = m_current;
306 }
307 QPoint coords = m_grid.gridCoords(desktop);
308 Q_ASSERT(coords.x() >= 0);
309 while (true) {
310 coords.ry()++;
311 if (coords.y() >= m_grid.height()) {
312 if (wrap) {
313 coords.setY(0);
314 } else {
315 // Already at the bottom-most desktop
316 return desktop;
317 }
318 }
319 if (VirtualDesktop *vd = m_grid.at(coords)) {
320 return vd;
321 }
322 }
323 return nullptr;
324}
325
327{
328 Q_ASSERT(m_current);
329 if (!desktop) {
330 desktop = m_current;
331 }
332 QPoint coords = m_grid.gridCoords(desktop);
333 Q_ASSERT(coords.x() >= 0);
334 while (true) {
335 coords.rx()--;
336 if (coords.x() < 0) {
337 if (wrap) {
338 coords.setX(m_grid.width() - 1);
339 } else {
340 return desktop; // Already at the left-most desktop
341 }
342 }
343 if (VirtualDesktop *vd = m_grid.at(coords)) {
344 return vd;
345 }
346 }
347 return nullptr;
348}
349
351{
352 Q_ASSERT(m_current);
353 if (!desktop) {
354 desktop = m_current;
355 }
356 auto it = std::find(m_desktops.begin(), m_desktops.end(), desktop);
357 Q_ASSERT(it != m_desktops.end());
358 it++;
359 if (it == m_desktops.end()) {
360 if (wrap) {
361 return m_desktops.first();
362 } else {
363 return desktop;
364 }
365 }
366 return *it;
367}
368
370{
371 Q_ASSERT(m_current);
372 if (!desktop) {
373 desktop = m_current;
374 }
375 auto it = std::find(m_desktops.begin(), m_desktops.end(), desktop);
376 Q_ASSERT(it != m_desktops.end());
377 if (it == m_desktops.begin()) {
378 if (wrap) {
379 return m_desktops.last();
380 } else {
381 return desktop;
382 }
383 }
384 it--;
385 return *it;
386}
387
389{
390 if (id == 0 || id > count()) {
391 return nullptr;
392 }
393 return m_desktops.at(id - 1);
394}
395
397{
398 auto desk = std::find_if(
399 m_desktops.constBegin(),
400 m_desktops.constEnd(),
401 [id](const VirtualDesktop *desk) {
402 return desk->id() == id;
403 });
404
405 if (desk != m_desktops.constEnd()) {
406 return *desk;
407 }
408
409 return nullptr;
410}
411
413{
414 // too many, can't insert new ones
415 if ((uint)m_desktops.count() == VirtualDesktopManager::maximum()) {
416 return nullptr;
417 }
418
419 position = std::clamp(position, 0u, static_cast<uint>(m_desktops.count()));
420
421 QString desktopName = name;
422 if (desktopName.isEmpty()) {
423 desktopName = defaultName(position + 1);
424 }
425
426 auto *vd = new VirtualDesktop(this);
427 vd->setX11DesktopNumber(position + 1);
428 vd->setId(generateDesktopId());
429 vd->setName(desktopName);
430
431 connect(vd, &VirtualDesktop::nameChanged, this, [this, vd]() {
432 if (m_rootInfo) {
433 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
434 }
435 });
436
437 if (m_rootInfo) {
438 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
439 }
440
441 m_desktops.insert(position, vd);
442
443 // update the id of displaced desktops
444 for (uint i = position + 1; i < (uint)m_desktops.count(); ++i) {
445 m_desktops[i]->setX11DesktopNumber(i + 1);
446 if (m_rootInfo) {
447 m_rootInfo->setDesktopName(i + 1, m_desktops[i]->name().toUtf8().data());
448 }
449 }
450
451 save();
452
453 updateLayout();
455 Q_EMIT desktopAdded(vd);
456 Q_EMIT countChanged(m_desktops.count() - 1, m_desktops.count());
457 return vd;
458}
459
461{
462 auto desktop = desktopForId(id);
463 if (desktop) {
464 removeVirtualDesktop(desktop);
465 }
466}
467
469{
470 // don't end up without any desktop
471 if (m_desktops.count() == 1) {
472 return;
473 }
474
475 const int i = m_desktops.indexOf(desktop);
476 m_desktops.remove(i);
477
478 for (int j = i; j < m_desktops.count(); ++j) {
479 m_desktops[j]->setX11DesktopNumber(j + 1);
480 if (m_rootInfo) {
481 m_rootInfo->setDesktopName(j + 1, m_desktops[j]->name().toUtf8().data());
482 }
483 }
484
485 if (m_current == desktop) {
486 m_current = (i < m_desktops.count()) ? m_desktops.at(i) : m_desktops.constLast();
487 Q_EMIT currentChanged(desktop, m_current);
488 }
489
490 updateLayout();
492 save();
493
494 Q_EMIT desktopRemoved(desktop);
495 Q_EMIT countChanged(m_desktops.count() + 1, m_desktops.count());
496
497 desktop->deleteLater();
498}
499
501{
502 return m_current ? m_current->x11DesktopNumber() : 0;
503}
504
506{
507 return m_current;
508}
509
511{
512 if (newDesktop < 1 || newDesktop > count()) {
513 return false;
514 }
515 auto d = desktopForX11Id(newDesktop);
516 Q_ASSERT(d);
517 return setCurrent(d);
518}
519
521{
522 Q_ASSERT(newDesktop);
523 if (m_current == newDesktop) {
524 return false;
525 }
526 VirtualDesktop *oldDesktop = currentDesktop();
527 m_current = newDesktop;
528 Q_EMIT currentChanged(oldDesktop, newDesktop);
529 return true;
530}
531
533{
534 count = std::clamp<uint>(count, 1, VirtualDesktopManager::maximum());
535 if (count == uint(m_desktops.count())) {
536 // nothing to change
537 return;
538 }
539 QList<VirtualDesktop *> newDesktops;
540 const uint oldCount = m_desktops.count();
541 // this explicit check makes it more readable
542 if ((uint)m_desktops.count() > count) {
543 const auto desktopsToRemove = m_desktops.mid(count);
544 m_desktops.resize(count);
545 if (m_current && desktopsToRemove.contains(m_current)) {
546 VirtualDesktop *oldCurrent = m_current;
547 m_current = m_desktops.last();
548 Q_EMIT currentChanged(oldCurrent, m_current);
549 }
550 for (auto desktop : desktopsToRemove) {
551 Q_EMIT desktopRemoved(desktop);
552 desktop->deleteLater();
553 }
554 } else {
555 while (uint(m_desktops.count()) < count) {
556 auto vd = new VirtualDesktop(this);
557 const int x11Number = m_desktops.count() + 1;
558 vd->setX11DesktopNumber(x11Number);
559 vd->setName(defaultName(x11Number));
560 if (!s_loadingDesktopSettings) {
561 vd->setId(generateDesktopId());
562 }
563 m_desktops << vd;
564 newDesktops << vd;
565 connect(vd, &VirtualDesktop::nameChanged, this, [this, vd]() {
566 if (m_rootInfo) {
567 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
568 }
569 });
570 if (m_rootInfo) {
571 m_rootInfo->setDesktopName(vd->x11DesktopNumber(), vd->name().toUtf8().data());
572 }
573 }
574 }
575
576 if (!m_current) {
577 m_current = m_desktops.at(0);
578 }
579
580 updateLayout();
582
583 if (!s_loadingDesktopSettings) {
584 save();
585 }
586 for (auto vd : std::as_const(newDesktops)) {
587 Q_EMIT desktopAdded(vd);
588 }
589 Q_EMIT countChanged(oldCount, m_desktops.count());
590}
591
593{
594 return m_rows;
595}
596
598{
599 if (rows == 0 || rows > count() || rows == m_rows) {
600 return;
601 }
602
603 m_rows = rows;
604
605 updateLayout();
607}
608
610{
611 if (m_rootInfo) {
612 const int n = count();
613 m_rootInfo->setNumberOfDesktops(n);
614 NETPoint *viewports = new NETPoint[n];
615 m_rootInfo->setDesktopViewport(n, *viewports);
616 delete[] viewports;
617 m_rootInfo->setDesktopLayout(NET::OrientationHorizontal, m_grid.width(), m_grid.height(), NET::DesktopLayoutCornerTopLeft);
618 }
619}
620
622{
623 m_rows = std::min(m_rows, count());
624
625 int columns = count() / m_rows;
626 if (count() % m_rows > 0) {
627 columns++;
628 }
629
630 m_grid.update(QSize(columns, m_rows), m_desktops);
631
632 Q_EMIT layoutChanged(columns, m_rows);
633 Q_EMIT rowsChanged(m_rows);
634}
635
637{
638 s_loadingDesktopSettings = true;
639 if (!m_config) {
640 return;
641 }
642
643 KConfigGroup group(m_config, QStringLiteral("Desktops"));
644 const int n = group.readEntry("Number", 1);
645 setCount(n);
646
647 for (int i = 1; i <= n; i++) {
648 QString s = group.readEntry(QStringLiteral("Name_%1").arg(i), i18n("Desktop %1", i));
649 if (m_rootInfo) {
650 m_rootInfo->setDesktopName(i, s.toUtf8().data());
651 }
652 m_desktops[i - 1]->setName(s);
653
654 const QString sId = group.readEntry(QStringLiteral("Id_%1").arg(i), QString());
655
656 if (m_desktops[i - 1]->id().isEmpty()) {
657 m_desktops[i - 1]->setId(sId.isEmpty() ? generateDesktopId() : sId);
658 } else {
659 Q_ASSERT(sId.isEmpty() || m_desktops[i - 1]->id() == sId);
660 }
661
662 // TODO: update desktop focus chain, why?
663 // m_desktopFocusChain.value()[i-1] = i;
664 }
665
666 int rows = group.readEntry<int>("Rows", 2);
667 m_rows = std::clamp(rows, 1, n);
668
669 s_loadingDesktopSettings = false;
670}
671
673{
674 if (s_loadingDesktopSettings) {
675 return;
676 }
677 if (!m_config) {
678 return;
679 }
680 KConfigGroup group(m_config, QStringLiteral("Desktops"));
681
682 for (int i = count() + 1; group.hasKey(QStringLiteral("Id_%1").arg(i)); i++) {
683 group.deleteEntry(QStringLiteral("Id_%1").arg(i));
684 group.deleteEntry(QStringLiteral("Name_%1").arg(i));
685 }
686
687 group.writeEntry("Number", count());
688 for (VirtualDesktop *desktop : std::as_const(m_desktops)) {
689 const uint position = desktop->x11DesktopNumber();
690
691 QString s = desktop->name();
692 const QString defaultvalue = defaultName(position);
693 if (s.isEmpty()) {
694 s = defaultvalue;
695 if (m_rootInfo) {
696 m_rootInfo->setDesktopName(position, s.toUtf8().data());
697 }
698 }
699
700 if (s != defaultvalue) {
701 group.writeEntry(QStringLiteral("Name_%1").arg(position), s);
702 } else {
703 QString currentvalue = group.readEntry(QStringLiteral("Name_%1").arg(position), QString());
704 if (currentvalue != defaultvalue) {
705 group.deleteEntry(QStringLiteral("Name_%1").arg(position));
706 }
707 }
708 group.writeEntry(QStringLiteral("Id_%1").arg(position), desktop->id());
709 }
710
711 group.writeEntry("Rows", m_rows);
712
713 // Save to disk
714 group.sync();
715}
716
717QString VirtualDesktopManager::defaultName(int desktop) const
718{
719 return i18n("Desktop %1", desktop);
720}
721
723{
724 initSwitchToShortcuts();
725
726 addAction(QStringLiteral("Switch to Next Desktop"), i18n("Switch to Next Desktop"), QKeySequence(), &VirtualDesktopManager::slotNext);
727 addAction(QStringLiteral("Switch to Previous Desktop"), i18n("Switch to Previous Desktop"), QKeySequence(), &VirtualDesktopManager::slotPrevious);
728
729 // shortcuts
730 addAction(QStringLiteral("Switch One Desktop to the Right"), i18n("Switch One Desktop to the Right"), QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Right), &VirtualDesktopManager::slotRight);
731 addAction(QStringLiteral("Switch One Desktop to the Left"), i18n("Switch One Desktop to the Left"), QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Left), &VirtualDesktopManager::slotLeft);
732 addAction(QStringLiteral("Switch One Desktop Up"), i18n("Switch One Desktop Up"), QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Up), &VirtualDesktopManager::slotUp);
733 addAction(QStringLiteral("Switch One Desktop Down"), i18n("Switch One Desktop Down"), QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Down), &VirtualDesktopManager::slotDown);
734
735 // Gestures
736 // These connections decide which desktop to end on after gesture ends
737 connect(m_swipeGestureReleasedX.get(), &QAction::triggered, this, &VirtualDesktopManager::gestureReleasedX);
738 connect(m_swipeGestureReleasedY.get(), &QAction::triggered, this, &VirtualDesktopManager::gestureReleasedY);
739
740 const auto left = [this](qreal cb) {
741 if (grid().width() > 1) {
742 m_currentDesktopOffset.setX(cb);
743 Q_EMIT currentChanging(currentDesktop(), m_currentDesktopOffset);
744 }
745 };
746 const auto right = [this](qreal cb) {
747 if (grid().width() > 1) {
748 m_currentDesktopOffset.setX(-cb);
749 Q_EMIT currentChanging(currentDesktop(), m_currentDesktopOffset);
750 }
751 };
752 input()->registerTouchpadSwipeShortcut(SwipeDirection::Left, 3, m_swipeGestureReleasedX.get(), left);
753 input()->registerTouchpadSwipeShortcut(SwipeDirection::Right, 3, m_swipeGestureReleasedX.get(), right);
754 input()->registerTouchpadSwipeShortcut(SwipeDirection::Left, 4, m_swipeGestureReleasedX.get(), left);
755 input()->registerTouchpadSwipeShortcut(SwipeDirection::Right, 4, m_swipeGestureReleasedX.get(), right);
756 input()->registerTouchpadSwipeShortcut(SwipeDirection::Down, 3, m_swipeGestureReleasedY.get(), [this](qreal cb) {
757 if (grid().height() > 1) {
758 m_currentDesktopOffset.setY(-cb);
759 Q_EMIT currentChanging(currentDesktop(), m_currentDesktopOffset);
760 }
761 });
762 input()->registerTouchpadSwipeShortcut(SwipeDirection::Up, 3, m_swipeGestureReleasedY.get(), [this](qreal cb) {
763 if (grid().height() > 1) {
764 m_currentDesktopOffset.setY(cb);
765 Q_EMIT currentChanging(currentDesktop(), m_currentDesktopOffset);
766 }
767 });
768 input()->registerTouchscreenSwipeShortcut(SwipeDirection::Left, 3, m_swipeGestureReleasedX.get(), left);
769 input()->registerTouchscreenSwipeShortcut(SwipeDirection::Right, 3, m_swipeGestureReleasedX.get(), right);
770
771 // axis events
772 input()->registerAxisShortcut(Qt::MetaModifier | Qt::AltModifier, PointerAxisDown,
773 findChild<QAction *>(QStringLiteral("Switch to Next Desktop")));
774 input()->registerAxisShortcut(Qt::MetaModifier | Qt::AltModifier, PointerAxisUp,
775 findChild<QAction *>(QStringLiteral("Switch to Previous Desktop")));
776}
777
778void VirtualDesktopManager::gestureReleasedY()
779{
780 // Note that if desktop wrapping is disabled and there's no desktop above or below,
781 // above() and below() will return the current desktop.
782 VirtualDesktop *target = m_current;
783 if (m_currentDesktopOffset.y() <= -GESTURE_SWITCH_THRESHOLD) {
784 target = above(m_current, isNavigationWrappingAround());
785 } else if (m_currentDesktopOffset.y() >= GESTURE_SWITCH_THRESHOLD) {
786 target = below(m_current, isNavigationWrappingAround());
787 }
788
789 // If the current desktop has not changed, consider that the gesture has been canceled.
790 if (m_current != target) {
791 setCurrent(target);
792 } else {
793 Q_EMIT currentChangingCancelled();
794 }
795 m_currentDesktopOffset = QPointF(0, 0);
796}
797
798void VirtualDesktopManager::gestureReleasedX()
799{
800 // Note that if desktop wrapping is disabled and there's no desktop to left or right,
801 // toLeft() and toRight() will return the current desktop.
802 VirtualDesktop *target = m_current;
803 if (m_currentDesktopOffset.x() <= -GESTURE_SWITCH_THRESHOLD) {
804 target = toLeft(m_current, isNavigationWrappingAround());
805 } else if (m_currentDesktopOffset.x() >= GESTURE_SWITCH_THRESHOLD) {
806 target = toRight(m_current, isNavigationWrappingAround());
807 }
808
809 // If the current desktop has not changed, consider that the gesture has been canceled.
810 if (m_current != target) {
811 setCurrent(target);
812 } else {
813 Q_EMIT currentChangingCancelled();
814 }
815 m_currentDesktopOffset = QPointF(0, 0);
816}
817
818void VirtualDesktopManager::initSwitchToShortcuts()
819{
820 const QString toDesktop = QStringLiteral("Switch to Desktop %1");
821 const KLocalizedString toDesktopLabel = ki18n("Switch to Desktop %1");
822 addAction(toDesktop, toDesktopLabel, 1, QKeySequence(Qt::CTRL | Qt::Key_F1), &VirtualDesktopManager::slotSwitchTo);
823 addAction(toDesktop, toDesktopLabel, 2, QKeySequence(Qt::CTRL | Qt::Key_F2), &VirtualDesktopManager::slotSwitchTo);
824 addAction(toDesktop, toDesktopLabel, 3, QKeySequence(Qt::CTRL | Qt::Key_F3), &VirtualDesktopManager::slotSwitchTo);
825 addAction(toDesktop, toDesktopLabel, 4, QKeySequence(Qt::CTRL | Qt::Key_F4), &VirtualDesktopManager::slotSwitchTo);
826
827 for (uint i = 5; i <= maximum(); ++i) {
828 addAction(toDesktop, toDesktopLabel, i, QKeySequence(), &VirtualDesktopManager::slotSwitchTo);
829 }
830}
831
832QAction *VirtualDesktopManager::addAction(const QString &name, const KLocalizedString &label, uint value, const QKeySequence &key, void (VirtualDesktopManager::*slot)())
833{
834 QAction *a = new QAction(this);
835 a->setProperty("componentName", QStringLiteral("kwin"));
836 a->setObjectName(name.arg(value));
837 a->setText(label.subs(value).toString());
838 a->setData(value);
839 KGlobalAccel::setGlobalShortcut(a, key);
840 connect(a, &QAction::triggered, this, slot);
841 return a;
842}
843
844QAction *VirtualDesktopManager::addAction(const QString &name, const QString &label, const QKeySequence &key, void (VirtualDesktopManager::*slot)())
845{
846 QAction *a = new QAction(this);
847 a->setProperty("componentName", QStringLiteral("kwin"));
848 a->setObjectName(name);
849 a->setText(label);
850 KGlobalAccel::setGlobalShortcut(a, key);
851 connect(a, &QAction::triggered, this, slot);
852 return a;
853}
854
855void VirtualDesktopManager::slotSwitchTo()
856{
857 QAction *act = qobject_cast<QAction *>(sender());
858 if (!act) {
859 return;
860 }
861 bool ok = false;
862 const uint i = act->data().toUInt(&ok);
863 if (!ok) {
864 return;
865 }
866 setCurrent(i);
867}
868
870{
871 if (enabled == m_navigationWrapsAround) {
872 return;
873 }
874 m_navigationWrapsAround = enabled;
876}
877
878void VirtualDesktopManager::slotDown()
879{
881}
882
883void VirtualDesktopManager::slotLeft()
884{
886}
887
888void VirtualDesktopManager::slotPrevious()
889{
891}
892
893void VirtualDesktopManager::slotNext()
894{
896}
897
898void VirtualDesktopManager::slotRight()
899{
901}
902
903void VirtualDesktopManager::slotUp()
904{
906}
907
908} // KWin
909
910#include "moc_virtualdesktops.cpp"
void registerTouchscreenSwipeShortcut(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function< void(qreal)> progressCallback={})
void registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action)
void registerTouchpadSwipeShortcut(SwipeDirection direction, uint32_t fingerCount, QAction *onUp, std::function< void(qreal)> progressCallback={})
Wrapper for the org_kde_plasma_virtual_desktop_management interface.
QList< PlasmaVirtualDesktopInterface * > desktops() const
PlasmaVirtualDesktopInterface * createDesktop(const QString &id, quint32 position=std::numeric_limits< uint32_t >::max())
void desktopCreateRequested(const QString &name, quint32 position)
void desktopRemoveRequested(const QString &id)
void update(const QSize &size, const QList< VirtualDesktop * > &desktops)
QPoint gridCoords(uint id) const
VirtualDesktop * at(const QPoint &coords) const
const QSize & size() const
void setId(const QString &id)
void x11DesktopNumberChanged()
void setX11DesktopNumber(uint number)
void setName(const QString &name)
VirtualDesktop(QObject *parent=nullptr)
Manages the number of available virtual desktops, the layout of those and which virtual desktop is th...
VirtualDesktop * previous(VirtualDesktop *desktop=nullptr, bool wrap=true) const
const VirtualDesktopGrid & grid() const
void moveTo(bool wrap=false)
void layoutChanged(int columns, int rows)
void setRootInfo(NETRootInfo *info)
void removeVirtualDesktop(const QString &id)
void setVirtualDesktopManagement(PlasmaVirtualDesktopManagementInterface *management)
VirtualDesktop * desktopForId(const QString &id) const
VirtualDesktop * above(VirtualDesktop *desktop, bool wrap=true) const
void desktopAdded(KWin::VirtualDesktop *desktop)
VirtualDesktop * createVirtualDesktop(uint position, const QString &name=QString())
void countChanged(uint previousCount, uint newCount)
void currentChanging(KWin::VirtualDesktop *currentDesktop, QPointF offset)
VirtualDesktop * inDirection(VirtualDesktop *desktop, Direction direction, bool wrap=true)
VirtualDesktop * currentDesktop() const
void currentChanged(KWin::VirtualDesktop *previousDesktop, KWin::VirtualDesktop *newDesktop)
VirtualDesktop * below(VirtualDesktop *desktop, bool wrap=true) const
VirtualDesktop * desktopForX11Id(uint id) const
VirtualDesktop * toRight(VirtualDesktop *desktop, bool wrap=true) const
void rowsChanged(uint rows)
VirtualDesktop * toLeft(VirtualDesktop *desktop, bool wrap=true) const
VirtualDesktop * next(VirtualDesktop *desktop=nullptr, bool wrap=true) const
void setNavigationWrappingAround(bool enabled)
void desktopRemoved(KWin::VirtualDesktop *desktop)
#define KWIN_SINGLETON_FACTORY_VARIABLE(ClassName, variableName)
Definition globals.h:333
InputRedirection * input()
Definition input.h:549