1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
7     SPDX-FileCopyrightText: 2009 Martin Gräßlin <mgraesslin@kde.org>
8 
9     SPDX-License-Identifier: GPL-2.0-or-later
10 */
11 
12 #ifndef KWIN_TABBOX_H
13 #define KWIN_TABBOX_H
14 
15 #include <QKeySequence>
16 #include <QTimer>
17 #include <QModelIndex>
18 #include "utils.h"
19 #include "tabbox/tabboxhandler.h"
20 
21 class KConfigGroup;
22 class QAction;
23 class QMouseEvent;
24 class QKeyEvent;
25 class QWheelEvent;
26 
27 namespace KWin
28 {
29 
30 class Workspace;
31 class AbstractClient;
32 class X11EventFilter;
33 namespace TabBox
34 {
35 class DesktopChainManager;
36 class TabBoxConfig;
37 class TabBox;
38 class TabBoxHandlerImpl : public TabBoxHandler
39 {
40 public:
41     explicit TabBoxHandlerImpl(TabBox* tabBox);
42     ~TabBoxHandlerImpl() override;
43 
44     int activeScreen() const override;
45     QWeakPointer< TabBoxClient > activeClient() const override;
46     int currentDesktop() const override;
47     QString desktopName(TabBoxClient* client) const override;
48     QString desktopName(int desktop) const override;
49     bool isKWinCompositing() const override;
50     QWeakPointer< TabBoxClient > nextClientFocusChain(TabBoxClient* client) const override;
51     QWeakPointer< TabBoxClient > firstClientFocusChain() const override;
52     bool isInFocusChain (TabBoxClient* client) const override;
53     int nextDesktopFocusChain(int desktop) const override;
54     int numberOfDesktops() const override;
55     TabBoxClientList stackingOrder() const override;
56     void elevateClient(TabBoxClient* c, QWindow *tabbox, bool elevate) const override;
57     void raiseClient(TabBoxClient *client) const override;
58     void restack(TabBoxClient *c, TabBoxClient *under) override;
59     void shadeClient(TabBoxClient *c, bool b) const override;
60     QWeakPointer< TabBoxClient > clientToAddToList(KWin::TabBox::TabBoxClient* client, int desktop) const override;
61     QWeakPointer< TabBoxClient > desktopClient() const override;
62     void activateAndClose() override;
63     void highlightWindows(TabBoxClient *window = nullptr, QWindow *controller = nullptr) override;
64     bool noModifierGrab() const override;
65 
66 private:
67     bool checkDesktop(TabBoxClient* client, int desktop) const;
68     bool checkActivity(TabBoxClient* client) const;
69     bool checkApplications(TabBoxClient* client) const;
70     bool checkMinimized(TabBoxClient* client) const;
71     bool checkMultiScreen(TabBoxClient* client) const;
72 
73     TabBox* m_tabBox;
74     DesktopChainManager* m_desktopFocusChain;
75 };
76 
77 class TabBoxClientImpl : public TabBoxClient
78 {
79 public:
80     explicit TabBoxClientImpl(AbstractClient *client);
81     ~TabBoxClientImpl() override;
82 
83     QString caption() const override;
84     QIcon icon() const override;
85     bool isMinimized() const override;
86     int x() const override;
87     int y() const override;
88     int width() const override;
89     int height() const override;
90     bool isCloseable() const override;
91     void close() override;
92     bool isFirstInTabBox() const override;
93     QUuid internalId() const override;
94 
client()95     AbstractClient* client() const {
96         return m_client;
97     }
98 
99 private:
100     AbstractClient* m_client;
101 };
102 
103 class KWIN_EXPORT TabBox : public QObject
104 {
105     Q_OBJECT
106 public:
107     ~TabBox() override;
108 
109     /**
110      * Returns the currently displayed client ( only works in TabBoxWindowsMode ).
111      * Returns 0 if no client is displayed.
112      */
113     AbstractClient *currentClient();
114 
115     /**
116      * Returns the list of clients potentially displayed ( only works in
117      * TabBoxWindowsMode ).
118      * Returns an empty list if no clients are available.
119      */
120     QList<AbstractClient*> currentClientList();
121 
122     /**
123      * Returns the currently displayed virtual desktop ( only works in
124      * TabBoxDesktopListMode )
125      * Returns -1 if no desktop is displayed.
126      */
127     int currentDesktop();
128 
129     /**
130      * Returns the list of desktops potentially displayed ( only works in
131      * TabBoxDesktopListMode )
132      * Returns an empty list if no are available.
133      */
134     QList< int > currentDesktopList();
135 
136     /**
137      * Change the currently selected client, and notify the effects.
138      *
139      * @see setCurrentDesktop
140      */
141     void setCurrentClient(AbstractClient *newClient);
142 
143     /**
144      * Change the currently selected desktop, and notify the effects.
145      *
146      * @see setCurrentClient
147      */
148     void setCurrentDesktop(int newDesktop);
149 
150     /**
151      * Sets the current mode to \a mode, either TabBoxDesktopListMode or TabBoxWindowsMode
152      *
153      * @see mode
154      */
155     void setMode(TabBoxMode mode);
mode()156     TabBoxMode mode() const {
157         return m_tabBoxMode;
158     }
159 
160     /**
161      * Resets the tab box to display the active client in TabBoxWindowsMode, or the
162      * current desktop in TabBoxDesktopListMode
163      */
164     void reset(bool partial_reset = false);
165 
166     /**
167      * Shows the next or previous item, depending on \a next
168      */
169     void nextPrev(bool next = true);
170 
171     /**
172      * Shows the tab box after some delay.
173      *
174      * If the 'ShowDelay' setting is false, show() is simply called.
175      *
176      * Otherwise, we start a timer for the delay given in the settings and only
177      * do a show() when it times out.
178      *
179      * This means that you can alt-tab between windows and you don't see the
180      * tab box immediately. Not only does this make alt-tabbing faster, it gives
181      * less 'flicker' to the eyes. You don't need to see the tab box if you're
182      * just quickly switching between 2 or 3 windows. It seems to work quite
183      * nicely.
184      */
185     void delayedShow();
186 
187     /**
188      * Notify effects that the tab box is being hidden.
189      */
190     void hide(bool abort = false);
191 
192     /**
193      * Increases the reference count, preventing the default tabbox from showing.
194      *
195      * @see unreference
196      * @see isDisplayed
197      */
reference()198     void reference() {
199         ++m_displayRefcount;
200     }
201 
202     /**
203      * Decreases the reference count. Only when the reference count is 0 will
204      * the default tab box be shown.
205      */
unreference()206     void unreference() {
207         --m_displayRefcount;
208     }
209 
210     /**
211      * Returns whether the tab box is being displayed, either natively or by an
212      * effect.
213      *
214      * @see reference
215      * @see unreference
216      */
isDisplayed()217     bool isDisplayed() const {
218         return m_displayRefcount > 0;
219     }
220 
221     /**
222      * @returns @c true if TabBox is shown, @c false if replaced by Effect
223      */
isShown()224     bool isShown() const {
225         return m_isShown;
226     }
227 
228     bool handleMouseEvent(QMouseEvent *event);
229     bool handleWheelEvent(QWheelEvent *event);
230     void grabbedKeyEvent(QKeyEvent* event);
231 
isGrabbed()232     bool isGrabbed() const {
233         return m_tabGrab || m_desktopGrab;
234     }
235 
236     void initShortcuts();
237 
238     AbstractClient* nextClientStatic(AbstractClient*) const;
239     AbstractClient* previousClientStatic(AbstractClient*) const;
240     int nextDesktopStatic(int iDesktop) const;
241     int previousDesktopStatic(int iDesktop) const;
242     void keyPress(int key);
243     void modifiersReleased();
244 
forcedGlobalMouseGrab()245     bool forcedGlobalMouseGrab() const {
246         return m_forcedGlobalMouseGrab;
247     }
248 
noModifierGrab()249     bool noModifierGrab() const {
250         return m_noModifierGrab;
251     }
252     void setCurrentIndex(QModelIndex index, bool notifyEffects = true);
253 
254     static TabBox *self();
255     static TabBox *create(QObject *parent);
256 
257 public Q_SLOTS:
258     /**
259      * Notify effects that the tab box is being shown, and only display the
260      * default tab box QFrame if no effect has referenced the tab box.
261      */
262     void show();
263     void close(bool abort = false);
264     void accept(bool closeTabBox = true);
265     void slotWalkThroughDesktops();
266     void slotWalkBackThroughDesktops();
267     void slotWalkThroughDesktopList();
268     void slotWalkBackThroughDesktopList();
269     void slotWalkThroughWindows();
270     void slotWalkBackThroughWindows();
271     void slotWalkThroughWindowsAlternative();
272     void slotWalkBackThroughWindowsAlternative();
273     void slotWalkThroughCurrentAppWindows();
274     void slotWalkBackThroughCurrentAppWindows();
275     void slotWalkThroughCurrentAppWindowsAlternative();
276     void slotWalkBackThroughCurrentAppWindowsAlternative();
277 
278     void handlerReady();
279 
280     bool toggle(ElectricBorder eb);
281 
282 Q_SIGNALS:
283     void tabBoxAdded(int);
284     void tabBoxClosed();
285     void tabBoxUpdated();
286     void tabBoxKeyEvent(QKeyEvent*);
287 
288 private:
289     explicit TabBox(QObject *parent);
290     void loadConfig(const KConfigGroup& config, TabBoxConfig& tabBoxConfig);
291 
292     bool startKDEWalkThroughWindows(TabBoxMode mode);   // TabBoxWindowsMode | TabBoxWindowsAlternativeMode
293     bool startWalkThroughDesktops(TabBoxMode mode);   // TabBoxDesktopMode | TabBoxDesktopListMode
294     bool startWalkThroughDesktops();
295     bool startWalkThroughDesktopList();
296     void navigatingThroughWindows(bool forward, const QKeySequence &shortcut, TabBoxMode mode);   // TabBoxWindowsMode | TabBoxWindowsAlternativeMode
297     void KDEWalkThroughWindows(bool forward);
298     void CDEWalkThroughWindows(bool forward);
299     void walkThroughDesktops(bool forward);
300     void KDEOneStepThroughWindows(bool forward, TabBoxMode mode);   // TabBoxWindowsMode | TabBoxWindowsAlternativeMode
301     void oneStepThroughDesktops(bool forward, TabBoxMode mode);   // TabBoxDesktopMode | TabBoxDesktopListMode
302     void oneStepThroughDesktops(bool forward);
303     void oneStepThroughDesktopList(bool forward);
304     bool establishTabBoxGrab();
305     void removeTabBoxGrab();
306     template <typename Slot>
307     void key(const char *actionName, Slot slot, const QKeySequence &shortcut = QKeySequence());
308 
309     void shadeActivate(AbstractClient *c);
310 
311     bool toggleMode(TabBoxMode mode);
312 
313 private Q_SLOTS:
314     void reconfigure();
315     void globalShortcutChanged(QAction *action, const QKeySequence &seq);
316 
317 private:
318     TabBoxMode m_tabBoxMode;
319     TabBoxHandlerImpl* m_tabBox;
320     bool m_delayShow;
321     int m_delayShowTime;
322 
323     QTimer m_delayedShowTimer;
324     int m_displayRefcount;
325 
326     TabBoxConfig m_defaultConfig;
327     TabBoxConfig m_alternativeConfig;
328     TabBoxConfig m_defaultCurrentApplicationConfig;
329     TabBoxConfig m_alternativeCurrentApplicationConfig;
330     TabBoxConfig m_desktopConfig;
331     TabBoxConfig m_desktopListConfig;
332     // false if an effect has referenced the tabbox
333     // true if tabbox is active (independent on showTabbox setting)
334     bool m_isShown;
335     bool m_desktopGrab;
336     bool m_tabGrab;
337     // true if tabbox is in modal mode which does not require holding a modifier
338     bool m_noModifierGrab;
339     QKeySequence m_cutWalkThroughDesktops, m_cutWalkThroughDesktopsReverse;
340     QKeySequence m_cutWalkThroughDesktopList, m_cutWalkThroughDesktopListReverse;
341     QKeySequence m_cutWalkThroughWindows, m_cutWalkThroughWindowsReverse;
342     QKeySequence m_cutWalkThroughWindowsAlternative, m_cutWalkThroughWindowsAlternativeReverse;
343     QKeySequence m_cutWalkThroughCurrentAppWindows, m_cutWalkThroughCurrentAppWindowsReverse;
344     QKeySequence m_cutWalkThroughCurrentAppWindowsAlternative, m_cutWalkThroughCurrentAppWindowsAlternativeReverse;
345     bool m_forcedGlobalMouseGrab;
346     bool m_ready; // indicates whether the config is completely loaded
347     QList<ElectricBorder> m_borderActivate, m_borderAlternativeActivate;
348     QHash<ElectricBorder, QAction *> m_touchActivate;
349     QHash<ElectricBorder, QAction *> m_touchAlternativeActivate;
350     QScopedPointer<X11EventFilter> m_x11EventFilter;
351 
352     static TabBox *s_self;
353 };
354 
355 inline
self()356 TabBox *TabBox::self()
357 {
358     return s_self;
359 }
360 
361 } // namespace TabBox
362 } // namespace
363 #endif
364