-
Notifications
You must be signed in to change notification settings - Fork 18
/
focuschain.h
254 lines (238 loc) · 10.2 KB
/
focuschain.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_FOCUS_CHAIN_H
#define KWIN_FOCUS_CHAIN_H
// KWin
#include <kwinglobals.h>
// Qt
#include <QObject>
#include <QHash>
namespace KWin
{
// forward declarations
class AbstractClient;
/**
* @brief Singleton class to handle the various focus chains.
*
* A focus chain is a list of Clients containing information on which Client should be activated.
*
* Internally this FocusChain holds multiple independent chains. There is one chain of most recently
* used Clients which is primarily used by TabBox to build up the list of Clients for navigation.
* The chains are organized as a normal QList of Clients with the most recently used Client 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 Client
* 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
};
~FocusChain() override;
/**
* @brief Updates the position of the @p client 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 client does no longer want to get focus, it is removed from all chains. In case
* the client 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 Client 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 client is the currently active Client. If it is the active Client it
* becomes the first Client in the chain, otherwise it is inserted at the second position that is
* directly after the currently active Client.
*
* @param client The Client which should be moved inside the chains.
* @param change Where to move the Client
* @return void
*/
void update(AbstractClient *client, Change change);
/**
* @brief Moves @p client behind the @p reference Client in all focus chains.
*
* @param client The Client to move in the chains
* @param reference The Client behind which the @p client should be moved
* @return void
*/
void moveAfterClient(AbstractClient *client, AbstractClient *reference);
/**
* @brief Finds the best Client to become the new active Client in the focus chain for the given
* virtual @p desktop.
*
* In case that separate screen focus is used only Clients on the current screen are considered.
* If no Client for activation is found @c null is returned.
*
* @param desktop The virtual desktop to look for a Client for activation
* @return :X11Client *The Client which could be activated or @c null if there is none.
*/
AbstractClient *getForActivation(uint desktop) const;
/**
* @brief Finds the best Client to become the new active Client 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 Client for activation is found @c null is returned.
*
* @param desktop The virtual desktop to look for a Client for activation
* @param screen The screen to constrain the search on with separate screen focus
* @return :X11Client *The Client which could be activated or @c null if there is none.
*/
AbstractClient *getForActivation(uint desktop, int screen) const;
/**
* @brief Checks whether the most recently used focus chain contains the given @p client.
*
* Does not consider the per-desktop focus chains.
* @param client The Client to look for.
* @return bool @c true if the most recently used focus chain contains @p client, @c false otherwise.
*/
bool contains(AbstractClient *client) const;
/**
* @brief Checks whether the focus chain for the given @p desktop contains the given @p client.
*
* Does not consider the most recently used focus chain.
*
* @param client The Client 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 client, @c false otherwise.
*/
bool contains(AbstractClient *client, uint desktop) const;
/**
* @brief Queries the most recently used focus chain for the next Client after the given
* @p reference Client.
*
* The navigation wraps around the borders of the chain. That is if the @p reference Client is
* the last item of the focus chain, the first Client will be returned.
*
* If the @p reference Client 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 :X11Client *The relatively next Client in the most recently used chain.
*/
AbstractClient *nextMostRecentlyUsed(AbstractClient *reference) const;
/**
* @brief Queries the focus chain for @p desktop for the next Client in relation to the given
* @p reference Client.
*
* The method finds the first usable Client which is not the @p reference Client. If no Client
* can be found @c null is returned
*
* @param reference The reference Client which should not be returned
* @param desktop The virtual desktop whose focus chain should be used
* @return :X11Client *The next usable Client or @c null if none can be found.
*/
AbstractClient *nextForDesktop(AbstractClient *reference, uint desktop) const;
/**
* @brief Returns the first Client in the most recently used focus chain. First Client in this
* case means really the first Client in the chain and not the most recently used Client.
*
* @return :X11Client *The first Client in the most recently used chain.
*/
AbstractClient *firstMostRecentlyUsed() const;
public Q_SLOTS:
/**
* @brief Resizes the per virtual desktop focus chains from @p previousSize to @p newSize.
* This means that for each virtual desktop between previous and new size a new focus chain is
* created and in case the number is reduced the focus chains are destroyed.
*
* @param previousSize The previous number of virtual desktops
* @param newSize The new number of virtual desktops
* @return void
*/
void resize(uint previousSize, uint newSize);
/**
* @brief Removes @p client from all focus chains.
*
* @param client The Client to remove from all focus chains.
* @return void
*/
void remove(KWin::AbstractClient *client);
void setSeparateScreenFocus(bool enabled);
void setActiveClient(KWin::AbstractClient *client);
void setCurrentDesktop(uint previous, uint newDesktop);
bool isUsableFocusCandidate(AbstractClient *c, AbstractClient *prev) const;
private:
using Chain = QList<AbstractClient*>;
/**
* @brief Makes @p client the first Client in the given focus @p chain.
*
* This means the existing position of @p client is dropped and @p client is appended to the
* @p chain which makes it the first item.
*
* @param client The Client to become the first in @p chain
* @param chain The focus chain to operate on
* @return void
*/
void makeFirstInChain(AbstractClient *client, Chain &chain);
/**
* @brief Makes @p client the last Client in the given focus @p chain.
*
* This means the existing position of @p client is dropped and @p client is prepended to the
* @p chain which makes it the last item.
*
* @param client The Client to become the last in @p chain
* @param chain The focus chain to operate on
* @return void
*/
void makeLastInChain(AbstractClient *client, Chain &chain);
void moveAfterClientInChain(AbstractClient *client, AbstractClient *reference, Chain &chain);
void updateClientInChain(AbstractClient *client, Change change, Chain &chain);
void insertClientIntoChain(AbstractClient *client, Chain &chain);
Chain m_mostRecentlyUsed;
QHash<uint, Chain> m_desktopFocusChains;
bool m_separateScreenFocus;
AbstractClient *m_activeClient;
uint m_currentDesktop;
KWIN_SINGLETON_VARIABLE(FocusChain, s_manager)
};
inline
bool FocusChain::contains(AbstractClient *client) const
{
return m_mostRecentlyUsed.contains(client);
}
inline
void FocusChain::setSeparateScreenFocus(bool enabled)
{
m_separateScreenFocus = enabled;
}
inline
void FocusChain::setActiveClient(AbstractClient *client)
{
m_activeClient = client;
}
inline
void FocusChain::setCurrentDesktop(uint previous, uint newDesktop)
{
Q_UNUSED(previous)
m_currentDesktop = newDesktop;
}
} // namespace
#endif // KWIN_FOCUS_CHAIN_H