File indexing completed on 2024-09-15 12:58:36
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 <kwinglobals.h> 0012 // Qt 0013 #include <QHash> 0014 #include <QObject> 0015 0016 namespace KWin 0017 { 0018 // forward declarations 0019 class Window; 0020 class Output; 0021 class VirtualDesktop; 0022 0023 /** 0024 * @brief Singleton class to handle the various focus chains. 0025 * 0026 * A focus chain is a list of Windows containing information on which Window should be activated. 0027 * 0028 * Internally this FocusChain holds multiple independent chains. There is one chain of most recently 0029 * used Windows which is primarily used by TabBox to build up the list of Windows for navigation. 0030 * The chains are organized as a normal QList of Windows with the most recently used Window being the 0031 * last item of the list, that is a LIFO like structure. 0032 * 0033 * In addition there is one chain for each virtual desktop which is used to determine which Window 0034 * should get activated when the user switches to another virtual desktop. 0035 * 0036 * Furthermore this class contains various helper methods for the two different kind of chains. 0037 */ 0038 class FocusChain : public QObject 0039 { 0040 Q_OBJECT 0041 public: 0042 enum Change { 0043 MakeFirst, 0044 MakeLast, 0045 Update, 0046 MakeFirstMinimized = MakeFirst 0047 }; 0048 explicit FocusChain() = default; 0049 0050 /** 0051 * @brief Updates the position of the @p window according to the requested @p change in the 0052 * focus chain. 0053 * 0054 * This method affects both the most recently used focus chain and the per virtual desktop focus 0055 * chain. 0056 * 0057 * In case the window does no longer want to get focus, it is removed from all chains. In case 0058 * the window is on all virtual desktops it is ensured that it is present in each of the virtual 0059 * desktops focus chain. In case it's on exactly one virtual desktop it is ensured that it is only 0060 * in the focus chain for that virtual desktop. 0061 * 0062 * Depending on @p change the Window is inserted at different positions in the focus chain. In case 0063 * of @c MakeFirst it is moved to the first position of the chain, in case of 0064 * @c MakeLast it is moved to the last position of the chain. In all other cases it 0065 * depends on whether the @p window is the currently active Window. If it is the active Window it 0066 * becomes the first Window in the chain, otherwise it is inserted at the second position that is 0067 * directly after the currently active Window. 0068 * 0069 * @param window The Window which should be moved inside the chains. 0070 * @param change Where to move the Window 0071 * @return void 0072 */ 0073 void update(Window *window, Change change); 0074 /** 0075 * @brief Moves @p window behind the @p reference Window in all focus chains. 0076 * 0077 * @param window The Window to move in the chains 0078 * @param reference The Window behind which the @p window should be moved 0079 * @return void 0080 */ 0081 void moveAfterWindow(Window *window, Window *reference); 0082 /** 0083 * @brief Finds the best Window to become the new active Window in the focus chain for the given 0084 * virtual @p desktop. 0085 * 0086 * In case that separate screen focus is used only Windows on the current screen are considered. 0087 * If no Window for activation is found @c null is returned. 0088 * 0089 * @param desktop The virtual desktop to look for a Window for activation 0090 * @return :X11Window *The Window which could be activated or @c null if there is none. 0091 */ 0092 Window *getForActivation(VirtualDesktop *desktop) const; 0093 /** 0094 * @brief Finds the best Window to become the new active Window in the focus chain for the given 0095 * virtual @p desktop on the given @p screen. 0096 * 0097 * This method makes only sense to use if separate screen focus is used. If separate screen focus 0098 * is disabled the @p screen is ignored. 0099 * If no Window for activation is found @c null is returned. 0100 * 0101 * @param desktop The virtual desktop to look for a Window for activation 0102 * @param output The screen to constrain the search on with separate screen focus 0103 * @return :X11Window *The Window which could be activated or @c null if there is none. 0104 */ 0105 Window *getForActivation(VirtualDesktop *desktop, Output *output) const; 0106 0107 /** 0108 * @brief Checks whether the most recently used focus chain contains the given @p window. 0109 * 0110 * Does not consider the per-desktop focus chains. 0111 * @param window The Window to look for. 0112 * @return bool @c true if the most recently used focus chain contains @p window, @c false otherwise. 0113 */ 0114 bool contains(Window *window) const; 0115 /** 0116 * @brief Checks whether the focus chain for the given @p desktop contains the given @p window. 0117 * 0118 * Does not consider the most recently used focus chain. 0119 * 0120 * @param window The Window to look for. 0121 * @param desktop The virtual desktop whose focus chain should be used 0122 * @return bool @c true if the focus chain for @p desktop contains @p window, @c false otherwise. 0123 */ 0124 bool contains(Window *window, VirtualDesktop *desktop) const; 0125 /** 0126 * @brief Queries the most recently used focus chain for the next Window after the given 0127 * @p reference Window. 0128 * 0129 * The navigation wraps around the borders of the chain. That is if the @p reference Window is 0130 * the last item of the focus chain, the first Window will be returned. 0131 * 0132 * If the @p reference Window cannot be found in the focus chain, the first element of the focus 0133 * chain is returned. 0134 * 0135 * @param reference The start point in the focus chain to search 0136 * @return :X11Window *The relatively next Window in the most recently used chain. 0137 */ 0138 Window *nextMostRecentlyUsed(Window *reference) const; 0139 /** 0140 * @brief Queries the focus chain for @p desktop for the next Window in relation to the given 0141 * @p reference Window. 0142 * 0143 * The method finds the first usable Window which is not the @p reference Window. If no Window 0144 * can be found @c null is returned 0145 * 0146 * @param reference The reference Window which should not be returned 0147 * @param desktop The virtual desktop whose focus chain should be used 0148 * @return :X11Window *The next usable Window or @c null if none can be found. 0149 */ 0150 Window *nextForDesktop(Window *reference, VirtualDesktop *desktop) const; 0151 /** 0152 * @brief Returns the first Window in the most recently used focus chain. First Window in this 0153 * case means really the first Window in the chain and not the most recently used Window. 0154 * 0155 * @return :X11Window *The first Window in the most recently used chain. 0156 */ 0157 Window *firstMostRecentlyUsed() const; 0158 0159 bool isUsableFocusCandidate(Window *window, Window *prev) const; 0160 0161 public Q_SLOTS: 0162 /** 0163 * @brief Removes @p window from all focus chains. 0164 * 0165 * @param window The Window to remove from all focus chains. 0166 * @return void 0167 */ 0168 void remove(KWin::Window *window); 0169 void setSeparateScreenFocus(bool enabled); 0170 void setActiveWindow(KWin::Window *window); 0171 void setCurrentDesktop(VirtualDesktop *desktop); 0172 void addDesktop(VirtualDesktop *desktop); 0173 void removeDesktop(VirtualDesktop *desktop); 0174 0175 private: 0176 using Chain = QList<Window *>; 0177 /** 0178 * @brief Makes @p window the first Window in the given focus @p chain. 0179 * 0180 * This means the existing position of @p window is dropped and @p window is appended to the 0181 * @p chain which makes it the first item. 0182 * 0183 * @param window The Window to become the first in @p chain 0184 * @param chain The focus chain to operate on 0185 * @return void 0186 */ 0187 void makeFirstInChain(Window *window, Chain &chain); 0188 /** 0189 * @brief Makes @p window the last Window in the given focus @p chain. 0190 * 0191 * This means the existing position of @p window is dropped and @p window is prepended to the 0192 * @p chain which makes it the last item. 0193 * 0194 * @param window The Window to become the last in @p chain 0195 * @param chain The focus chain to operate on 0196 * @return void 0197 */ 0198 void makeLastInChain(Window *window, Chain &chain); 0199 void moveAfterWindowInChain(Window *window, Window *reference, Chain &chain); 0200 void updateWindowInChain(Window *window, Change change, Chain &chain); 0201 void insertWindowIntoChain(Window *window, Chain &chain); 0202 Chain m_mostRecentlyUsed; 0203 QHash<VirtualDesktop *, Chain> m_desktopFocusChains; 0204 bool m_separateScreenFocus = false; 0205 Window *m_activeWindow = nullptr; 0206 VirtualDesktop *m_currentDesktop = nullptr; 0207 }; 0208 0209 inline bool FocusChain::contains(Window *window) const 0210 { 0211 return m_mostRecentlyUsed.contains(window); 0212 } 0213 0214 inline void FocusChain::setSeparateScreenFocus(bool enabled) 0215 { 0216 m_separateScreenFocus = enabled; 0217 } 0218 0219 inline void FocusChain::setActiveWindow(Window *window) 0220 { 0221 m_activeWindow = window; 0222 } 0223 0224 inline void FocusChain::setCurrentDesktop(VirtualDesktop *desktop) 0225 { 0226 m_currentDesktop = desktop; 0227 } 0228 0229 } // namespace