1 | /******************************************************************** |
2 | KWin - the KDE window manager |
3 | This file is part of the KDE project. |
4 | |
5 | Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org> |
6 | |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | *********************************************************************/ |
20 | |
21 | #ifndef TABBOXHANDLER_H |
22 | #define TABBOXHANDLER_H |
23 | |
24 | #include "tabboxconfig.h" |
25 | |
26 | #include <QModelIndex> |
27 | #include <QPixmap> |
28 | #include <QString> |
29 | #include <X11/Xlib.h> |
30 | #include <fixx11h.h> |
31 | #include <xcb/xcb.h> |
32 | |
33 | /** |
34 | * @file |
35 | * This file contains the classes which hide KWin core from tabbox. |
36 | * It defines the pure virtual classes TabBoxHandler and TabBoxClient. |
37 | * The classes have to be implemented in KWin Core. |
38 | * |
39 | * @author Martin Gräßlin <mgraesslin@kde.org> |
40 | * @since 4.4 |
41 | */ |
42 | |
43 | class QKeyEvent; |
44 | |
45 | namespace KWin |
46 | { |
47 | /** |
48 | * The TabBox is a model based view for displaying a list while switching windows or desktops. |
49 | * This functionality is mostly referred as Alt+Tab. TabBox itself does not provide support for |
50 | * switching windows or desktops. This has to be done outside of TabBox inside an independent controller. |
51 | * |
52 | * The main entrance point to TabBox is the class TabBoxHandler, which has to be subclassed and implemented. |
53 | * The class TabBoxClient, which represents a window client inside TabBox, has to be implemented as well. |
54 | * |
55 | * The behavior of the TabBox is defined by the TabBoxConfig and has to be set in the TabBoxHandler. |
56 | * If the TabBox should be used to switch desktops as well as clients it is sufficient to just provide |
57 | * different TabBoxConfig objects instead of creating an own handler for each mode. |
58 | * |
59 | * In order to use the TabBox the TabBoxConfig has to be set. This defines if the model for desktops or for |
60 | * clients will be used. The model has to be initialized by calling TabBoxHandler::createModel(), as the |
61 | * model is undefined when the TabBox is not active. The TabBox is activated by TabBoxHandler::show(). |
62 | * Depending on the current set TabBoxConfig it is possible that the |
63 | * highlight windows effect activated and that the view is not displayed at all. As already mentioned |
64 | * the TabBox does not handle any updating of the selected item. This has to be done by invoking |
65 | * TabBoxHandler::setCurrentIndex(). Nevertheless the TabBoxHandler provides methods to query for the |
66 | * model index or the next or previous item, for a cursor position or for a given item (that is |
67 | * TabBoxClient or desktop). By invoking TabBoxHandler::hide() the view, the |
68 | * optional highlight windows effect are removed. The model is invalidated immediately. So if it is |
69 | * necessary to retrieve the last selected item this has to be done before calling the hide method. |
70 | * |
71 | * The layout of the TabBox View and the items is completely customizable. Therefore TabBox provides |
72 | * a widget LayoutConfig which includes a live preview (in kcmkwin/kwintabbox). The layout of items |
73 | * can be defined by an xml document. That way the user is able to define own custom layouts. The view |
74 | * itself is made up of two widgets: one to show the complete list and one to show only the selected |
75 | * item. This way it is possible to have a view which shows for example a list containing only small |
76 | * icons and nevertheless show the title of the currently selected client. |
77 | */ |
78 | namespace TabBox |
79 | { |
80 | class DesktopModel; |
81 | class ClientModel; |
82 | class TabBoxConfig; |
83 | class TabBoxClient; |
84 | class TabBoxHandlerPrivate; |
85 | typedef QList< QWeakPointer< TabBoxClient > > TabBoxClientList; |
86 | |
87 | /** |
88 | * This class is a wrapper around KWin Workspace. It is used for accessing the |
89 | * required core methods from inside TabBox and has to be implemented in KWin core. |
90 | * |
91 | * @author Martin Gräßlin <mgraesslin@kde.org> |
92 | * @since 4.4 |
93 | */ |
94 | class TabBoxHandler : public QObject |
95 | { |
96 | Q_OBJECT |
97 | public: |
98 | TabBoxHandler(); |
99 | virtual ~TabBoxHandler(); |
100 | |
101 | /** |
102 | * @return The id of the active screen |
103 | */ |
104 | virtual int activeScreen() const = 0; |
105 | /** |
106 | * @return The current active TabBoxClient or NULL |
107 | * if there is no active client. |
108 | */ |
109 | virtual QWeakPointer<TabBoxClient> activeClient() const = 0; |
110 | /** |
111 | * @param client The client which is starting point to find the next client |
112 | * @return The next TabBoxClient in focus chain |
113 | */ |
114 | virtual QWeakPointer<TabBoxClient> nextClientFocusChain(TabBoxClient* client) const = 0; |
115 | /** |
116 | * This method is used by the ClientModel to find an entrance into the focus chain in case |
117 | * there is no active Client. |
118 | * |
119 | * @return The first Client of the focus chain |
120 | * @since 4.9.1 |
121 | **/ |
122 | virtual QWeakPointer<TabBoxClient> firstClientFocusChain() const = 0; |
123 | /** |
124 | * Checks whether the given @p client is part of the focus chain at all. |
125 | * This is useful to figure out whether the currently active Client can be used |
126 | * as a starting point to construct the recently used list. |
127 | * |
128 | * In case the @p client is not in the focus chain it is recommended to use the |
129 | * Client returned by @link firstClientFocusChain. |
130 | * |
131 | * The method accepts a @c null Client and in that case @c false is returned. |
132 | * @param client The Client to check whether it is in the Focus Chain |
133 | * @return @c true in case the Client is part of the focus chain, @c false otherwise. |
134 | * @since 4.9.2 |
135 | **/ |
136 | virtual bool isInFocusChain(TabBoxClient* client) const = 0; |
137 | /** |
138 | * @param client The client whose desktop name should be retrieved |
139 | * @return The desktop name of the given TabBoxClient. If the client is |
140 | * on all desktops the name of current desktop will be returned. |
141 | */ |
142 | virtual QString desktopName(TabBoxClient* client) const = 0; |
143 | /** |
144 | * @param desktop The desktop whose name should be retrieved |
145 | * @return The desktop name of given desktop |
146 | */ |
147 | virtual QString desktopName(int desktop) const = 0; |
148 | /** |
149 | * @return The number of current desktop |
150 | */ |
151 | virtual int currentDesktop() const = 0; |
152 | /** |
153 | * @return The number of virtual desktops |
154 | */ |
155 | virtual int numberOfDesktops() const = 0; |
156 | /** |
157 | * @param desktop The desktop which is the starting point to find the next desktop |
158 | * @return The next desktop in the current focus chain. |
159 | */ |
160 | virtual int nextDesktopFocusChain(int desktop) const = 0; |
161 | |
162 | /** |
163 | * whether KWin is currently compositing and it's related features (elevating) can be used |
164 | */ |
165 | virtual bool isKWinCompositing() const = 0; |
166 | |
167 | /** |
168 | * De-/Elevate a client using the compositor (if enabled) |
169 | */ |
170 | virtual void elevateClient(TabBoxClient* c, WId tabbox, bool elevate) const = 0; |
171 | |
172 | /** |
173 | * Raise a client (w/o activating it) |
174 | */ |
175 | virtual void raiseClient(TabBoxClient* c) const = 0; |
176 | |
177 | /** |
178 | * @param c The client to be restacked |
179 | * @param under The client the other one will be placed below |
180 | */ |
181 | virtual void restack(TabBoxClient *c, TabBoxClient *under) = 0; |
182 | |
183 | /** |
184 | * @return The current stacking order of TabBoxClients |
185 | */ |
186 | virtual TabBoxClientList stackingOrder() const = 0; |
187 | /** |
188 | * Determines if given client will be added to the list: |
189 | * <UL> |
190 | * <LI>Depends on desktop</LI> |
191 | * <LI>if the client wants to have tab focus.</LI> |
192 | * <LI>The client won't be added if it has modal dialogs</LI> |
193 | * <LI>In that case the modal dialog will be returned if it isn't already |
194 | * included</LI> |
195 | * <LI>Won't be added if it isn't on active screen when using separate |
196 | * screen focus</LI> |
197 | * </UL> |
198 | * @param client The client to be checked for inclusion |
199 | * @param desktop The desktop the client should be on. This is irrelevant if allDesktops is set |
200 | * @param allDesktops Add clients from all desktops or only from current |
201 | * @return The client to be included in the list or NULL if it isn't to be included |
202 | */ |
203 | virtual QWeakPointer<TabBoxClient> clientToAddToList(TabBoxClient* client, int desktop) const = 0; |
204 | /** |
205 | * @return The first desktop window in the stacking order. |
206 | */ |
207 | virtual QWeakPointer<TabBoxClient> desktopClient() const = 0; |
208 | /** |
209 | * Activates the currently selected client and closes the TabBox. |
210 | **/ |
211 | virtual void activateAndClose() = 0; |
212 | |
213 | /** |
214 | * @return The currently used TabBoxConfig |
215 | */ |
216 | const TabBoxConfig& config() const; |
217 | /** |
218 | * Call this method when you want to change the currently used TabBoxConfig. |
219 | * It fires the signal configChanged. |
220 | * @param config Updates the currently used TabBoxConfig to config |
221 | */ |
222 | void setConfig(const TabBoxConfig& config); |
223 | |
224 | /** |
225 | * Call this method to show the TabBoxView. Depending on current |
226 | * configuration this method might not do anything. |
227 | * If highlight windows effect is to be used it will be activated. |
228 | * Highlight windows and outline are not shown if |
229 | * TabBoxConfig::TabBoxMode is TabBoxConfig::DesktopTabBox. |
230 | * @see TabBoxConfig::isShowTabBox |
231 | * @see TabBoxConfig::isHighlightWindows |
232 | */ |
233 | void show(); |
234 | /** |
235 | * Hides the TabBoxView if shown. |
236 | * Deactivates highlight windows effect if active. |
237 | * @see show |
238 | */ |
239 | void hide(bool abort = false); |
240 | |
241 | /** |
242 | * Sets the current model index in the view and updates |
243 | * highlight windows if active. |
244 | * @param index The current Model index |
245 | */ |
246 | void setCurrentIndex(const QModelIndex& index); |
247 | /** |
248 | * @returns the current index |
249 | **/ |
250 | const QModelIndex ¤tIndex() const; |
251 | |
252 | /** |
253 | * Retrieves the next or previous item of the current item. |
254 | * @param forward next or previous item |
255 | * @return The next or previous item. If there is no matching item |
256 | * the current item will be returned. |
257 | */ |
258 | QModelIndex nextPrev(bool forward) const; |
259 | |
260 | /** |
261 | * Initializes the model based on the current config. |
262 | * This method has to be invoked before showing the TabBox. |
263 | * It can also be invoked when clients are added or removed. |
264 | * In that case partialReset has to be true. |
265 | * |
266 | * @param partialReset Keep the currently selected item or regenerate everything |
267 | */ |
268 | void createModel(bool partialReset = false); |
269 | |
270 | /** |
271 | * @param desktop The desktop whose index should be retrieved |
272 | * @return The model index of given desktop. If TabBoxMode is not |
273 | * TabBoxConfig::DesktopTabBox an invalid model index will be returned. |
274 | */ |
275 | QModelIndex desktopIndex(int desktop) const; |
276 | /** |
277 | * @return The current list of desktops. |
278 | * If TabBoxMode is not TabBoxConfig::DesktopTabBox an empty list will |
279 | * be returned. |
280 | * @see DesktopModel::desktopList |
281 | */ |
282 | QList< int > desktopList() const; |
283 | /** |
284 | * @return The desktop for given model index. If the index is not valid |
285 | * or TabBoxMode is not TabBoxConfig::DesktopTabBox -1 will be returned. |
286 | * @see DesktopModel::desktopIndex |
287 | */ |
288 | int desktop(const QModelIndex& index) const; |
289 | |
290 | /** |
291 | * Handles additional grabbed key events by the TabBox controller. |
292 | * @param event The key event which has been grabbed |
293 | */ |
294 | virtual void grabbedKeyEvent(QKeyEvent* event) const; |
295 | /** |
296 | * @param pos The position to be tested in global coordinates |
297 | * @return True if the view contains the point, otherwise false. |
298 | */ |
299 | bool containsPos(const QPoint& pos) const; |
300 | /** |
301 | * @param client The TabBoxClient whose index should be returned |
302 | * @return Returns the ModelIndex of given TabBoxClient or an invalid ModelIndex |
303 | * if the model does not contain the given TabBoxClient. |
304 | * @see ClientModel::index |
305 | */ |
306 | QModelIndex index(QWeakPointer<TabBoxClient> client) const; |
307 | /** |
308 | * @return Returns the current list of TabBoxClients. |
309 | * If TabBoxMode is not TabBoxConfig::ClientTabBox an empty list will |
310 | * be returned. |
311 | * @see ClientModel::clientList |
312 | */ |
313 | TabBoxClientList clientList() const; |
314 | /** |
315 | * @param index The index of the client to be returned |
316 | * @return Returns the TabBoxClient at given model index. If |
317 | * the index is invalid, does not point to a Client or the list |
318 | * is empty, NULL will be returned. |
319 | */ |
320 | TabBoxClient* client(const QModelIndex& index) const; |
321 | /** |
322 | * @return The first model index. That is the model index at position 0, 0. |
323 | * It is valid, as desktop has at least one desktop and if there are no |
324 | * clients an empty item is created. |
325 | */ |
326 | QModelIndex first() const; |
327 | |
328 | void setEmbedded(WId wid); |
329 | WId embedded() const; |
330 | void setEmbeddedOffset(const QPoint &offset); |
331 | const QPoint &embeddedOffset() const; |
332 | void setEmbeddedSize(const QSize &size); |
333 | const QSize &embeddedSize() const; |
334 | void setEmbeddedAlignment(Qt::Alignment alignment); |
335 | Qt::Alignment embeddedAlignment() const; |
336 | void resetEmbedded(); |
337 | |
338 | signals: |
339 | /** |
340 | * This signal is fired when the TabBoxConfig changes |
341 | * @see setConfig |
342 | */ |
343 | void configChanged(); |
344 | void embeddedChanged(bool enabled); |
345 | void selectedIndexChanged(); |
346 | |
347 | private slots: |
348 | void updateHighlightWindows(); |
349 | |
350 | private: |
351 | friend class TabBoxHandlerPrivate; |
352 | TabBoxHandlerPrivate* d; |
353 | }; |
354 | |
355 | /** |
356 | * This class is a wrapper around a KWin Client. It is used for accessing the |
357 | * required client methods from inside TabBox and has to be implemented in KWin core. |
358 | * |
359 | * @author Martin Gräßlin <mgraesslin@kde.org> |
360 | * @since 4.4 |
361 | */ |
362 | class TabBoxClient |
363 | { |
364 | public: |
365 | TabBoxClient(); |
366 | virtual ~TabBoxClient(); |
367 | |
368 | /** |
369 | * @return The caption of the client |
370 | */ |
371 | virtual QString caption() const = 0; |
372 | /** |
373 | * @param size Requested size of the icon |
374 | * @return The icon of the client |
375 | */ |
376 | virtual QPixmap icon(const QSize& size = QSize(32, 32)) const = 0; |
377 | /** |
378 | * @return The window Id of the client |
379 | */ |
380 | virtual WId window() const = 0; |
381 | /** |
382 | * @return Minimized state of the client |
383 | */ |
384 | virtual bool isMinimized() const = 0; |
385 | virtual int x() const = 0; |
386 | virtual int y() const = 0; |
387 | virtual int width() const = 0; |
388 | virtual int height() const = 0; |
389 | virtual bool isCloseable() const = 0; |
390 | virtual void close() = 0; |
391 | virtual bool isFirstInTabBox() const = 0; |
392 | }; |
393 | |
394 | /** |
395 | * Pointer to the global TabBoxHandler object. |
396 | **/ |
397 | extern TabBoxHandler* tabBox; |
398 | |
399 | } // namespace TabBox |
400 | } // namespace KWin |
401 | |
402 | #endif // TABBOXHANDLER_H |
403 | |