1/********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
43class QKeyEvent;
44
45namespace 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*/
78namespace TabBox
79{
80class DesktopModel;
81class ClientModel;
82class TabBoxConfig;
83class TabBoxClient;
84class TabBoxHandlerPrivate;
85typedef 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*/
94class TabBoxHandler : public QObject
95{
96 Q_OBJECT
97public:
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 &currentIndex() 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
338signals:
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
347private slots:
348 void updateHighlightWindows();
349
350private:
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*/
362class TabBoxClient
363{
364public:
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 **/
397extern TabBoxHandler* tabBox;
398
399} // namespace TabBox
400} // namespace KWin
401
402#endif // TABBOXHANDLER_H
403