File indexing completed on 2024-05-19 16:34:56

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2009 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #pragma once
0011 
0012 #include "tabboxconfig.h"
0013 
0014 #include <QModelIndex>
0015 #include <QPixmap>
0016 #include <QString>
0017 
0018 /**
0019  * @file
0020  * This file contains the classes which hide KWin core from tabbox.
0021  * It defines the pure virtual classes TabBoxHandler and TabBoxClient.
0022  * The classes have to be implemented in KWin Core.
0023  *
0024  * @author Martin Gräßlin <mgraesslin@kde.org>
0025  * @since 4.4
0026  */
0027 
0028 class QKeyEvent;
0029 
0030 namespace KWin
0031 {
0032 /**
0033  * The TabBox is a model based view for displaying a list while switching windows or desktops.
0034  * This functionality is mostly referred to as Alt+Tab. TabBox itself does not provide support for
0035  * switching windows or desktops. This has to be done outside of TabBox inside an independent controller.
0036  *
0037  * The main entrance point to TabBox is the class TabBoxHandler, which has to be subclassed and implemented.
0038  * The class TabBoxClient, which represents a window client inside TabBox, has to be implemented as well.
0039  *
0040  * The behavior of the TabBox is defined by the TabBoxConfig and has to be set in the TabBoxHandler.
0041  * If the TabBox should be used to switch desktops as well as clients it is sufficient to just provide
0042  * different TabBoxConfig objects instead of creating an own handler for each mode.
0043  *
0044  * In order to use the TabBox the TabBoxConfig has to be set. This defines if the model for desktops or for
0045  * clients will be used. The model has to be initialized by calling TabBoxHandler::createModel(), as the
0046  * model is undefined when the TabBox is not active. The TabBox is activated by TabBoxHandler::show().
0047  * Depending on the current set TabBoxConfig it is possible that the
0048  * highlight windows effect activated and that the view is not displayed at all. As already mentioned
0049  * the TabBox does not handle any updating of the selected item. This has to be done by invoking
0050  * TabBoxHandler::setCurrentIndex(). Nevertheless the TabBoxHandler provides methods to query for the
0051  * model index or the next or previous item, for a cursor position or for a given item (that is
0052  * TabBoxClient or desktop). By invoking TabBoxHandler::hide() the view, the
0053  * optional highlight windows effect are removed. The model is invalidated immediately. So if it is
0054  * necessary to retrieve the last selected item this has to be done before calling the hide method.
0055  *
0056  * The layout of the TabBox View and the items is completely customizable. Therefore TabBox provides
0057  * a widget LayoutConfig which includes a live preview (in kcmkwin/kwintabbox). The layout of items
0058  * can be defined by an xml document. That way the user is able to define own custom layouts. The view
0059  * itself is made up of two widgets: one to show the complete list and one to show only the selected
0060  * item. This way it is possible to have a view which shows for example a list containing only small
0061  * icons and nevertheless show the title of the currently selected client.
0062  */
0063 namespace TabBox
0064 {
0065 class DesktopModel;
0066 class ClientModel;
0067 class TabBoxConfig;
0068 class TabBoxClient;
0069 class TabBoxHandlerPrivate;
0070 typedef QList<QWeakPointer<TabBoxClient>> TabBoxClientList;
0071 
0072 /**
0073  * This class is a wrapper around KWin Workspace. It is used for accessing the
0074  * required core methods from inside TabBox and has to be implemented in KWin core.
0075  *
0076  * @author Martin Gräßlin <mgraesslin@kde.org>
0077  * @since 4.4
0078  */
0079 class TabBoxHandler : public QObject
0080 {
0081     Q_OBJECT
0082 public:
0083     TabBoxHandler(QObject *parent);
0084     ~TabBoxHandler() override;
0085 
0086     /**
0087      * @return The id of the active screen
0088      */
0089     virtual int activeScreen() const = 0;
0090     /**
0091      * @return The current active TabBoxClient or NULL
0092      * if there is no active client.
0093      */
0094     virtual QWeakPointer<TabBoxClient> activeClient() const = 0;
0095     /**
0096      * @param client The client which is starting point to find the next client
0097      * @return The next TabBoxClient in focus chain
0098      */
0099     virtual QWeakPointer<TabBoxClient> nextClientFocusChain(TabBoxClient *client) const = 0;
0100     /**
0101      * This method is used by the ClientModel to find an entrance into the focus chain in case
0102      * there is no active Client.
0103      *
0104      * @return The first Client of the focus chain
0105      * @since 4.9.1
0106      */
0107     virtual QWeakPointer<TabBoxClient> firstClientFocusChain() const = 0;
0108     /**
0109      * Checks whether the given @p client is part of the focus chain at all.
0110      * This is useful to figure out whether the currently active Client can be used
0111      * as a starting point to construct the recently used list.
0112      *
0113      * In case the @p client is not in the focus chain it is recommended to use the
0114      * Client returned by firstClientFocusChain.
0115      *
0116      * The method accepts a @c null Client and in that case @c false is returned.
0117      * @param client The Client to check whether it is in the Focus Chain
0118      * @return @c true in case the Client is part of the focus chain, @c false otherwise.
0119      * @since 4.9.2
0120      */
0121     virtual bool isInFocusChain(TabBoxClient *client) const = 0;
0122     /**
0123      * @param client The client whose desktop name should be retrieved
0124      * @return The desktop name of the given TabBoxClient. If the client is
0125      * on all desktops the name of current desktop will be returned.
0126      */
0127     virtual QString desktopName(TabBoxClient *client) const = 0;
0128     /**
0129      * @param desktop The desktop whose name should be retrieved
0130      * @return The desktop name of given desktop
0131      */
0132     virtual QString desktopName(int desktop) const = 0;
0133     /**
0134      * @return The number of current desktop
0135      */
0136     virtual int currentDesktop() const = 0;
0137     /**
0138      * @return The number of virtual desktops
0139      */
0140     virtual int numberOfDesktops() const = 0;
0141     /**
0142      * @param desktop The desktop which is the starting point to find the next desktop
0143      * @return The next desktop in the current focus chain.
0144      */
0145     virtual int nextDesktopFocusChain(int desktop) const = 0;
0146 
0147     /**
0148      * whether KWin is currently compositing and it's related features (elevating) can be used
0149      */
0150     virtual bool isKWinCompositing() const = 0;
0151 
0152     /**
0153      * De-/Elevate a client using the compositor (if enabled)
0154      */
0155     virtual void elevateClient(TabBoxClient *c, QWindow *tabbox, bool elevate) const = 0;
0156 
0157     /**
0158      * Raise a client (w/o activating it)
0159      */
0160     virtual void raiseClient(TabBoxClient *c) const = 0;
0161 
0162     /**
0163      * @param c The client to be restacked
0164      * @param under The client the other one will be placed below
0165      */
0166     virtual void restack(TabBoxClient *c, TabBoxClient *under) = 0;
0167 
0168     /**
0169      * Toggle between ShadeHover and ShadeNormal - not shaded windows are unaffected
0170      * @param c The client to be shaded
0171      * @param b Whether to un- or shade
0172      */
0173     virtual void shadeClient(TabBoxClient *c, bool b) const = 0;
0174 
0175     virtual void highlightWindows(TabBoxClient *window = nullptr, QWindow *controller = nullptr) = 0;
0176 
0177     /**
0178      * @return The current stacking order of TabBoxClients
0179      */
0180     virtual TabBoxClientList stackingOrder() const = 0;
0181     /**
0182      * Determines if given client will be added to the list:
0183      * <UL>
0184      * <LI>Depends on desktop</LI>
0185      * <LI>if the client wants to have tab focus.</LI>
0186      * <LI>The client won't be added if it has modal dialogs</LI>
0187      * <LI>In that case the modal dialog will be returned if it isn't already
0188      * included</LI>
0189      * <LI>Won't be added if it isn't on active screen when using separate
0190      * screen focus</LI>
0191      * </UL>
0192      * @param client The client to be checked for inclusion
0193      * @param desktop The desktop the client should be on. This is irrelevant if allDesktops is set
0194      * @param allDesktops Add clients from all desktops or only from current
0195      * @return The client to be included in the list or NULL if it isn't to be included
0196      */
0197     virtual QWeakPointer<TabBoxClient> clientToAddToList(TabBoxClient *client, int desktop) const = 0;
0198     /**
0199      * @return The first desktop window in the stacking order.
0200      */
0201     virtual QWeakPointer<TabBoxClient> desktopClient() const = 0;
0202     /**
0203      * Activates the currently selected client and closes the TabBox.
0204      */
0205     virtual void activateAndClose() = 0;
0206 
0207     /**
0208      * @return The currently used TabBoxConfig
0209      */
0210     const TabBoxConfig &config() const;
0211     /**
0212      * Call this method when you want to change the currently used TabBoxConfig.
0213      * It fires the signal configChanged.
0214      * @param config Updates the currently used TabBoxConfig to config
0215      */
0216     void setConfig(const TabBoxConfig &config);
0217 
0218     /**
0219      * Call this method to show the TabBoxView. Depending on current
0220      * configuration this method might not do anything.
0221      * If highlight windows effect is to be used it will be activated.
0222      * Highlight windows and outline are not shown if
0223      * TabBoxConfig::TabBoxMode is TabBoxConfig::DesktopTabBox.
0224      * @see TabBoxConfig::isShowTabBox
0225      * @see TabBoxConfig::isHighlightWindows
0226      */
0227     void show();
0228     /**
0229      * Hides the TabBoxView if shown.
0230      * Deactivates highlight windows effect if active.
0231      * @see show
0232      */
0233     void hide(bool abort = false);
0234 
0235     /**
0236      * Sets the current model index in the view and updates
0237      * highlight windows if active.
0238      * @param index The current Model index
0239      */
0240     void setCurrentIndex(const QModelIndex &index);
0241     /**
0242      * @returns the current index
0243      */
0244     const QModelIndex &currentIndex() const;
0245 
0246     /**
0247      * Retrieves the next or previous item of the current item.
0248      * @param forward next or previous item
0249      * @return The next or previous item. If there is no matching item
0250      * the current item will be returned.
0251      */
0252     QModelIndex nextPrev(bool forward) const;
0253 
0254     /**
0255      * Initializes the model based on the current config.
0256      * This method has to be invoked before showing the TabBox.
0257      * It can also be invoked when clients are added or removed.
0258      * In that case partialReset has to be true.
0259      *
0260      * @param partialReset Keep the currently selected item or regenerate everything
0261      */
0262     void createModel(bool partialReset = false);
0263 
0264     /**
0265      * @param desktop The desktop whose index should be retrieved
0266      * @return The model index of given desktop. If TabBoxMode is not
0267      * TabBoxConfig::DesktopTabBox an invalid model index will be returned.
0268      */
0269     QModelIndex desktopIndex(int desktop) const;
0270     /**
0271      * @return The current list of desktops.
0272      * If TabBoxMode is not TabBoxConfig::DesktopTabBox an empty list will
0273      * be returned.
0274      * @see DesktopModel::desktopList
0275      */
0276     QList<int> desktopList() const;
0277     /**
0278      * @return The desktop for given model index. If the index is not valid
0279      * or TabBoxMode is not TabBoxConfig::DesktopTabBox -1 will be returned.
0280      * @see DesktopModel::desktopIndex
0281      */
0282     int desktop(const QModelIndex &index) const;
0283 
0284     /**
0285      * Handles additional grabbed key events by the TabBox controller.
0286      * @param event The key event which has been grabbed
0287      */
0288     virtual void grabbedKeyEvent(QKeyEvent *event) const;
0289     /**
0290      * @param pos The position to be tested in global coordinates
0291      * @return True if the view contains the point, otherwise false.
0292      */
0293     bool containsPos(const QPoint &pos) const;
0294     /**
0295      * @param client The TabBoxClient whose index should be returned
0296      * @return Returns the ModelIndex of given TabBoxClient or an invalid ModelIndex
0297      * if the model does not contain the given TabBoxClient.
0298      * @see ClientModel::index
0299      */
0300     QModelIndex index(QWeakPointer<TabBoxClient> client) const;
0301     /**
0302      * @return Returns the current list of TabBoxClients.
0303      * If TabBoxMode is not TabBoxConfig::ClientTabBox an empty list will
0304      * be returned.
0305      * @see ClientModel::clientList
0306      */
0307     TabBoxClientList clientList() const;
0308     /**
0309      * @param index The index of the client to be returned
0310      * @return Returns the TabBoxClient at given model index. If
0311      * the index is invalid, does not point to a Client or the list
0312      * is empty, NULL will be returned.
0313      */
0314     TabBoxClient *client(const QModelIndex &index) const;
0315     /**
0316      * @return The first model index. That is the model index at position 0, 0.
0317      * It is valid, as desktop has at least one desktop and if there are no
0318      * clients an empty item is created.
0319      */
0320     QModelIndex first() const;
0321 
0322     bool eventFilter(QObject *watcher, QEvent *event) override;
0323 
0324     /**
0325      * @returns whether the TabBox operates in a no modifier grab mode.
0326      * In this mode a click on an item should directly accept and close the tabbox.
0327      */
0328     virtual bool noModifierGrab() const = 0;
0329 
0330 Q_SIGNALS:
0331     /**
0332      * This signal is fired when the TabBoxConfig changes
0333      * @see setConfig
0334      */
0335     void configChanged();
0336     void selectedIndexChanged();
0337 
0338 private Q_SLOTS:
0339     void initHighlightWindows();
0340 
0341 private:
0342     friend class TabBoxHandlerPrivate;
0343     TabBoxHandlerPrivate *d;
0344 };
0345 
0346 /**
0347  * This class is a wrapper around a KWin Client. It is used for accessing the
0348  * required client methods from inside TabBox and has to be implemented in KWin core.
0349  *
0350  * @author Martin Gräßlin <mgraesslin@kde.org>
0351  * @since 4.4
0352  */
0353 class TabBoxClient
0354 {
0355 public:
0356     TabBoxClient();
0357     virtual ~TabBoxClient();
0358 
0359     /**
0360      * @return The caption of the client
0361      */
0362     virtual QString caption() const = 0;
0363     /**
0364      * @param size Requested size of the icon
0365      * @return The icon of the client
0366      */
0367     virtual QIcon icon() const = 0;
0368     /**
0369      * @return Minimized state of the client
0370      */
0371     virtual bool isMinimized() const = 0;
0372     virtual int x() const = 0;
0373     virtual int y() const = 0;
0374     virtual int width() const = 0;
0375     virtual int height() const = 0;
0376     virtual bool isCloseable() const = 0;
0377     virtual void close() = 0;
0378     virtual bool isFirstInTabBox() const = 0;
0379     virtual QUuid internalId() const = 0;
0380 };
0381 
0382 /**
0383  * Pointer to the global TabBoxHandler object.
0384  */
0385 extern TabBoxHandler *tabBox;
0386 
0387 } // namespace TabBox
0388 } // namespace KWin