kwin/src/focuschain.h

234 lines
9 KiB
C
Raw Normal View History

2020-08-02 22:22:19 +00:00
/*
KWin - the KDE window manager
This file is part of the KDE project.
2020-08-02 22:22:19 +00:00
SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
2020-08-02 22:22:19 +00:00
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef KWIN_FOCUS_CHAIN_H
#define KWIN_FOCUS_CHAIN_H
// KWin
#include <kwinglobals.h>
// Qt
#include <QHash>
#include <QObject>
namespace KWin
{
// forward declarations
2022-04-22 17:39:12 +00:00
class Window;
class Output;
2021-08-16 12:07:43 +00:00
class VirtualDesktop;
/**
* @brief Singleton class to handle the various focus chains.
*
* A focus chain is a list of Windows containing information on which Window should be activated.
*
* Internally this FocusChain holds multiple independent chains. There is one chain of most recently
* used Windows which is primarily used by TabBox to build up the list of Windows for navigation.
* The chains are organized as a normal QList of Windows with the most recently used Window being the
* last item of the list, that is a LIFO like structure.
*
* In addition there is one chain for each virtual desktop which is used to determine which Window
* should get activated when the user switches to another virtual desktop.
*
* Furthermore this class contains various helper methods for the two different kind of chains.
*/
class FocusChain : public QObject
{
Q_OBJECT
public:
enum Change {
MakeFirst,
MakeLast,
Update,
MakeFirstMinimized = MakeFirst
};
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 16:52:26 +00:00
~FocusChain() override;
/**
* @brief Updates the position of the @p window according to the requested @p change in the
* focus chain.
*
* This method affects both the most recently used focus chain and the per virtual desktop focus
* chain.
*
* In case the window does no longer want to get focus, it is removed from all chains. In case
* the window is on all virtual desktops it is ensured that it is present in each of the virtual
* desktops focus chain. In case it's on exactly one virtual desktop it is ensured that it is only
* in the focus chain for that virtual desktop.
*
* Depending on @p change the Window is inserted at different positions in the focus chain. In case
* of @c MakeFirst it is moved to the first position of the chain, in case of
* @c MakeLast it is moved to the last position of the chain. In all other cases it
* depends on whether the @p window is the currently active Window. If it is the active Window it
* becomes the first Window in the chain, otherwise it is inserted at the second position that is
* directly after the currently active Window.
*
* @param window The Window which should be moved inside the chains.
* @param change Where to move the Window
* @return void
*/
void update(Window *window, Change change);
/**
* @brief Moves @p window behind the @p reference Window in all focus chains.
*
* @param window The Window to move in the chains
* @param reference The Window behind which the @p window should be moved
* @return void
*/
void moveAfterWindow(Window *window, Window *reference);
/**
* @brief Finds the best Window to become the new active Window in the focus chain for the given
* virtual @p desktop.
*
* In case that separate screen focus is used only Windows on the current screen are considered.
* If no Window for activation is found @c null is returned.
*
* @param desktop The virtual desktop to look for a Window for activation
* @return :X11Window *The Window which could be activated or @c null if there is none.
*/
2022-04-22 17:39:12 +00:00
Window *getForActivation(VirtualDesktop *desktop) const;
/**
* @brief Finds the best Window to become the new active Window in the focus chain for the given
* virtual @p desktop on the given @p screen.
*
* This method makes only sense to use if separate screen focus is used. If separate screen focus
* is disabled the @p screen is ignored.
* If no Window for activation is found @c null is returned.
*
* @param desktop The virtual desktop to look for a Window for activation
2021-08-28 14:48:12 +00:00
* @param output The screen to constrain the search on with separate screen focus
* @return :X11Window *The Window which could be activated or @c null if there is none.
*/
2022-04-22 17:39:12 +00:00
Window *getForActivation(VirtualDesktop *desktop, Output *output) const;
/**
* @brief Checks whether the most recently used focus chain contains the given @p window.
*
* Does not consider the per-desktop focus chains.
* @param window The Window to look for.
* @return bool @c true if the most recently used focus chain contains @p window, @c false otherwise.
*/
bool contains(Window *window) const;
/**
* @brief Checks whether the focus chain for the given @p desktop contains the given @p window.
*
* Does not consider the most recently used focus chain.
*
* @param window The Window to look for.
* @param desktop The virtual desktop whose focus chain should be used
* @return bool @c true if the focus chain for @p desktop contains @p window, @c false otherwise.
*/
bool contains(Window *window, VirtualDesktop *desktop) const;
/**
* @brief Queries the most recently used focus chain for the next Window after the given
* @p reference Window.
*
* The navigation wraps around the borders of the chain. That is if the @p reference Window is
* the last item of the focus chain, the first Window will be returned.
*
* If the @p reference Window cannot be found in the focus chain, the first element of the focus
* chain is returned.
*
* @param reference The start point in the focus chain to search
* @return :X11Window *The relatively next Window in the most recently used chain.
*/
2022-04-22 17:39:12 +00:00
Window *nextMostRecentlyUsed(Window *reference) const;
/**
* @brief Queries the focus chain for @p desktop for the next Window in relation to the given
* @p reference Window.
*
* The method finds the first usable Window which is not the @p reference Window. If no Window
* can be found @c null is returned
*
* @param reference The reference Window which should not be returned
* @param desktop The virtual desktop whose focus chain should be used
* @return :X11Window *The next usable Window or @c null if none can be found.
*/
2022-04-22 17:39:12 +00:00
Window *nextForDesktop(Window *reference, VirtualDesktop *desktop) const;
/**
* @brief Returns the first Window in the most recently used focus chain. First Window in this
* case means really the first Window in the chain and not the most recently used Window.
*
* @return :X11Window *The first Window in the most recently used chain.
*/
2022-04-22 17:39:12 +00:00
Window *firstMostRecentlyUsed() const;
bool isUsableFocusCandidate(Window *window, Window *prev) const;
2021-05-13 17:07:01 +00:00
public Q_SLOTS:
/**
* @brief Removes @p window from all focus chains.
*
* @param window The Window to remove from all focus chains.
* @return void
*/
void remove(KWin::Window *window);
void setSeparateScreenFocus(bool enabled);
void setActiveWindow(KWin::Window *window);
2021-08-16 12:07:43 +00:00
void setCurrentDesktop(VirtualDesktop *desktop);
void addDesktop(VirtualDesktop *desktop);
void removeDesktop(VirtualDesktop *desktop);
private:
2022-04-22 17:39:12 +00:00
using Chain = QList<Window *>;
/**
* @brief Makes @p window the first Window in the given focus @p chain.
*
* This means the existing position of @p window is dropped and @p window is appended to the
* @p chain which makes it the first item.
*
* @param window The Window to become the first in @p chain
* @param chain The focus chain to operate on
* @return void
*/
void makeFirstInChain(Window *window, Chain &chain);
/**
* @brief Makes @p window the last Window in the given focus @p chain.
*
* This means the existing position of @p window is dropped and @p window is prepended to the
* @p chain which makes it the last item.
*
* @param window The Window to become the last in @p chain
* @param chain The focus chain to operate on
* @return void
*/
void makeLastInChain(Window *window, Chain &chain);
void moveAfterWindowInChain(Window *window, Window *reference, Chain &chain);
void updateWindowInChain(Window *window, Change change, Chain &chain);
void insertWindowIntoChain(Window *window, Chain &chain);
Chain m_mostRecentlyUsed;
2021-08-16 12:07:43 +00:00
QHash<VirtualDesktop *, Chain> m_desktopFocusChains;
bool m_separateScreenFocus;
Window *m_activeWindow;
2021-08-16 12:07:43 +00:00
VirtualDesktop *m_currentDesktop = nullptr;
KWIN_SINGLETON_VARIABLE(FocusChain, s_manager)
};
inline bool FocusChain::contains(Window *window) const
{
return m_mostRecentlyUsed.contains(window);
}
inline void FocusChain::setSeparateScreenFocus(bool enabled)
{
m_separateScreenFocus = enabled;
}
inline void FocusChain::setActiveWindow(Window *window)
{
m_activeWindow = window;
}
inline void FocusChain::setCurrentDesktop(VirtualDesktop *desktop)
{
2021-08-16 12:07:43 +00:00
m_currentDesktop = desktop;
}
} // namespace
#endif // KWIN_FOCUS_CHAIN_H