File indexing completed on 2024-09-15 12:58:50
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