1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 #ifndef KWIN_VIRTUAL_DESKTOPS_H
10 #define KWIN_VIRTUAL_DESKTOPS_H
11 // KWin
12 #include <kwinglobals.h>
13 #include <kwin_export.h>
14 // Qt includes
15 #include <QObject>
16 #include <QPoint>
17 #include <QPointer>
18 #include <QSize>
19 
20 // KDE includes
21 #include <KConfig>
22 #include <KSharedConfig>
23 
24 class KLocalizedString;
25 class NETRootInfo;
26 class QAction;
27 
28 namespace KWaylandServer
29 {
30 class PlasmaVirtualDesktopManagementInterface;
31 }
32 
33 namespace KWin {
34 
35 class KWIN_EXPORT VirtualDesktop : public QObject
36 {
37     Q_OBJECT
38     Q_PROPERTY(QString id READ id CONSTANT)
39     Q_PROPERTY(uint x11DesktopNumber READ x11DesktopNumber NOTIFY x11DesktopNumberChanged)
40     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
41 public:
42     explicit VirtualDesktop(QObject *parent = nullptr);
43     ~VirtualDesktop() override;
44 
45     void setId(const QString &id);
id()46     QString id() const {
47         return m_id;
48     }
49 
50     void setName(const QString &name);
name()51     QString name() const {
52         return m_name;
53     }
54 
55     void setX11DesktopNumber(uint number);
x11DesktopNumber()56     uint x11DesktopNumber() const {
57         return m_x11DesktopNumber;
58     }
59 
60 Q_SIGNALS:
61     void nameChanged();
62     void x11DesktopNumberChanged();
63     /**
64      * Emitted just before the desktop gets destroyed.
65      */
66     void aboutToBeDestroyed();
67 
68 private:
69     QString m_id;
70     QString m_name;
71     int m_x11DesktopNumber = 0;
72 
73 };
74 
75 /**
76  * @brief Two dimensional grid containing the ID of the virtual desktop at a specific position
77  * in the grid.
78  *
79  * The VirtualDesktopGrid represents a visual layout of the Virtual Desktops as they are in e.g.
80  * a Pager. This grid is used for getting a desktop next to a given desktop in any direction by
81  * making use of the layout information. This allows navigation like move to desktop on left.
82  */
83 class VirtualDesktopGrid
84 {
85 public:
86     VirtualDesktopGrid();
87     ~VirtualDesktopGrid();
88     void update(const QSize &size, Qt::Orientation orientation, const QVector<VirtualDesktop*> &desktops);
89     /**
90      * @returns The coords of desktop @a id in grid units.
91      */
92     QPoint gridCoords(uint id) const;
93     /**
94      * @returns The coords of desktop @a vd in grid units.
95      */
96     QPoint gridCoords(VirtualDesktop *vd) const;
97     /**
98      * @returns The desktop at the point @a coords or 0 if no desktop exists at that
99      * point. @a coords is to be in grid units.
100      */
101     VirtualDesktop *at(const QPoint &coords) const;
102     int width() const;
103     int height() const;
104     const QSize &size() const;
105 private:
106     QSize m_size;
107     QVector<QVector<VirtualDesktop*>> m_grid;
108 };
109 
110 /**
111  * @brief Manages the number of available virtual desktops, the layout of those and which virtual
112  * desktop is the current one.
113  *
114  * This manager is responsible for Virtual Desktop handling inside KWin. It has a property for the
115  * count of available virtual desktops and a property for the currently active virtual desktop. All
116  * changes to the number of virtual desktops and the current virtual desktop need to go through this
117  * manager.
118  *
119  * On all changes a signal is emitted and interested parties should connect to the signal. The manager
120  * itself does not interact with other parts of the system. E.g. it does not hide/show windows of
121  * desktop changes. This is outside the scope of this manager.
122  *
123  * Internally the manager organizes the virtual desktops in a grid allowing to navigate over the
124  * virtual desktops. For this a set of convenient methods are available which allow to get the id
125  * of an adjacent desktop or to switch to an adjacent desktop. Interested parties should make use of
126  * these methods and not replicate the logic to switch to the next desktop.
127  */
128 class KWIN_EXPORT VirtualDesktopManager : public QObject
129 {
130     Q_OBJECT
131     /**
132      * The number of virtual desktops currently available.
133      * The ids of the virtual desktops are in the range [1, VirtualDesktopManager::maximum()].
134      */
135     Q_PROPERTY(uint count READ count WRITE setCount NOTIFY countChanged)
136     /**
137      * The id of the virtual desktop which is currently in use.
138      */
139     Q_PROPERTY(uint current READ current WRITE setCurrent NOTIFY currentChanged)
140     /**
141      * Whether navigation in the desktop layout wraps around at the borders.
142      */
143     Q_PROPERTY(bool navigationWrappingAround READ isNavigationWrappingAround WRITE setNavigationWrappingAround NOTIFY navigationWrappingAroundChanged)
144 public:
145     ~VirtualDesktopManager() override;
146     /**
147      * @internal, for X11 case
148      */
149     void setRootInfo(NETRootInfo *info);
150     /**
151      * @internal, for Wayland case
152      */
153     void setVirtualDesktopManagement(KWaylandServer::PlasmaVirtualDesktopManagementInterface *management);
154     /**
155      * @internal
156      */
157     void setConfig(KSharedConfig::Ptr config);
158     /**
159      * @returns Total number of desktops currently in existence.
160      * @see setCount
161      * @see countChanged
162      */
163     uint count() const;
164     /**
165      * @returns the number of rows the layout has.
166      * @see setRows
167      * @see rowsChanged
168      */
169     uint rows() const;
170     /**
171      * @returns The ID of the current desktop.
172      * @see setCurrent
173      * @see currentChanged
174      */
175     uint current() const;
176     /**
177      * @returns The current desktop
178      * @see setCurrent
179      * @see currentChanged
180      */
181     VirtualDesktop *currentDesktop() const;
182     /**
183      * Moves to the desktop through the algorithm described by Direction.
184      * @param wrap If @c true wraps around to the other side of the layout
185      * @see setCurrent
186      */
187     template <typename Direction>
188     void moveTo(bool wrap = false);
189 
190     /**
191      * @returns @c true if navigation at borders of layout wraps around, @c false otherwise
192      * @see setNavigationWrappingAround
193      * @see navigationWrappingAroundChanged
194      */
195     bool isNavigationWrappingAround() const;
196 
197     /**
198      * @returns The layout aware virtual desktop grid used by this manager.
199      */
200     const VirtualDesktopGrid &grid() const;
201 
202     /**
203      * @returns The ID of the desktop above desktop @a id. Wraps around to the bottom of
204      * the layout if @a wrap is set. If @a id is not set use the current one.
205      */
206     uint above(uint id = 0, bool wrap = true) const;
207     /**
208      * @returns The desktop above desktop @a desktop. Wraps around to the bottom of
209      * the layout if @a wrap is set. If @a desktop is @c null use the current one.
210      */
211     VirtualDesktop *above(VirtualDesktop *desktop, bool wrap = true) const;
212     /**
213      * @returns The ID of the desktop to the right of desktop @a id. Wraps around to the
214      * left of the layout if @a wrap is set. If @a id is not set use the current one.
215      */
216     uint toRight(uint id = 0, bool wrap = true) const;
217     /**
218      * @returns The desktop to the right of desktop @a desktop. Wraps around to the
219      * left of the layout if @a wrap is set. If @a desktop is @c null use the current one.
220      */
221     VirtualDesktop *toRight(VirtualDesktop *desktop, bool wrap = true) const;
222     /**
223      * @returns The ID of the desktop below desktop @a id. Wraps around to the top of the
224      * layout if @a wrap is set. If @a id is not set use the current one.
225      */
226     uint below(uint id = 0, bool wrap = true) const;
227     /**
228      * @returns The desktop below desktop @a desktop. Wraps around to the top of the
229      * layout if @a wrap is set. If @a desktop is @c null use the current one.
230      */
231     VirtualDesktop *below(VirtualDesktop *desktop, bool wrap = true) const;
232     /**
233      * @returns The ID of the desktop to the left of desktop @a id. Wraps around to the
234      * right of the layout if @a wrap is set. If @a id is not set use the current one.
235      */
236     uint toLeft(uint id = 0, bool wrap = true) const;
237     /**
238      * @returns The desktop to the left of desktop @a desktop. Wraps around to the
239      * right of the layout if @a wrap is set. If @a desktop is @c null use the current one.
240      */
241     VirtualDesktop *toLeft(VirtualDesktop *desktop, bool wrap = true) const;
242     /**
243      * @returns The desktop after the desktop @a desktop. Wraps around to the first
244      * desktop if @a wrap is set. If @a desktop is @c null use the current desktop.
245      */
246     VirtualDesktop *next(VirtualDesktop *desktop = nullptr, bool wrap = true) const;
247     /**
248      * @returns The desktop in front of the desktop @a desktop. Wraps around to the
249      * last desktop if @a wrap is set. If @a desktop is @c null use the current desktop.
250      */
251     VirtualDesktop *previous(VirtualDesktop *desktop = nullptr, bool wrap = true) const;
252 
253     void initShortcuts();
254 
255     /**
256      * @returns all currently managed VirtualDesktops
257      */
desktops()258     QVector<VirtualDesktop*> desktops() const {
259         return m_desktops;
260     }
261 
262     /**
263      * @returns The VirtualDesktop for the x11 @p id, if no such VirtualDesktop @c null is returned
264      */
265     VirtualDesktop *desktopForX11Id(uint id) const;
266 
267     /**
268      * @returns The VirtualDesktop for the internal desktop string @p id, if no such VirtualDesktop @c null is returned
269      */
270     VirtualDesktop *desktopForId(const QString &id) const;
271 
272     /**
273      * Create a new virtual desktop at the requested position.
274      * The difference with setCount is that setCount always adds new desktops at the end of the chain. The Id is automatically generated.
275      * @param position The position of the desktop. It should be in range [0, count].
276      * @param name The name for the new desktop, if empty the default name will be used.
277      * @returns the new VirtualDesktop, nullptr if we reached the maximum number of desktops
278      */
279      VirtualDesktop *createVirtualDesktop(uint position, const QString &name = QString());
280 
281     /**
282      * Remove the virtual desktop identified by id, if it exists
283      * difference with setCount is that is possible to remove an arbitrary desktop,
284      * not only the last one.
285      * @param id the string id of the desktop to remove
286      */
287     void removeVirtualDesktop(const QString &id);
288 
289     /**
290      * Updates the net root info for new number of desktops
291      */
292     void updateRootInfo();
293 
294     /**
295      * @returns The maximum number of desktops that KWin supports.
296      */
297     static uint maximum();
298 
299 public Q_SLOTS:
300     /**
301      * Set the number of available desktops to @a count. This function overrides any previous
302      * grid layout.
303      * There needs to be at least one virtual desktop and the new value is capped at the maximum
304      * number of desktops. A caller of this function cannot expect that the change has been applied.
305      * It is the callers responsibility to either check the numberOfDesktops or connect to the
306      * countChanged signal.
307      *
308      * In case the @ref current desktop is on a desktop higher than the new count, the current desktop
309      * is changed to be the new desktop with highest id. In that situation the signal desktopRemoved
310      * is emitted.
311      * @param count The new number of desktops to use
312      * @see count
313      * @see maximum
314      * @see countChanged
315      * @see desktopCreated
316      * @see desktopRemoved
317      */
318     void setCount(uint count);
319     /**
320      * Set the current desktop to @a current.
321      * @returns True on success, false otherwise.
322      * @see current
323      * @see currentChanged
324      * @see moveTo
325      */
326     bool setCurrent(uint current);
327     /**
328      * Set the current desktop to @a current.
329      * @returns True on success, false otherwise.
330      * @see current
331      * @see currentChanged
332      * @see moveTo
333      */
334     bool setCurrent(VirtualDesktop *current);
335     /**
336      * Updates the layout to a new number of rows. The number of columns will be calculated accordingly
337      */
338     void setRows(uint rows);
339     /**
340      * Called from within setCount() to ensure the desktop layout is still valid.
341      */
342     void updateLayout();
343     /**
344      * @param enabled wrapping around borders for navigation in desktop layout
345      * @see isNavigationWrappingAround
346      * @see navigationWrappingAroundChanged
347      */
348     void setNavigationWrappingAround(bool enabled);
349     /**
350      * Loads number of desktops and names from configuration file
351      */
352     void load();
353     /**
354      * Saves number of desktops and names to configuration file
355      */
356     void save();
357 
358 Q_SIGNALS:
359     /**
360      * Signal emitted whenever the number of virtual desktops changes.
361      * @param previousCount The number of desktops prior to the change
362      * @param newCount The new current number of desktops
363      */
364     void countChanged(uint previousCount, uint newCount);
365 
366     /**
367      * Signal when the number of rows in the layout changes
368      * @param rows number of rows
369      */
370     void rowsChanged(uint rows);
371 
372     /**
373      * A new desktop has been created
374      * @param desktop the new just crated desktop
375      */
376     void desktopCreated(KWin::VirtualDesktop *desktop);
377 
378     /**
379      * A desktop has been removed and is about to be deleted
380      * @param desktop the desktop that has been removed.
381      *          It's guaranteed to stil la valid pointer when the signal arrives,
382      *          but it's about to be deleted.
383      */
384     void desktopRemoved(KWin::VirtualDesktop *desktop);
385 
386     /**
387      * Signal emitted whenever the current desktop changes.
388      * @param previousDesktop The virtual desktop changed from
389      * @param newDesktop The virtual desktop changed to
390      */
391     void currentChanged(uint previousDesktop, uint newDesktop);
392     /**
393      * Signal emitted whenever the desktop layout changes.
394      * @param columns The new number of columns in the layout
395      * @param rows The new number of rows in the layout
396      */
397     void layoutChanged(int columns, int rows);
398     /**
399      * Signal emitted whenever the navigationWrappingAround property changes.
400      */
401     void navigationWrappingAroundChanged();
402 
403 private Q_SLOTS:
404     /**
405      * Common slot for all "Switch to Desktop n" shortcuts.
406      * This method uses the sender() method to access some data.
407      * DO NOT CALL DIRECTLY! ONLY TO BE USED FROM AN ACTION!
408      */
409     void slotSwitchTo();
410     /**
411      * Slot for switch to next desktop action.
412      */
413     void slotNext();
414     /**
415      * Slot for switch to previous desktop action.
416      */
417     void slotPrevious();
418     /**
419      * Slot for switch to right desktop action.
420      */
421     void slotRight();
422     /**
423      * Slot for switch to left desktop action.
424      */
425     void slotLeft();
426     /**
427      * Slot for switch to desktop above action.
428      */
429     void slotUp();
430     /**
431      * Slot for switch to desktop below action.
432      */
433     void slotDown();
434 
435 private:
436     /**
437      * Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters.
438      */
439     void setNETDesktopLayout(Qt::Orientation orientation, uint width, uint height, int startingCorner);
440     /**
441      * @returns A default name for the given @p desktop
442      */
443     QString defaultName(int desktop) const;
444     /**
445      * Creates all the global keyboard shortcuts for "Switch To Desktop n" actions.
446      */
447     void initSwitchToShortcuts();
448     /**
449      * Creates an action and connects it to the @p slot in this Manager. This method is
450      * meant to be used for the case that an additional information needs to be stored in
451      * the action and the label.
452      * @param name The name of the action to be created
453      * @param label The localized name for the action to be created
454      * @param value An additional value added to the label and to the created action
455      * @param key The global shortcut for the action
456      * @param slot The slot to invoke when the action is triggered
457      */
458     QAction *addAction(const QString &name, const KLocalizedString &label, uint value, const QKeySequence &key, void (VirtualDesktopManager::*slot)());
459     /**
460      * Creates an action and connects it to the @p slot in this Manager.
461      * Overloaded method for the case that no additional value needs to be passed to the action and
462      * no global shortcut is defined by default.
463      * @param name The name of the action to be created
464      * @param label The localized name for the action to be created
465      * @param slot The slot to invoke when the action is triggered
466      */
467     QAction *addAction(const QString &name, const QString &label, void (VirtualDesktopManager::*slot)());
468 
469     QVector<VirtualDesktop*> m_desktops;
470     QPointer<VirtualDesktop> m_current;
471     quint32 m_rows = 2;
472     bool m_navigationWrapsAround;
473     VirtualDesktopGrid m_grid;
474     // TODO: QPointer
475     NETRootInfo *m_rootInfo;
476     KWaylandServer::PlasmaVirtualDesktopManagementInterface *m_virtualDesktopManagement = nullptr;
477     KSharedConfig::Ptr m_config;
478 
479     KWIN_SINGLETON_VARIABLE(VirtualDesktopManager, s_manager)
480 };
481 
482 /**
483  * Function object to select the desktop above in the layout.
484  * Note: does not switch to the desktop!
485  */
486 class DesktopAbove
487 {
488 public:
DesktopAbove()489     DesktopAbove() {}
490     /**
491      * @param desktop The desktop from which the desktop above should be selected. If @c 0 the current desktop is used
492      * @param wrap Whether to wrap around if already topmost desktop
493      * @returns Id of the desktop above @p desktop
494      */
operator()495     uint operator() (uint desktop, bool wrap) {
496         return (*this)(VirtualDesktopManager::self()->desktopForX11Id(desktop), wrap)->x11DesktopNumber();
497     }
498     /**
499      * @param desktop The desktop from which the desktop above should be selected. If @c 0 the current desktop is used
500      * @param wrap Whether to wrap around if already topmost desktop
501      * @returns the desktop above @p desktop
502      */
operator()503     VirtualDesktop *operator() (VirtualDesktop *desktop, bool wrap) {
504         return VirtualDesktopManager::self()->above(desktop, wrap);
505     }
506 };
507 
508 /**
509  * Function object to select the desktop below in the layout.
510  * Note: does not switch to the desktop!
511  */
512 class DesktopBelow
513 {
514 public:
DesktopBelow()515     DesktopBelow() {}
516     /**
517      * @param desktop The desktop from which the desktop below should be selected. If @c 0 the current desktop is used
518      * @param wrap Whether to wrap around if already lowest desktop
519      * @returns Id of the desktop below @p desktop
520      */
operator()521     uint operator() (uint desktop, bool wrap) {
522         return (*this)(VirtualDesktopManager::self()->desktopForX11Id(desktop), wrap)->x11DesktopNumber();
523     }
524     /**
525      * @param desktop The desktop from which the desktop below should be selected. If @c 0 the current desktop is used
526      * @param wrap Whether to wrap around if already lowest desktop
527      * @returns the desktop below @p desktop
528      */
operator()529     VirtualDesktop *operator() (VirtualDesktop *desktop, bool wrap) {
530         return VirtualDesktopManager::self()->below(desktop, wrap);
531     }
532 };
533 
534 /**
535  * Function object to select the desktop to the left in the layout.
536  * Note: does not switch to the desktop!
537  */
538 class DesktopLeft
539 {
540 public:
DesktopLeft()541     DesktopLeft() {}
542     /**
543      * @param desktop The desktop from which the desktop on the left should be selected. If @c 0 the current desktop is used
544      * @param wrap Whether to wrap around if already leftmost desktop
545      * @returns Id of the desktop left of @p desktop
546      */
operator()547     uint operator() (uint desktop, bool wrap) {
548         return (*this)(VirtualDesktopManager::self()->desktopForX11Id(desktop), wrap)->x11DesktopNumber();
549     }
550     /**
551      * @param desktop The desktop from which the desktop on the left should be selected. If @c 0 the current desktop is used
552      * @param wrap Whether to wrap around if already leftmost desktop
553      * @returns the desktop left of @p desktop
554      */
operator()555     VirtualDesktop *operator() (VirtualDesktop *desktop, bool wrap) {
556         return VirtualDesktopManager::self()->toLeft(desktop, wrap);
557     }
558 };
559 
560 /**
561  * Function object to select the desktop to the right in the layout.
562  * Note: does not switch to the desktop!
563  */
564 class DesktopRight
565 {
566 public:
DesktopRight()567     DesktopRight() {}
568     /**
569      * @param desktop The desktop from which the desktop on the right should be selected. If @c 0 the current desktop is used
570      * @param wrap Whether to wrap around if already rightmost desktop
571      * @returns Id of the desktop right of @p desktop
572      */
operator()573     uint operator() (uint desktop, bool wrap) {
574         return (*this)(VirtualDesktopManager::self()->desktopForX11Id(desktop), wrap)->x11DesktopNumber();
575     }
576     /**
577      * @param desktop The desktop from which the desktop on the right should be selected. If @c 0 the current desktop is used
578      * @param wrap Whether to wrap around if already rightmost desktop
579      * @returns the desktop right of @p desktop
580      */
operator()581     VirtualDesktop *operator() (VirtualDesktop *desktop, bool wrap) {
582         return VirtualDesktopManager::self()->toRight(desktop, wrap);
583     }
584 };
585 
586 /**
587  * Function object to select the next desktop in the layout.
588  * Note: does not switch to the desktop!
589  */
590 class DesktopNext
591 {
592 public:
DesktopNext()593     DesktopNext() {}
594     /**
595      * @param desktop The desktop from which the next desktop should be selected. If @c 0 the current desktop is used
596      * @param wrap Whether to wrap around if already last desktop
597      * @returns Id of the next desktop
598      */
operator()599     uint operator() (uint desktop, bool wrap) {
600         return (*this)(VirtualDesktopManager::self()->desktopForX11Id(desktop), wrap)->x11DesktopNumber();
601     }
602     /**
603      * @param desktop The desktop from which the next desktop should be selected. If @c 0 the current desktop is used
604      * @param wrap Whether to wrap around if already last desktop
605      * @returns the next desktop
606      */
operator()607     VirtualDesktop *operator() (VirtualDesktop *desktop, bool wrap) {
608         return VirtualDesktopManager::self()->next(desktop, wrap);
609     }
610 };
611 
612 /**
613  * Function object to select the previous desktop in the layout.
614  * Note: does not switch to the desktop!
615  */
616 class DesktopPrevious
617 {
618 public:
DesktopPrevious()619     DesktopPrevious() {}
620     /**
621      * @param desktop The desktop from which the previous desktop should be selected. If @c 0 the current desktop is used
622      * @param wrap Whether to wrap around if already first desktop
623      * @returns Id of the previous desktop
624      */
operator()625     uint operator() (uint desktop, bool wrap) {
626         return (*this)(VirtualDesktopManager::self()->desktopForX11Id(desktop), wrap)->x11DesktopNumber();
627     }
628     /**
629      * @param desktop The desktop from which the previous desktop should be selected. If @c 0 the current desktop is used
630      * @param wrap Whether to wrap around if already first desktop
631      * @returns the previous desktop
632      */
operator()633     VirtualDesktop *operator() (VirtualDesktop *desktop, bool wrap) {
634         return VirtualDesktopManager::self()->previous(desktop, wrap);
635     }
636 };
637 
638 /**
639  * Helper function to get the ID of a virtual desktop in the direction from
640  * the given @p desktop. If @c 0 the current desktop is used as a starting point.
641  * @param desktop The desktop from which the desktop in given Direction should be selected.
642  * @param wrap Whether desktop navigation wraps around at the borders of the layout
643  * @returns The next desktop in specified direction
644  */
645 template <typename Direction>
646 uint getDesktop(int desktop = 0, bool wrap = true);
647 
648 template <typename Direction>
getDesktop(int d,bool wrap)649 uint getDesktop(int d, bool wrap)
650 {
651     Direction direction;
652     return direction(d, wrap);
653 }
654 
655 inline
width()656 int VirtualDesktopGrid::width() const
657 {
658     return m_size.width();
659 }
660 
661 inline
height()662 int VirtualDesktopGrid::height() const
663 {
664     return m_size.height();
665 }
666 
667 inline
size()668 const QSize &VirtualDesktopGrid::size() const
669 {
670     return m_size;
671 }
672 
673 inline
maximum()674 uint VirtualDesktopManager::maximum()
675 {
676     return 20;
677 }
678 
679 inline
count()680 uint VirtualDesktopManager::count() const
681 {
682     return m_desktops.count();
683 }
684 
685 inline
isNavigationWrappingAround()686 bool VirtualDesktopManager::isNavigationWrappingAround() const
687 {
688     return m_navigationWrapsAround;
689 }
690 
691 inline
setConfig(KSharedConfig::Ptr config)692 void VirtualDesktopManager::setConfig(KSharedConfig::Ptr config)
693 {
694     m_config = std::move(config);
695 }
696 
697 inline
grid()698 const VirtualDesktopGrid &VirtualDesktopManager::grid() const
699 {
700     return m_grid;
701 }
702 
703 template <typename Direction>
moveTo(bool wrap)704 void VirtualDesktopManager::moveTo(bool wrap)
705 {
706     Direction functor;
707     setCurrent(functor(nullptr, wrap));
708 }
709 
710 } // namespace KWin
711 #endif
712