File indexing completed on 2024-04-28 16:49:04

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #pragma once
0010 // KWin
0011 #include <kwin_export.h>
0012 #include <kwinglobals.h>
0013 // Qt includes
0014 #include <QAction>
0015 #include <QObject>
0016 #include <QPoint>
0017 #include <QPointer>
0018 #include <QSize>
0019 
0020 // KDE includes
0021 #include <KConfig>
0022 #include <KSharedConfig>
0023 
0024 class KLocalizedString;
0025 class NETRootInfo;
0026 class QAction;
0027 class Options;
0028 
0029 namespace KWaylandServer
0030 {
0031 class PlasmaVirtualDesktopManagementInterface;
0032 }
0033 
0034 namespace KWin
0035 {
0036 
0037 class KWIN_EXPORT VirtualDesktop : public QObject
0038 {
0039     Q_OBJECT
0040     Q_PROPERTY(QString id READ id CONSTANT)
0041     Q_PROPERTY(uint x11DesktopNumber READ x11DesktopNumber NOTIFY x11DesktopNumberChanged)
0042     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
0043 public:
0044     explicit VirtualDesktop(QObject *parent = nullptr);
0045     ~VirtualDesktop() override;
0046 
0047     void setId(const QString &id);
0048     QString id() const
0049     {
0050         return m_id;
0051     }
0052 
0053     void setName(const QString &name);
0054     QString name() const
0055     {
0056         return m_name;
0057     }
0058 
0059     void setX11DesktopNumber(uint number);
0060     uint x11DesktopNumber() const
0061     {
0062         return m_x11DesktopNumber;
0063     }
0064 
0065 Q_SIGNALS:
0066     void nameChanged();
0067     void x11DesktopNumberChanged();
0068     /**
0069      * Emitted just before the desktop gets destroyed.
0070      */
0071     void aboutToBeDestroyed();
0072 
0073 private:
0074     QString m_id;
0075     QString m_name;
0076     int m_x11DesktopNumber = 0;
0077 };
0078 
0079 /**
0080  * @brief Two dimensional grid containing the ID of the virtual desktop at a specific position
0081  * in the grid.
0082  *
0083  * The VirtualDesktopGrid represents a visual layout of the Virtual Desktops as they are in e.g.
0084  * a Pager. This grid is used for getting a desktop next to a given desktop in any direction by
0085  * making use of the layout information. This allows navigation like move to desktop on left.
0086  */
0087 class VirtualDesktopGrid
0088 {
0089 public:
0090     VirtualDesktopGrid();
0091     ~VirtualDesktopGrid();
0092     void update(const QSize &size, Qt::Orientation orientation, const QVector<VirtualDesktop *> &desktops);
0093     /**
0094      * @returns The coords of desktop @a id in grid units.
0095      */
0096     QPoint gridCoords(uint id) const;
0097     /**
0098      * @returns The coords of desktop @a vd in grid units.
0099      */
0100     QPoint gridCoords(VirtualDesktop *vd) const;
0101     /**
0102      * @returns The desktop at the point @a coords or 0 if no desktop exists at that
0103      * point. @a coords is to be in grid units.
0104      */
0105     VirtualDesktop *at(const QPoint &coords) const;
0106     int width() const;
0107     int height() const;
0108     const QSize &size() const;
0109 
0110 private:
0111     QSize m_size;
0112     QVector<QVector<VirtualDesktop *>> m_grid;
0113 };
0114 
0115 /**
0116  * @brief Manages the number of available virtual desktops, the layout of those and which virtual
0117  * desktop is the current one.
0118  *
0119  * This manager is responsible for Virtual Desktop handling inside KWin. It has a property for the
0120  * count of available virtual desktops and a property for the currently active virtual desktop. All
0121  * changes to the number of virtual desktops and the current virtual desktop need to go through this
0122  * manager.
0123  *
0124  * On all changes a signal is emitted and interested parties should connect to the signal. The manager
0125  * itself does not interact with other parts of the system. E.g. it does not hide/show windows of
0126  * desktop changes. This is outside the scope of this manager.
0127  *
0128  * Internally the manager organizes the virtual desktops in a grid allowing to navigate over the
0129  * virtual desktops. For this a set of convenient methods are available which allow to get the id
0130  * of an adjacent desktop or to switch to an adjacent desktop. Interested parties should make use of
0131  * these methods and not replicate the logic to switch to the next desktop.
0132  */
0133 class KWIN_EXPORT VirtualDesktopManager : public QObject
0134 {
0135     Q_OBJECT
0136     /**
0137      * The number of virtual desktops currently available.
0138      * The ids of the virtual desktops are in the range [1, VirtualDesktopManager::maximum()].
0139      */
0140     Q_PROPERTY(uint count READ count WRITE setCount NOTIFY countChanged)
0141     /**
0142      * The id of the virtual desktop which is currently in use.
0143      */
0144     Q_PROPERTY(uint current READ current WRITE setCurrent NOTIFY currentChanged)
0145     /**
0146      * Whether navigation in the desktop layout wraps around at the borders.
0147      */
0148     Q_PROPERTY(bool navigationWrappingAround READ isNavigationWrappingAround WRITE setNavigationWrappingAround NOTIFY navigationWrappingAroundChanged)
0149 public:
0150     ~VirtualDesktopManager() override;
0151     /**
0152      * @internal, for X11 case
0153      */
0154     void setRootInfo(NETRootInfo *info);
0155     /**
0156      * @internal, for Wayland case
0157      */
0158     void setVirtualDesktopManagement(KWaylandServer::PlasmaVirtualDesktopManagementInterface *management);
0159     /**
0160      * @internal
0161      */
0162     void setConfig(KSharedConfig::Ptr config);
0163     /**
0164      * @returns Total number of desktops currently in existence.
0165      * @see setCount
0166      * @see countChanged
0167      */
0168     uint count() const;
0169     /**
0170      * @returns the number of rows the layout has.
0171      * @see setRows
0172      * @see rowsChanged
0173      */
0174     uint rows() const;
0175     /**
0176      * @returns The ID of the current desktop.
0177      * @see setCurrent
0178      * @see currentChanged
0179      */
0180     uint current() const;
0181     /**
0182      * @returns The current desktop
0183      * @see setCurrent
0184      * @see currentChanged
0185      */
0186     VirtualDesktop *currentDesktop() const;
0187     /**
0188      * Moves to the desktop through the algorithm described by Direction.
0189      * @param wrap If @c true wraps around to the other side of the layout
0190      * @see setCurrent
0191      */
0192     template<typename Direction>
0193     void moveTo(bool wrap = false);
0194 
0195     /**
0196      * @returns @c true if navigation at borders of layout wraps around, @c false otherwise
0197      * @see setNavigationWrappingAround
0198      * @see navigationWrappingAroundChanged
0199      */
0200     bool isNavigationWrappingAround() const;
0201 
0202     /**
0203      * @returns The layout aware virtual desktop grid used by this manager.
0204      */
0205     const VirtualDesktopGrid &grid() const;
0206 
0207     enum class Direction {
0208         Up,
0209         Down,
0210         Right,
0211         Left,
0212         Next,
0213         Previous
0214     };
0215     VirtualDesktop *inDirection(VirtualDesktop *desktop, Direction direction, bool wrap = true);
0216     uint inDirection(uint desktop, Direction direction, bool wrap = true);
0217     void moveTo(Direction direction, bool wrap = true);
0218 
0219     /**
0220      * @returns The desktop above desktop @a desktop. Wraps around to the bottom of
0221      * the layout if @a wrap is set. If @a desktop is @c null use the current one.
0222      */
0223     VirtualDesktop *above(VirtualDesktop *desktop, bool wrap = true) const;
0224     /**
0225      * @returns The desktop to the right of desktop @a desktop. Wraps around to the
0226      * left of the layout if @a wrap is set. If @a desktop is @c null use the current one.
0227      */
0228     VirtualDesktop *toRight(VirtualDesktop *desktop, bool wrap = true) const;
0229     /**
0230      * @returns The desktop below desktop @a desktop. Wraps around to the top of the
0231      * layout if @a wrap is set. If @a desktop is @c null use the current one.
0232      */
0233     VirtualDesktop *below(VirtualDesktop *desktop, bool wrap = true) const;
0234     /**
0235      * @returns The desktop to the left of desktop @a desktop. Wraps around to the
0236      * right of the layout if @a wrap is set. If @a desktop is @c null use the current one.
0237      */
0238     VirtualDesktop *toLeft(VirtualDesktop *desktop, bool wrap = true) const;
0239     /**
0240      * @returns The desktop after the desktop @a desktop. Wraps around to the first
0241      * desktop if @a wrap is set. If @a desktop is @c null use the current desktop.
0242      */
0243     VirtualDesktop *next(VirtualDesktop *desktop = nullptr, bool wrap = true) const;
0244     /**
0245      * @returns The desktop in front of the desktop @a desktop. Wraps around to the
0246      * last desktop if @a wrap is set. If @a desktop is @c null use the current desktop.
0247      */
0248     VirtualDesktop *previous(VirtualDesktop *desktop = nullptr, bool wrap = true) const;
0249 
0250     void initShortcuts();
0251 
0252     /**
0253      * @returns all currently managed VirtualDesktops
0254      */
0255     QVector<VirtualDesktop *> desktops() const
0256     {
0257         return m_desktops;
0258     }
0259 
0260     /**
0261      * @returns The VirtualDesktop for the x11 @p id, if no such VirtualDesktop @c null is returned
0262      */
0263     VirtualDesktop *desktopForX11Id(uint id) const;
0264 
0265     /**
0266      * @returns The VirtualDesktop for the internal desktop string @p id, if no such VirtualDesktop @c null is returned
0267      */
0268     VirtualDesktop *desktopForId(const QString &id) const;
0269 
0270     /**
0271      * Create a new virtual desktop at the requested position.
0272      * The difference with setCount is that setCount always adds new desktops at the end of the chain. The Id is automatically generated.
0273      * @param position The position of the desktop. It should be in range [0, count].
0274      * @param name The name for the new desktop, if empty the default name will be used.
0275      * @returns the new VirtualDesktop, nullptr if we reached the maximum number of desktops
0276      */
0277     VirtualDesktop *createVirtualDesktop(uint position, const QString &name = QString());
0278 
0279     /**
0280      * Remove the virtual desktop identified by id, if it exists
0281      * difference with setCount is that is possible to remove an arbitrary desktop,
0282      * not only the last one.
0283      * @param id the string id of the desktop to remove
0284      */
0285     void removeVirtualDesktop(const QString &id);
0286     void removeVirtualDesktop(VirtualDesktop *desktop);
0287 
0288     /**
0289      * Updates the net root info for new number of desktops
0290      */
0291     void updateRootInfo();
0292 
0293     /**
0294      * @returns The maximum number of desktops that KWin supports.
0295      */
0296     static uint maximum();
0297 
0298 public Q_SLOTS:
0299     /**
0300      * Set the number of available desktops to @a count. This function overrides any previous
0301      * grid layout.
0302      * There needs to be at least one virtual desktop and the new value is capped at the maximum
0303      * number of desktops. A caller of this function cannot expect that the change has been applied.
0304      * It is the callers responsibility to either check the numberOfDesktops or connect to the
0305      * countChanged signal.
0306      *
0307      * In case the @ref current desktop is on a desktop higher than the new count, the current desktop
0308      * is changed to be the new desktop with highest id. In that situation the signal desktopRemoved
0309      * is emitted.
0310      * @param count The new number of desktops to use
0311      * @see count
0312      * @see maximum
0313      * @see countChanged
0314      * @see desktopCreated
0315      * @see desktopRemoved
0316      */
0317     void setCount(uint count);
0318     /**
0319      * Set the current desktop to @a current.
0320      * @returns True on success, false otherwise.
0321      * @see current
0322      * @see currentChanged
0323      * @see moveTo
0324      */
0325     bool setCurrent(uint current);
0326     /**
0327      * Set the current desktop to @a current.
0328      * @returns True on success, false otherwise.
0329      * @see current
0330      * @see currentChanged
0331      * @see moveTo
0332      */
0333     bool setCurrent(VirtualDesktop *current);
0334     /**
0335      * Updates the layout to a new number of rows. The number of columns will be calculated accordingly
0336      */
0337     void setRows(uint rows);
0338     /**
0339      * Called from within setCount() to ensure the desktop layout is still valid.
0340      */
0341     void updateLayout();
0342     /**
0343      * @param enabled wrapping around borders for navigation in desktop layout
0344      * @see isNavigationWrappingAround
0345      * @see navigationWrappingAroundChanged
0346      */
0347     void setNavigationWrappingAround(bool enabled);
0348     /**
0349      * Loads number of desktops and names from configuration file
0350      */
0351     void load();
0352     /**
0353      * Saves number of desktops and names to configuration file
0354      */
0355     void save();
0356 
0357 Q_SIGNALS:
0358     /**
0359      * Signal emitted whenever the number of virtual desktops changes.
0360      * @param previousCount The number of desktops prior to the change
0361      * @param newCount The new current number of desktops
0362      */
0363     void countChanged(uint previousCount, uint newCount);
0364 
0365     /**
0366      * Signal when the number of rows in the layout changes
0367      * @param rows number of rows
0368      */
0369     void rowsChanged(uint rows);
0370 
0371     /**
0372      * A new desktop has been created
0373      * @param desktop the new just crated desktop
0374      */
0375     void desktopCreated(KWin::VirtualDesktop *desktop);
0376 
0377     /**
0378      * A desktop has been removed and is about to be deleted
0379      * @param desktop the desktop that has been removed.
0380      *          It's guaranteed to stil la valid pointer when the signal arrives,
0381      *          but it's about to be deleted.
0382      */
0383     void desktopRemoved(KWin::VirtualDesktop *desktop);
0384 
0385     /**
0386      * Signal emitted whenever the current desktop changes.
0387      * @param previousDesktop The virtual desktop changed from
0388      * @param newDesktop The virtual desktop changed to
0389      */
0390     void currentChanged(uint previousDesktop, uint newDesktop);
0391 
0392     /**
0393      * Signal emmitted for realtime desktop switching animations.
0394      * @param currentDesktop The current virtual desktop
0395      * @param offset The current total change in desktop coordinate
0396      * Offset x and y are negative if switching Left and Down.
0397      * Example: x = 0.6 means 60% of the way to the desktop to the right.
0398      */
0399     void currentChanging(uint currentDesktop, QPointF offset);
0400     void currentChangingCancelled();
0401 
0402     /**
0403      * Signal emitted whenever the desktop layout changes.
0404      * @param columns The new number of columns in the layout
0405      * @param rows The new number of rows in the layout
0406      */
0407     void layoutChanged(int columns, int rows);
0408     /**
0409      * Signal emitted whenever the navigationWrappingAround property changes.
0410      */
0411     void navigationWrappingAroundChanged();
0412 
0413 private Q_SLOTS:
0414     /**
0415      * Common slot for all "Switch to Desktop n" shortcuts.
0416      * This method uses the sender() method to access some data.
0417      * DO NOT CALL DIRECTLY! ONLY TO BE USED FROM AN ACTION!
0418      */
0419     void slotSwitchTo();
0420     /**
0421      * Slot for switch to next desktop action.
0422      */
0423     void slotNext();
0424     /**
0425      * Slot for switch to previous desktop action.
0426      */
0427     void slotPrevious();
0428     /**
0429      * Slot for switch to right desktop action.
0430      */
0431     void slotRight();
0432     /**
0433      * Slot for switch to left desktop action.
0434      */
0435     void slotLeft();
0436     /**
0437      * Slot for switch to desktop above action.
0438      */
0439     void slotUp();
0440     /**
0441      * Slot for switch to desktop below action.
0442      */
0443     void slotDown();
0444 
0445     /* For gestured desktopSwitching
0446      * Called when gesture ended, the thing that actually switches the desktop.
0447      */
0448     void gestureReleasedY();
0449     void gestureReleasedX();
0450 
0451 private:
0452     /**
0453      * Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters.
0454      */
0455     void setNETDesktopLayout(Qt::Orientation orientation, uint width, uint height, int startingCorner);
0456     /**
0457      * @returns A default name for the given @p desktop
0458      */
0459     QString defaultName(int desktop) const;
0460     /**
0461      * Creates all the global keyboard shortcuts for "Switch To Desktop n" actions.
0462      */
0463     void initSwitchToShortcuts();
0464     /**
0465      * Creates an action and connects it to the @p slot in this Manager. This method is
0466      * meant to be used for the case that an additional information needs to be stored in
0467      * the action and the label.
0468      * @param name The name of the action to be created
0469      * @param label The localized name for the action to be created
0470      * @param value An additional value added to the label and to the created action
0471      * @param key The global shortcut for the action
0472      * @param slot The slot to invoke when the action is triggered
0473      */
0474     QAction *addAction(const QString &name, const KLocalizedString &label, uint value, const QKeySequence &key, void (VirtualDesktopManager::*slot)());
0475     /**
0476      * Creates an action and connects it to the @p slot in this Manager.
0477      * Overloaded method for the case that no additional value needs to be passed to the action.
0478      * @param name The name of the action to be created
0479      * @param label The localized name for the action to be created
0480      * @param key The global shortcut for the action. If an empty QKeySequence is passed, no global shortcut is defined by default.
0481      * @param slot The slot to invoke when the action is triggered
0482      */
0483     QAction *addAction(const QString &name, const QString &label, const QKeySequence &key, void (VirtualDesktopManager::*slot)());
0484 
0485     QVector<VirtualDesktop *> m_desktops;
0486     QPointer<VirtualDesktop> m_current;
0487     quint32 m_rows = 2;
0488     bool m_navigationWrapsAround;
0489     VirtualDesktopGrid m_grid;
0490     // TODO: QPointer
0491     NETRootInfo *m_rootInfo;
0492     KWaylandServer::PlasmaVirtualDesktopManagementInterface *m_virtualDesktopManagement = nullptr;
0493     KSharedConfig::Ptr m_config;
0494 
0495     std::unique_ptr<QAction> m_swipeGestureReleasedY;
0496     std::unique_ptr<QAction> m_swipeGestureReleasedX;
0497     QPointF m_currentDesktopOffset = QPointF(0, 0);
0498 
0499     KWIN_SINGLETON_VARIABLE(VirtualDesktopManager, s_manager)
0500 };
0501 
0502 inline int VirtualDesktopGrid::width() const
0503 {
0504     return m_size.width();
0505 }
0506 
0507 inline int VirtualDesktopGrid::height() const
0508 {
0509     return m_size.height();
0510 }
0511 
0512 inline const QSize &VirtualDesktopGrid::size() const
0513 {
0514     return m_size;
0515 }
0516 
0517 inline uint VirtualDesktopManager::maximum()
0518 {
0519     return 20;
0520 }
0521 
0522 inline uint VirtualDesktopManager::count() const
0523 {
0524     return m_desktops.count();
0525 }
0526 
0527 inline bool VirtualDesktopManager::isNavigationWrappingAround() const
0528 {
0529     return m_navigationWrapsAround;
0530 }
0531 
0532 inline void VirtualDesktopManager::setConfig(KSharedConfig::Ptr config)
0533 {
0534     m_config = std::move(config);
0535 }
0536 
0537 inline const VirtualDesktopGrid &VirtualDesktopManager::grid() const
0538 {
0539     return m_grid;
0540 }
0541 
0542 } // namespace KWin