kwin/tabbox/tabboxhandler.h

392 lines
14 KiB
C
Raw Normal View History

2020-08-03 01:22:19 +03:00
/*
KWin - the KDE window manager
This file is part of the KDE project.
2020-08-03 01:22:19 +03:00
SPDX-FileCopyrightText: 2009 Martin Gräßlin <mgraesslin@kde.org>
2020-08-03 01:22:19 +03:00
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef TABBOXHANDLER_H
#define TABBOXHANDLER_H
#include "tabboxconfig.h"
#include <QModelIndex>
#include <QPixmap>
#include <QString>
/**
* @file
* This file contains the classes which hide KWin core from tabbox.
* It defines the pure virtual classes TabBoxHandler and TabBoxClient.
* The classes have to be implemented in KWin Core.
*
* @author Martin Gräßlin <mgraesslin@kde.org>
* @since 4.4
*/
class QKeyEvent;
namespace KWin
{
/**
* The TabBox is a model based view for displaying a list while switching windows or desktops.
* This functionality is mostly referred to as Alt+Tab. TabBox itself does not provide support for
* switching windows or desktops. This has to be done outside of TabBox inside an independent controller.
*
* The main entrance point to TabBox is the class TabBoxHandler, which has to be subclassed and implemented.
* The class TabBoxClient, which represents a window client inside TabBox, has to be implemented as well.
*
* The behavior of the TabBox is defined by the TabBoxConfig and has to be set in the TabBoxHandler.
* If the TabBox should be used to switch desktops as well as clients it is sufficient to just provide
* different TabBoxConfig objects instead of creating an own handler for each mode.
*
* In order to use the TabBox the TabBoxConfig has to be set. This defines if the model for desktops or for
* clients will be used. The model has to be initialized by calling TabBoxHandler::createModel(), as the
* model is undefined when the TabBox is not active. The TabBox is activated by TabBoxHandler::show().
* Depending on the current set TabBoxConfig it is possible that the
* highlight windows effect activated and that the view is not displayed at all. As already mentioned
* the TabBox does not handle any updating of the selected item. This has to be done by invoking
* TabBoxHandler::setCurrentIndex(). Nevertheless the TabBoxHandler provides methods to query for the
* model index or the next or previous item, for a cursor position or for a given item (that is
* TabBoxClient or desktop). By invoking TabBoxHandler::hide() the view, the
* optional highlight windows effect are removed. The model is invalidated immediately. So if it is
* necessary to retrieve the last selected item this has to be done before calling the hide method.
*
* The layout of the TabBox View and the items is completely customizable. Therefore TabBox provides
* a widget LayoutConfig which includes a live preview (in kcmkwin/kwintabbox). The layout of items
* can be defined by an xml document. That way the user is able to define own custom layouts. The view
* itself is made up of two widgets: one to show the complete list and one to show only the selected
* item. This way it is possible to have a view which shows for example a list containing only small
* icons and nevertheless show the title of the currently selected client.
*/
namespace TabBox
{
class DesktopModel;
class ClientModel;
class TabBoxConfig;
class TabBoxClient;
class TabBoxHandlerPrivate;
typedef QList< QWeakPointer< TabBoxClient > > TabBoxClientList;
/**
* This class is a wrapper around KWin Workspace. It is used for accessing the
* required core methods from inside TabBox and has to be implemented in KWin core.
*
* @author Martin Gräßlin <mgraesslin@kde.org>
* @since 4.4
*/
class TabBoxHandler : public QObject
2011-01-30 17:34:42 +03:00
{
Q_OBJECT
2011-01-30 17:34:42 +03:00
public:
TabBoxHandler(QObject *parent);
Run clang-tidy with modernize-use-override check Summary: Currently code base of kwin can be viewed as two pieces. One is very ancient, and the other one is more modern, which uses new C++ features. The main problem with the ancient code is that it was written before C++11 era. So, no override or final keywords, lambdas, etc. Quite recently, KDE compiler settings were changed to show a warning if a virtual method has missing override keyword. As you might have already guessed, this fired back at us because of that ancient code. We had about 500 new compiler warnings. A "solution" was proposed to that problem - disable -Wno-suggest-override and the other similar warning for clang. It's hard to call a solution because those warnings are disabled not only for the old code, but also for new. This is not what we want! The main argument for not actually fixing the problem was that git history will be screwed as well because of human factor. While good git history is a very important thing, we should not go crazy about it and block every change that somehow alters git history. git blame allows to specify starting revision for a reason. The other argument (human factor) can be easily solved by using tools such as clang-tidy. clang-tidy is a clang-based linter for C++. It can be used for various things, e.g. fixing coding style(e.g. add missing braces to if statements, readability-braces-around-statements check), or in our case add missing override keywords. Test Plan: Compiles. Reviewers: #kwin, davidedmundson Reviewed By: #kwin, davidedmundson Subscribers: davidedmundson, apol, romangg, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D22371
2019-07-22 19:52:26 +03:00
~TabBoxHandler() override;
2011-01-30 17:34:42 +03:00
/**
* @return The id of the active screen
*/
2011-01-30 17:34:42 +03:00
virtual int activeScreen() const = 0;
/**
* @return The current active TabBoxClient or NULL
* if there is no active client.
*/
virtual QWeakPointer<TabBoxClient> activeClient() const = 0;
2011-01-30 17:34:42 +03:00
/**
* @param client The client which is starting point to find the next client
* @return The next TabBoxClient in focus chain
*/
virtual QWeakPointer<TabBoxClient> nextClientFocusChain(TabBoxClient* client) const = 0;
/**
* This method is used by the ClientModel to find an entrance into the focus chain in case
* there is no active Client.
*
* @return The first Client of the focus chain
* @since 4.9.1
*/
virtual QWeakPointer<TabBoxClient> firstClientFocusChain() const = 0;
/**
* Checks whether the given @p client is part of the focus chain at all.
* This is useful to figure out whether the currently active Client can be used
* as a starting point to construct the recently used list.
*
* In case the @p client is not in the focus chain it is recommended to use the
2019-01-12 13:31:32 +03:00
* Client returned by firstClientFocusChain.
*
* The method accepts a @c null Client and in that case @c false is returned.
* @param client The Client to check whether it is in the Focus Chain
* @return @c true in case the Client is part of the focus chain, @c false otherwise.
* @since 4.9.2
*/
virtual bool isInFocusChain(TabBoxClient* client) const = 0;
2011-01-30 17:34:42 +03:00
/**
* @param client The client whose desktop name should be retrieved
* @return The desktop name of the given TabBoxClient. If the client is
* on all desktops the name of current desktop will be returned.
*/
2011-01-30 17:34:42 +03:00
virtual QString desktopName(TabBoxClient* client) const = 0;
/**
* @param desktop The desktop whose name should be retrieved
* @return The desktop name of given desktop
*/
2011-01-30 17:34:42 +03:00
virtual QString desktopName(int desktop) const = 0;
/**
* @return The number of current desktop
*/
2011-01-30 17:34:42 +03:00
virtual int currentDesktop() const = 0;
/**
* @return The number of virtual desktops
*/
2011-01-30 17:34:42 +03:00
virtual int numberOfDesktops() const = 0;
/**
* @param desktop The desktop which is the starting point to find the next desktop
* @return The next desktop in the current focus chain.
*/
2011-01-30 17:34:42 +03:00
virtual int nextDesktopFocusChain(int desktop) const = 0;
/**
* whether KWin is currently compositing and it's related features (elevating) can be used
*/
virtual bool isKWinCompositing() const = 0;
/**
* De-/Elevate a client using the compositor (if enabled)
*/
virtual void elevateClient(TabBoxClient* c, QWindow *tabbox, bool elevate) const = 0;
2011-01-30 17:34:42 +03:00
/**
* Raise a client (w/o activating it)
*/
2011-01-30 17:34:42 +03:00
virtual void raiseClient(TabBoxClient* c) const = 0;
2011-01-30 17:34:42 +03:00
/**
* @param c The client to be restacked
* @param under The client the other one will be placed below
*/
2011-01-30 17:34:42 +03:00
virtual void restack(TabBoxClient *c, TabBoxClient *under) = 0;
/**
* Toggle between ShadeHover and ShadeNormal - not shaded windows are unaffected
* @param c The client to be shaded
* @param b Whether to un- or shade
*/
virtual void shadeClient(TabBoxClient *c, bool b) const = 0;
virtual void highlightWindows(TabBoxClient *window = nullptr, QWindow *controller = nullptr) = 0;
2011-01-30 17:34:42 +03:00
/**
* @return The current stacking order of TabBoxClients
*/
2011-01-30 17:34:42 +03:00
virtual TabBoxClientList stackingOrder() const = 0;
/**
* Determines if given client will be added to the list:
* <UL>
* <LI>Depends on desktop</LI>
* <LI>if the client wants to have tab focus.</LI>
* <LI>The client won't be added if it has modal dialogs</LI>
* <LI>In that case the modal dialog will be returned if it isn't already
* included</LI>
* <LI>Won't be added if it isn't on active screen when using separate
* screen focus</LI>
* </UL>
* @param client The client to be checked for inclusion
* @param desktop The desktop the client should be on. This is irrelevant if allDesktops is set
* @param allDesktops Add clients from all desktops or only from current
* @return The client to be included in the list or NULL if it isn't to be included
*/
virtual QWeakPointer<TabBoxClient> clientToAddToList(TabBoxClient* client, int desktop) const = 0;
2011-01-30 17:34:42 +03:00
/**
* @return The first desktop window in the stacking order.
*/
virtual QWeakPointer<TabBoxClient> desktopClient() const = 0;
/**
* Activates the currently selected client and closes the TabBox.
*/
virtual void activateAndClose() = 0;
2011-01-30 17:34:42 +03:00
/**
* @return The currently used TabBoxConfig
*/
2011-01-30 17:34:42 +03:00
const TabBoxConfig& config() const;
/**
* Call this method when you want to change the currently used TabBoxConfig.
* It fires the signal configChanged.
* @param config Updates the currently used TabBoxConfig to config
*/
2011-01-30 17:34:42 +03:00
void setConfig(const TabBoxConfig& config);
2011-01-30 17:34:42 +03:00
/**
* Call this method to show the TabBoxView. Depending on current
* configuration this method might not do anything.
* If highlight windows effect is to be used it will be activated.
* Highlight windows and outline are not shown if
* TabBoxConfig::TabBoxMode is TabBoxConfig::DesktopTabBox.
* @see TabBoxConfig::isShowTabBox
* @see TabBoxConfig::isHighlightWindows
*/
2011-01-30 17:34:42 +03:00
void show();
/**
* Hides the TabBoxView if shown.
* Deactivates highlight windows effect if active.
* @see show
*/
2011-01-30 17:34:42 +03:00
void hide(bool abort = false);
2011-01-30 17:34:42 +03:00
/**
* Sets the current model index in the view and updates
* highlight windows if active.
* @param index The current Model index
*/
2011-01-30 17:34:42 +03:00
void setCurrentIndex(const QModelIndex& index);
/**
* @returns the current index
*/
const QModelIndex &currentIndex() const;
2011-01-30 17:34:42 +03:00
/**
* Retrieves the next or previous item of the current item.
* @param forward next or previous item
* @return The next or previous item. If there is no matching item
* the current item will be returned.
*/
2011-01-30 17:34:42 +03:00
QModelIndex nextPrev(bool forward) const;
2011-01-30 17:34:42 +03:00
/**
* Initializes the model based on the current config.
* This method has to be invoked before showing the TabBox.
* It can also be invoked when clients are added or removed.
* In that case partialReset has to be true.
*
* @param partialReset Keep the currently selected item or regenerate everything
*/
2011-01-30 17:34:42 +03:00
void createModel(bool partialReset = false);
2011-01-30 17:34:42 +03:00
/**
* @param desktop The desktop whose index should be retrieved
* @return The model index of given desktop. If TabBoxMode is not
* TabBoxConfig::DesktopTabBox an invalid model index will be returned.
*/
2011-01-30 17:34:42 +03:00
QModelIndex desktopIndex(int desktop) const;
/**
* @return The current list of desktops.
* If TabBoxMode is not TabBoxConfig::DesktopTabBox an empty list will
* be returned.
* @see DesktopModel::desktopList
*/
2011-01-30 17:34:42 +03:00
QList< int > desktopList() const;
/**
* @return The desktop for given model index. If the index is not valid
* or TabBoxMode is not TabBoxConfig::DesktopTabBox -1 will be returned.
* @see DesktopModel::desktopIndex
*/
2011-01-30 17:34:42 +03:00
int desktop(const QModelIndex& index) const;
2011-01-30 17:34:42 +03:00
/**
* Handles additional grabbed key events by the TabBox controller.
* @param event The key event which has been grabbed
*/
virtual void grabbedKeyEvent(QKeyEvent* event) const;
2011-01-30 17:34:42 +03:00
/**
* @param pos The position to be tested in global coordinates
* @return True if the view contains the point, otherwise false.
*/
2011-01-30 17:34:42 +03:00
bool containsPos(const QPoint& pos) const;
/**
* @param client The TabBoxClient whose index should be returned
* @return Returns the ModelIndex of given TabBoxClient or an invalid ModelIndex
* if the model does not contain the given TabBoxClient.
* @see ClientModel::index
*/
QModelIndex index(QWeakPointer<TabBoxClient> client) const;
2011-01-30 17:34:42 +03:00
/**
* @return Returns the current list of TabBoxClients.
* If TabBoxMode is not TabBoxConfig::ClientTabBox an empty list will
* be returned.
* @see ClientModel::clientList
*/
2011-01-30 17:34:42 +03:00
TabBoxClientList clientList() const;
/**
* @param index The index of the client to be returned
* @return Returns the TabBoxClient at given model index. If
* the index is invalid, does not point to a Client or the list
* is empty, NULL will be returned.
*/
2011-01-30 17:34:42 +03:00
TabBoxClient* client(const QModelIndex& index) const;
/**
* @return The first model index. That is the model index at position 0, 0.
* It is valid, as desktop has at least one desktop and if there are no
* clients an empty item is created.
*/
2011-01-30 17:34:42 +03:00
QModelIndex first() const;
[tabbox] Intercept QWheelEvents on QQuickWindow for scrolling Summary: The TabBox performs the scrolling of the items by itself in order to support wheel events even if the mouse is not on the TabBox. For that KWin grabs pointer events on X11 (on Wayland an input filter is used) and forwards them to the TabBox. Qt uses Xinput2 for scrolling on the QQuickWindow. Due to that KWin does not get any xcb core button press/release events when scrolling inside the QQuickWindow and thus scrolling doesn't work. There are three possible approaches to fix this: 1. Implement scrolling support in each of the QML switchers 2. Add an xinput2 filter to TabBox 3. Intercept the QWheelEvents on the QQuickWindow The first approach has the disadvantage that all themes need adjustment and that there might be behaviorial difference whether one scrolls on the TabBox window or outside the window. The second approach would be most in line with the other filters, but is difficult due to the nature of xinput2 (no xcb bindings, etc). Thus the third approach might be the best solution. Wheel events are only delivered to the QQuickWindow if the native events were not already intercepted, thus we know it won't have side effects for the case that Wayland is used or xinput2 is not supported. The implementation installs an event filter on the QQuickWindow which gets created when showing the TabBox and inside the filter waits till there is an angleDelta of +/-120 and scrolls by one per every 120 angle delta as described in the QWheelEvent documentation. BUG: 369661 FIXED-IN: 5.8.2 Test Plan: Scrolled with touchpad and mouse wheel. Reviewers: #kwin, #plasma, broulik Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D2953
2016-10-06 09:06:25 +03:00
bool eventFilter(QObject *watcher, QEvent *event) override;
/**
* @returns whether the TabBox operates in a no modifier grab mode.
* In this mode a click on an item should directly accept and close the tabbox.
*/
virtual bool noModifierGrab() const = 0;
Q_SIGNALS:
2011-01-30 17:34:42 +03:00
/**
* This signal is fired when the TabBoxConfig changes
* @see setConfig
*/
2011-01-30 17:34:42 +03:00
void configChanged();
void selectedIndexChanged();
2011-01-30 17:34:42 +03:00
private Q_SLOTS:
void initHighlightWindows();
2011-01-30 17:34:42 +03:00
private:
friend class TabBoxHandlerPrivate;
2011-01-30 17:34:42 +03:00
TabBoxHandlerPrivate* d;
};
/**
* This class is a wrapper around a KWin Client. It is used for accessing the
* required client methods from inside TabBox and has to be implemented in KWin core.
*
* @author Martin Gräßlin <mgraesslin@kde.org>
* @since 4.4
*/
class TabBoxClient
2011-01-30 17:34:42 +03:00
{
public:
TabBoxClient();
virtual ~TabBoxClient();
2011-01-30 17:34:42 +03:00
/**
* @return The caption of the client
*/
2011-01-30 17:34:42 +03:00
virtual QString caption() const = 0;
/**
* @param size Requested size of the icon
* @return The icon of the client
*/
virtual QIcon icon() const = 0;
2011-01-30 17:34:42 +03:00
/**
* @return Minimized state of the client
*/
2011-01-30 17:34:42 +03:00
virtual bool isMinimized() const = 0;
virtual int x() const = 0;
virtual int y() const = 0;
virtual int width() const = 0;
virtual int height() const = 0;
virtual bool isCloseable() const = 0;
virtual void close() = 0;
virtual bool isFirstInTabBox() const = 0;
virtual QUuid internalId() const = 0;
2011-01-30 17:34:42 +03:00
};
/**
* Pointer to the global TabBoxHandler object.
*/
extern TabBoxHandler* tabBox;
} // namespace TabBox
} // namespace KWin
#endif // TABBOXHANDLER_H