1/********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
8
9This program is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2 of the License, or
12(at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program. If not, see <http://www.gnu.org/licenses/>.
21*********************************************************************/
22
23#ifndef KWIN_WORKSPACE_H
24#define KWIN_WORKSPACE_H
25
26// kwin
27#include <kdecoration.h>
28#include "sm.h"
29#include "utils.h"
30// Qt
31#include <QTimer>
32#include <QVector>
33// X
34#include <X11/Xlib.h>
35
36// TODO: Cleanup the order of things in this .h file
37
38class QStringList;
39class KConfig;
40class KActionCollection;
41class KShortcut;
42class KStartupInfo;
43class KStartupInfoId;
44class KStartupInfoData;
45
46namespace KWin
47{
48
49namespace Xcb
50{
51class Window;
52}
53
54class Client;
55class KillWindow;
56class ShortcutDialog;
57class UserActionsMenu;
58class Compositor;
59
60class Workspace : public QObject, public KDecorationDefines
61{
62 Q_OBJECT
63public:
64 explicit Workspace(bool restore = false);
65 virtual ~Workspace();
66
67 static Workspace* self() {
68 return _self;
69 }
70
71 bool workspaceEvent(XEvent*);
72 bool workspaceEvent(QEvent*);
73
74 bool hasClient(const Client*);
75
76 template<typename T> Client* findClient(T predicate) const;
77 template<typename T1, typename T2> void forEachClient(T1 procedure, T2 predicate);
78 template<typename T> void forEachClient(T procedure);
79 template<typename T> Unmanaged* findUnmanaged(T predicate) const;
80 template<typename T1, typename T2> void forEachUnmanaged(T1 procedure, T2 predicate);
81 template<typename T> void forEachUnmanaged(T procedure);
82
83 QRect clientArea(clientAreaOption, const QPoint& p, int desktop) const;
84 QRect clientArea(clientAreaOption, const Client* c) const;
85 QRect clientArea(clientAreaOption, int screen, int desktop) const;
86
87 QRegion restrictedMoveArea(int desktop, StrutAreas areas = StrutAreaAll) const;
88
89 bool initializing() const;
90
91 /**
92 * Returns the active client, i.e. the client that has the focus (or None
93 * if no client has the focus)
94 */
95 Client* activeClient() const;
96 /**
97 * Client that was activated, but it's not yet really activeClient(), because
98 * we didn't process yet the matching FocusIn event. Used mostly in focus
99 * stealing prevention code.
100 */
101 Client* mostRecentlyActivatedClient() const;
102
103 Client* clientUnderMouse(int screen) const;
104
105 void activateClient(Client*, bool force = false);
106 void requestFocus(Client* c, bool force = false);
107 void takeActivity(Client* c, int flags, bool handled); // Flags are ActivityFlags
108 void handleTakeActivity(Client* c, xcb_timestamp_t timestamp, int flags); // Flags are ActivityFlags
109 bool allowClientActivation(const Client* c, xcb_timestamp_t time = -1U, bool focus_in = false,
110 bool ignore_desktop = false);
111 void restoreFocus();
112 void gotFocusIn(const Client*);
113 void setShouldGetFocus(Client*);
114 bool activateNextClient(Client* c);
115 bool focusChangeEnabled() {
116 return block_focus == 0;
117 }
118
119 /**
120 * Indicates that the client c is being moved around by the user.
121 */
122 void setClientIsMoving(Client* c);
123
124 QPoint adjustClientPosition(Client* c, QPoint pos, bool unrestricted, double snapAdjust = 1.0);
125 QRect adjustClientSize(Client* c, QRect moveResizeGeom, int mode);
126 void raiseClient(Client* c, bool nogroup = false);
127 void lowerClient(Client* c, bool nogroup = false);
128 void raiseClientRequest(Client* c, NET::RequestSource src, xcb_timestamp_t timestamp);
129 void lowerClientRequest(Client* c, NET::RequestSource src, xcb_timestamp_t timestamp);
130 void restackClientUnderActive(Client*);
131 void restack(Client *c, Client *under);
132 void updateClientLayer(Client* c);
133 void raiseOrLowerClient(Client*);
134 void resetUpdateToolWindowsTimer();
135 void restoreSessionStackingOrder(Client* c);
136 void updateStackingOrder(bool propagate_new_clients = false);
137 void forceRestacking();
138
139 void clientHidden(Client*);
140 void clientAttentionChanged(Client* c, bool set);
141
142 /**
143 * @return List of clients currently managed by Workspace
144 **/
145 const ClientList &clientList() const {
146 return clients;
147 }
148 /**
149 * @return List of unmanaged "clients" currently registered in Workspace
150 **/
151 const UnmanagedList &unmanagedList() const {
152 return unmanaged;
153 }
154 /**
155 * @return List of desktop "clients" currently managed by Workspace
156 **/
157 const ClientList &desktopList() const {
158 return desktops;
159 }
160 /**
161 * @return List of deleted "clients" currently managed by Workspace
162 **/
163 const DeletedList &deletedList() const {
164 return deleted;
165 }
166
167#ifdef KWIN_BUILD_SCREENEDGES
168 void stackScreenEdgesUnderOverrideRedirect();
169#endif
170
171public:
172 QPoint cascadeOffset(const Client *c) const;
173
174private:
175 Compositor *m_compositor;
176
177 //-------------------------------------------------
178 // Unsorted
179
180public:
181 bool isOnCurrentHead();
182 // True when performing Workspace::updateClientArea().
183 // The calls below are valid only in that case.
184 bool inUpdateClientArea() const;
185 QRegion previousRestrictedMoveArea(int desktop, StrutAreas areas = StrutAreaAll) const;
186 QVector< QRect > previousScreenSizes() const;
187 int oldDisplayWidth() const;
188 int oldDisplayHeight() const;
189
190 KActionCollection* actionCollection() const {
191 return keys;
192 }
193 KActionCollection* disableShortcutsKeys() const {
194 return disable_shortcuts_keys;
195 }
196 KActionCollection* clientKeys() const {
197 return client_keys;
198 }
199
200 /**
201 * Returns the list of clients sorted in stacking order, with topmost client
202 * at the last position
203 */
204 const ToplevelList& stackingOrder() const;
205 ToplevelList xStackingOrder() const;
206 ClientList ensureStackingOrder(const ClientList& clients) const;
207
208 Client* topClientOnDesktop(int desktop, int screen, bool unconstrained = false,
209 bool only_normal = true) const;
210 Client* findDesktop(bool topmost, int desktop) const;
211 void sendClientToDesktop(Client* c, int desktop, bool dont_activate);
212 void windowToPreviousDesktop(Client* c);
213 void windowToNextDesktop(Client* c);
214 void sendClientToScreen(Client* c, int screen);
215
216 /**
217 * Shows the menu operations menu for the client and makes it active if
218 * it's not already.
219 */
220 void showWindowMenu(const QRect& pos, Client* cl);
221 const UserActionsMenu *userActionsMenu() const {
222 return m_userActionsMenu;
223 }
224
225 void updateMinimizedOfTransients(Client*);
226 void updateOnAllDesktopsOfTransients(Client*);
227 void checkTransients(xcb_window_t w);
228
229 void performWindowOperation(Client* c, WindowOperation op);
230
231 void storeSession(KConfig* config, SMSavePhase phase);
232 void storeClient(KConfigGroup &cg, int num, Client *c);
233 void storeSubSession(const QString &name, QSet<QByteArray> sessionIds);
234 void loadSubSessionInfo(const QString &name);
235
236 SessionInfo* takeSessionInfo(Client*);
237
238 // D-Bus interface
239 bool waitForCompositingSetup();
240 QString supportInformation() const;
241
242 void setCurrentScreen(int new_screen);
243
244 void setShowingDesktop(bool showing);
245 void resetShowingDesktop(bool keep_hidden);
246 bool showingDesktop() const;
247
248 void sendPingToWindow(xcb_window_t w, xcb_timestamp_t timestamp); // Called from Client::pingWindow()
249 void sendTakeActivity(Client* c, xcb_timestamp_t timestamp, long flags); // Called from Client::takeActivity()
250
251 void removeClient(Client*); // Only called from Client::destroyClient() or Client::releaseWindow()
252 void setActiveClient(Client*);
253 Group* findGroup(xcb_window_t leader) const;
254 void addGroup(Group* group);
255 void removeGroup(Group* group);
256 Group* findClientLeaderGroup(const Client* c) const;
257
258 void removeUnmanaged(Unmanaged*); // Only called from Unmanaged::release()
259 void removeDeleted(Deleted*);
260 void addDeleted(Deleted*, Toplevel*);
261
262 bool checkStartupNotification(xcb_window_t w, KStartupInfoId& id, KStartupInfoData& data);
263
264 void focusToNull(); // SELI TODO: Public?
265
266 bool forcedGlobalMouseGrab() const;
267 void clientShortcutUpdated(Client* c);
268 bool shortcutAvailable(const KShortcut& cut, Client* ignore = NULL) const;
269 bool globalShortcutsDisabled() const;
270 void disableGlobalShortcutsForClient(bool disable);
271
272 void sessionSaveStarted();
273 void sessionSaveDone();
274 void setWasUserInteraction();
275 bool wasUserInteraction() const;
276 bool sessionSaving() const;
277
278 int packPositionLeft(const Client* cl, int oldx, bool left_edge) const;
279 int packPositionRight(const Client* cl, int oldx, bool right_edge) const;
280 int packPositionUp(const Client* cl, int oldy, bool top_edge) const;
281 int packPositionDown(const Client* cl, int oldy, bool bottom_edge) const;
282
283 void cancelDelayFocus();
284 void requestDelayFocus(Client*);
285 void updateFocusMousePosition(const QPoint& pos);
286 QPoint focusMousePosition() const;
287
288 Client* getMovingClient() {
289 return movingClient;
290 }
291
292 /**
293 * @returns Whether we have a Compositor and it is active (Scene created)
294 **/
295 bool compositing() const;
296
297public slots:
298 // Keybindings
299 //void slotSwitchToWindow( int );
300 void slotWindowToDesktop();
301
302 //void slotWindowToListPosition( int );
303 void slotSwitchToScreen();
304 void slotWindowToScreen();
305 void slotSwitchToNextScreen();
306 void slotWindowToNextScreen();
307 void slotSwitchToPrevScreen();
308 void slotWindowToPrevScreen();
309 void slotToggleShowDesktop();
310
311 void slotWindowMaximize();
312 void slotWindowMaximizeVertical();
313 void slotWindowMaximizeHorizontal();
314 void slotWindowMinimize();
315 void slotWindowShade();
316 void slotWindowRaise();
317 void slotWindowLower();
318 void slotWindowRaiseOrLower();
319 void slotActivateAttentionWindow();
320 void slotWindowPackLeft();
321 void slotWindowPackRight();
322 void slotWindowPackUp();
323 void slotWindowPackDown();
324 void slotWindowGrowHorizontal();
325 void slotWindowGrowVertical();
326 void slotWindowShrinkHorizontal();
327 void slotWindowShrinkVertical();
328 void slotWindowQuickTileLeft();
329 void slotWindowQuickTileRight();
330 void slotWindowQuickTileTopLeft();
331 void slotWindowQuickTileTopRight();
332 void slotWindowQuickTileBottomLeft();
333 void slotWindowQuickTileBottomRight();
334
335 void slotSwitchWindowUp();
336 void slotSwitchWindowDown();
337 void slotSwitchWindowRight();
338 void slotSwitchWindowLeft();
339
340 void slotIncreaseWindowOpacity();
341 void slotLowerWindowOpacity();
342
343 void slotWindowOperations();
344 void slotWindowClose();
345 void slotWindowMove();
346 void slotWindowResize();
347 void slotWindowAbove();
348 void slotWindowBelow();
349 void slotWindowOnAllDesktops();
350 void slotWindowFullScreen();
351 void slotWindowNoBorder();
352
353 void slotWindowToNextDesktop();
354 void slotWindowToPreviousDesktop();
355 void slotWindowToDesktopRight();
356 void slotWindowToDesktopLeft();
357 void slotWindowToDesktopUp();
358 void slotWindowToDesktopDown();
359
360 void slotSettingsChanged(int category);
361
362 void reconfigure();
363 void slotReconfigure();
364
365 void slotKillWindow();
366
367 void slotSetupWindowShortcut();
368 void setupWindowShortcutDone(bool);
369 void slotToggleCompositing();
370 void slotInvertScreen();
371
372 void updateClientArea();
373
374 void slotActivateNextTab(); // Slot to move left the active Client.
375 void slotActivatePrevTab(); // Slot to move right the active Client.
376 void slotUntab(); // Slot to remove the active client from its group.
377
378private slots:
379 void desktopResized();
380 void slotUpdateToolWindows();
381 void delayFocus();
382 void slotBlockShortcuts(int data);
383 void slotReloadConfig();
384 void updateCurrentActivity(const QString &new_activity);
385 // virtual desktop handling
386 void moveClientsFromRemovedDesktops();
387 void slotDesktopCountChanged(uint previousCount, uint newCount);
388 void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop);
389
390Q_SIGNALS:
391 /**
392 * Emitted after the Workspace has setup the complete initialization process.
393 * This can be used to connect to for performing post-workspace initialization.
394 **/
395 void workspaceInitialized();
396
397 //Signals required for the scripting interface
398signals:
399 void desktopPresenceChanged(KWin::Client*, int);
400 void currentDesktopChanged(int, KWin::Client*);
401 void clientAdded(KWin::Client*);
402 void clientRemoved(KWin::Client*);
403 void clientActivated(KWin::Client*);
404 void clientDemandsAttentionChanged(KWin::Client*, bool);
405 void groupAdded(KWin::Group*);
406 void unmanagedAdded(KWin::Unmanaged*);
407 void deletedRemoved(KWin::Deleted*);
408 void propertyNotify(long a);
409 void configChanged();
410 void reinitializeCompositing();
411 /**
412 * This signels is emitted when ever the stacking order is change, ie. a window is risen
413 * or lowered
414 */
415 void stackingOrderChanged();
416
417private:
418 void init();
419 void initShortcuts();
420 void setupWindowShortcut(Client* c);
421 enum Direction {
422 DirectionNorth,
423 DirectionEast,
424 DirectionSouth,
425 DirectionWest
426 };
427 void switchWindow(Direction direction);
428
429 void propagateClients(bool propagate_new_clients); // Called only from updateStackingOrder
430 ToplevelList constrainedStackingOrder();
431 void raiseClientWithinApplication(Client* c);
432 void lowerClientWithinApplication(Client* c);
433 bool allowFullClientRaising(const Client* c, xcb_timestamp_t timestamp);
434 bool keepTransientAbove(const Client* mainwindow, const Client* transient);
435 void blockStackingUpdates(bool block);
436 void updateToolWindows(bool also_hide);
437 void fixPositionAfterCrash(xcb_window_t w, const xcb_get_geometry_reply_t *geom);
438 void saveOldScreenSizes();
439
440 /// This is the right way to create a new client
441 Client* createClient(xcb_window_t w, bool is_mapped);
442 void addClient(Client* c);
443 Unmanaged* createUnmanaged(xcb_window_t w);
444 void addUnmanaged(Unmanaged* c);
445
446 xcb_window_t findSpecialEventWindow(XEvent* e);
447
448 //---------------------------------------------------------------------
449
450 void closeActivePopup();
451 void updateClientArea(bool force);
452 void resetClientAreas(uint desktopCount);
453 void updateClientVisibilityOnDesktopChange(uint oldDesktop, uint newDesktop);
454 void activateClientOnNewDesktop(uint desktop);
455 Client *findClientToActivateOnDesktop(uint desktop);
456
457 QWidget* active_popup;
458 Client* active_popup_client;
459
460 void loadSessionInfo();
461 void addSessionInfo(KConfigGroup &cg);
462
463 QList<SessionInfo*> session;
464 static const char* windowTypeToTxt(NET::WindowType type);
465 static NET::WindowType txtToWindowType(const char* txt);
466 static bool sessionInfoWindowTypeMatch(Client* c, SessionInfo* info);
467
468 Client* active_client;
469 Client* last_active_client;
470 Client* most_recently_raised; // Used ONLY by raiseOrLowerClient()
471 Client* movingClient;
472 Client* pending_take_activity;
473
474 // Delay(ed) window focus timer and client
475 QTimer* delayFocusTimer;
476 Client* delayfocus_client;
477 QPoint focusMousePos;
478
479 ClientList clients;
480 ClientList desktops;
481 UnmanagedList unmanaged;
482 DeletedList deleted;
483
484 ToplevelList unconstrained_stacking_order; // Topmost last
485 ToplevelList stacking_order; // Topmost last
486 bool force_restacking;
487 mutable ToplevelList x_stacking; // From XQueryTree()
488 mutable bool x_stacking_dirty;
489 ClientList should_get_focus; // Last is most recent
490 ClientList attention_chain;
491
492 bool showing_desktop;
493 ClientList showing_desktop_clients;
494 int block_showing_desktop;
495
496 GroupList groups;
497
498 bool was_user_interaction;
499 bool session_saving;
500 int session_active_client;
501 int session_desktop;
502
503 int block_focus;
504
505 /**
506 * Holds the menu containing the user actions which is shown
507 * on e.g. right click the window decoration.
508 **/
509 UserActionsMenu *m_userActionsMenu;
510
511 void modalActionsSwitch(bool enabled);
512
513 KActionCollection* keys;
514 KActionCollection* client_keys;
515 KActionCollection* disable_shortcuts_keys;
516 ShortcutDialog* client_keys_dialog;
517 Client* client_keys_client;
518 bool global_shortcuts_disabled_for_client;
519
520 // Timer to collect requests for 'reconfigure'
521 QTimer reconfigureTimer;
522
523 QTimer updateToolWindowsTimer;
524
525 static Workspace* _self;
526
527 bool workspaceInit;
528
529 KStartupInfo* startup;
530
531 QVector<QRect> workarea; // Array of workareas for virtual desktops
532 // Array of restricted areas that window cannot be moved into
533 QVector<StrutRects> restrictedmovearea;
534 // Array of the previous restricted areas that window cannot be moved into
535 QVector<StrutRects> oldrestrictedmovearea;
536 QVector< QVector<QRect> > screenarea; // Array of workareas per xinerama screen for all virtual desktops
537 QVector< QRect > oldscreensizes; // array of previous sizes of xinerama screens
538 QSize olddisplaysize; // previous sizes od displayWidth()/displayHeight()
539
540 int set_active_client_recursion;
541 int block_stacking_updates; // When > 0, stacking updates are temporarily disabled
542 bool blocked_propagating_new_clients; // Propagate also new clients after enabling stacking updates?
543 QScopedPointer<Xcb::Window> m_nullFocus;
544 bool forced_global_mouse_grab;
545 friend class StackingUpdatesBlocker;
546
547 QScopedPointer<KillWindow> m_windowKiller;
548
549private:
550 friend bool performTransiencyCheck();
551 friend Workspace *workspace();
552};
553
554/**
555 * Helper for Workspace::blockStackingUpdates() being called in pairs (True/false)
556 */
557class StackingUpdatesBlocker
558{
559public:
560 explicit StackingUpdatesBlocker(Workspace* w)
561 : ws(w) {
562 ws->blockStackingUpdates(true);
563 }
564 ~StackingUpdatesBlocker() {
565 ws->blockStackingUpdates(false);
566 }
567
568private:
569 Workspace* ws;
570};
571
572class ColorMapper : public QObject
573{
574 Q_OBJECT
575public:
576 ColorMapper(QObject *parent);
577 virtual ~ColorMapper();
578public Q_SLOTS:
579 void update();
580private:
581 xcb_colormap_t m_default;
582 xcb_colormap_t m_installed;
583};
584
585//---------------------------------------------------------
586// Unsorted
587
588inline bool Workspace::initializing() const
589{
590 return workspaceInit;
591}
592
593inline Client* Workspace::activeClient() const
594{
595 return active_client;
596}
597
598inline Client* Workspace::mostRecentlyActivatedClient() const
599{
600 return should_get_focus.count() > 0 ? should_get_focus.last() : active_client;
601}
602
603inline void Workspace::addGroup(Group* group)
604{
605 emit groupAdded(group);
606 groups.append(group);
607}
608
609inline void Workspace::removeGroup(Group* group)
610{
611 groups.removeAll(group);
612}
613
614inline const ToplevelList& Workspace::stackingOrder() const
615{
616 // TODO: Q_ASSERT( block_stacking_updates == 0 );
617 return stacking_order;
618}
619
620inline void Workspace::setWasUserInteraction()
621{
622 was_user_interaction = true;
623}
624
625inline bool Workspace::wasUserInteraction() const
626{
627 return was_user_interaction;
628}
629
630inline void Workspace::sessionSaveStarted()
631{
632 session_saving = true;
633}
634
635inline bool Workspace::sessionSaving() const
636{
637 return session_saving;
638}
639
640inline bool Workspace::forcedGlobalMouseGrab() const
641{
642 return forced_global_mouse_grab;
643}
644
645inline bool Workspace::showingDesktop() const
646{
647 return showing_desktop;
648}
649
650inline bool Workspace::globalShortcutsDisabled() const
651{
652 return global_shortcuts_disabled_for_client;
653}
654
655inline void Workspace::forceRestacking()
656{
657 force_restacking = true;
658 StackingUpdatesBlocker blocker(this); // Do restacking if not blocked
659}
660
661inline void Workspace::updateFocusMousePosition(const QPoint& pos)
662{
663 focusMousePos = pos;
664}
665
666inline QPoint Workspace::focusMousePosition() const
667{
668 return focusMousePos;
669}
670
671template< typename T >
672inline Client* Workspace::findClient(T predicate) const
673{
674 if (Client* ret = findClientInList(clients, predicate))
675 return ret;
676 if (Client* ret = findClientInList(desktops, predicate))
677 return ret;
678 return NULL;
679}
680
681template< typename T1, typename T2 >
682inline void Workspace::forEachClient(T1 procedure, T2 predicate)
683{
684 for (ClientList::ConstIterator it = clients.constBegin(); it != clients.constEnd(); ++it)
685 if (predicate(const_cast<const Client*>(*it)))
686 procedure(*it);
687 for (ClientList::ConstIterator it = desktops.constBegin(); it != desktops.constEnd(); ++it)
688 if (predicate(const_cast<const Client*>(*it)))
689 procedure(*it);
690}
691
692template< typename T >
693inline void Workspace::forEachClient(T procedure)
694{
695 return forEachClient(procedure, TruePredicate());
696}
697
698template< typename T >
699inline Unmanaged* Workspace::findUnmanaged(T predicate) const
700{
701 return findUnmanagedInList(unmanaged, predicate);
702}
703
704template< typename T1, typename T2 >
705inline void Workspace::forEachUnmanaged(T1 procedure, T2 predicate)
706{
707 for (UnmanagedList::ConstIterator it = unmanaged.constBegin(); it != unmanaged.constEnd(); ++it)
708 if (predicate(const_cast<const Unmanaged*>(*it)))
709 procedure(*it);
710}
711
712template< typename T >
713inline void Workspace::forEachUnmanaged(T procedure)
714{
715 return forEachUnmanaged(procedure, TruePredicate());
716}
717
718KWIN_COMPARE_PREDICATE(ClientMatchPredicate, Client, const Client*, cl == value);
719
720inline bool Workspace::hasClient(const Client* c)
721{
722 return findClient(ClientMatchPredicate(c));
723}
724
725inline Workspace *workspace()
726{
727 return Workspace::_self;
728}
729
730} // namespace
731
732#endif
733