diff --git a/focuschain.cpp b/focuschain.cpp index c62a7a14c..1054d69a5 100644 --- a/focuschain.cpp +++ b/focuschain.cpp @@ -1,269 +1,269 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2012 Martin Gräßlin 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 . *********************************************************************/ #include "focuschain.h" #include "abstract_client.h" #include "screens.h" namespace KWin { KWIN_SINGLETON_FACTORY_VARIABLE(FocusChain, s_manager) FocusChain::FocusChain(QObject *parent) : QObject(parent) , m_separateScreenFocus(false) , m_activeClient(NULL) , m_currentDesktop(0) { } FocusChain::~FocusChain() { s_manager = NULL; } void FocusChain::remove(AbstractClient *client) { - for (DesktopChains::iterator it = m_desktopFocusChains.begin(); + for (auto it = m_desktopFocusChains.begin(); it != m_desktopFocusChains.end(); ++it) { it.value().removeAll(client); } m_mostRecentlyUsed.removeAll(client); } void FocusChain::resize(uint previousSize, uint newSize) { for (uint i = previousSize + 1; i <= newSize; ++i) { - m_desktopFocusChains.insert(i, QList()); + m_desktopFocusChains.insert(i, Chain()); } for (uint i = previousSize; i > newSize; --i) { m_desktopFocusChains.remove(i); } } AbstractClient *FocusChain::getForActivation(uint desktop) const { return getForActivation(desktop, screens()->current()); } AbstractClient *FocusChain::getForActivation(uint desktop, int screen) const { - DesktopChains::const_iterator it = m_desktopFocusChains.find(desktop); + auto it = m_desktopFocusChains.constFind(desktop); if (it == m_desktopFocusChains.constEnd()) { return NULL; } const auto &chain = it.value(); for (int i = chain.size() - 1; i >= 0; --i) { auto tmp = chain.at(i); // TODO: move the check into Client if (tmp->isShown(false) && tmp->isOnCurrentActivity() && ( !m_separateScreenFocus || tmp->screen() == screen)) { return tmp; } } return NULL; } void FocusChain::update(AbstractClient *client, FocusChain::Change change) { if (!client->wantsTabFocus()) { // Doesn't want tab focus, remove remove(client); return; } if (client->isOnAllDesktops()) { // Now on all desktops, add it to focus chains it is not already in - for (DesktopChains::iterator it = m_desktopFocusChains.begin(); + for (auto it = m_desktopFocusChains.begin(); it != m_desktopFocusChains.end(); ++it) { auto &chain = it.value(); // Making first/last works only on current desktop, don't affect all desktops if (it.key() == m_currentDesktop && (change == MakeFirst || change == MakeLast)) { if (change == MakeFirst) { makeFirstInChain(client, chain); } else { makeLastInChain(client, chain); } } else { insertClientIntoChain(client, chain); } } } else { // Now only on desktop, remove it anywhere else - for (DesktopChains::iterator it = m_desktopFocusChains.begin(); + for (auto it = m_desktopFocusChains.begin(); it != m_desktopFocusChains.end(); ++it) { auto &chain = it.value(); if (client->isOnDesktop(it.key())) { updateClientInChain(client, change, chain); } else { chain.removeAll(client); } } } // add for most recently used chain updateClientInChain(client, change, m_mostRecentlyUsed); } -void FocusChain::updateClientInChain(AbstractClient *client, FocusChain::Change change, QList< AbstractClient * >& chain) +void FocusChain::updateClientInChain(AbstractClient *client, FocusChain::Change change, Chain &chain) { if (change == MakeFirst) { makeFirstInChain(client, chain); } else if (change == MakeLast) { makeLastInChain(client, chain); } else { insertClientIntoChain(client, chain); } } -void FocusChain::insertClientIntoChain(AbstractClient *client, QList< AbstractClient * >& chain) +void FocusChain::insertClientIntoChain(AbstractClient *client, Chain &chain) { if (chain.contains(client)) { return; } if (m_activeClient && m_activeClient != client && !chain.empty() && chain.last() == m_activeClient) { // Add it after the active client chain.insert(chain.size() - 1, client); } else { // Otherwise add as the first one chain.append(client); } } void FocusChain::moveAfterClient(AbstractClient *client, AbstractClient *reference) { if (!client->wantsTabFocus()) { return; } - for (DesktopChains::iterator it = m_desktopFocusChains.begin(); + for (auto it = m_desktopFocusChains.begin(); it != m_desktopFocusChains.end(); ++it) { if (!client->isOnDesktop(it.key())) { continue; } moveAfterClientInChain(client, reference, it.value()); } moveAfterClientInChain(client, reference, m_mostRecentlyUsed); } -void FocusChain::moveAfterClientInChain(AbstractClient *client, AbstractClient *reference, QList &chain) +void FocusChain::moveAfterClientInChain(AbstractClient *client, AbstractClient *reference, Chain &chain) { if (!chain.contains(reference)) { return; } if (AbstractClient::belongToSameApplication(reference, client)) { chain.removeAll(client); chain.insert(chain.indexOf(reference), client); } else { chain.removeAll(client); for (int i = chain.size() - 1; i >= 0; --i) { if (AbstractClient::belongToSameApplication(reference, chain.at(i))) { chain.insert(i, client); break; } } } } AbstractClient *FocusChain::firstMostRecentlyUsed() const { if (m_mostRecentlyUsed.isEmpty()) { return NULL; } return m_mostRecentlyUsed.first(); } AbstractClient *FocusChain::nextMostRecentlyUsed(AbstractClient *reference) const { if (m_mostRecentlyUsed.isEmpty()) { return NULL; } const int index = m_mostRecentlyUsed.indexOf(reference); if (index == -1) { return m_mostRecentlyUsed.first(); } if (index == 0) { return m_mostRecentlyUsed.last(); } return m_mostRecentlyUsed.at(index - 1); } // copied from activation.cpp bool FocusChain::isUsableFocusCandidate(AbstractClient *c, AbstractClient *prev) const { return c != prev && c->isShown(false) && c->isOnCurrentDesktop() && c->isOnCurrentActivity() && (!m_separateScreenFocus || c->isOnScreen(prev ? prev->screen() : screens()->current())); } AbstractClient *FocusChain::nextForDesktop(AbstractClient *reference, uint desktop) const { - DesktopChains::const_iterator it = m_desktopFocusChains.find(desktop); - if (it == m_desktopFocusChains.end()) { + auto it = m_desktopFocusChains.constFind(desktop); + if (it == m_desktopFocusChains.constEnd()) { return NULL; } const auto &chain = it.value(); for (int i = chain.size() - 1; i >= 0; --i) { auto client = chain.at(i); if (isUsableFocusCandidate(client, reference)) { return client; } } return NULL; } -void FocusChain::makeFirstInChain(AbstractClient *client, QList< AbstractClient * >& chain) +void FocusChain::makeFirstInChain(AbstractClient *client, Chain &chain) { chain.removeAll(client); if (client->isMinimized()) { // add it before the first minimized ... for (int i = chain.count()-1; i >= 0; --i) { if (chain.at(i)->isMinimized()) { chain.insert(i+1, client); return; } } chain.prepend(client); // ... or at end of chain } else { chain.append(client); } } -void FocusChain::makeLastInChain(AbstractClient *client, QList< AbstractClient * >& chain) +void FocusChain::makeLastInChain(AbstractClient *client, Chain &chain) { chain.removeAll(client); chain.prepend(client); } bool FocusChain::contains(AbstractClient *client, uint desktop) const { - DesktopChains::const_iterator it = m_desktopFocusChains.find(desktop); - if (it == m_desktopFocusChains.end()) { + auto it = m_desktopFocusChains.constFind(desktop); + if (it == m_desktopFocusChains.constEnd()) { return false; } return it.value().contains(client); } } // namespace diff --git a/focuschain.h b/focuschain.h index 886b37ea9..662cffd07 100644 --- a/focuschain.h +++ b/focuschain.h @@ -1,254 +1,254 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2012 Martin Gräßlin 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 . *********************************************************************/ #ifndef KWIN_FOCUS_CHAIN_H #define KWIN_FOCUS_CHAIN_H // KWin #include // Qt #include #include 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 }; virtual ~FocusChain(); /** * @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 :Client* 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 :Client* 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 :Client* 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 :Client* 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 :Client* 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; /** * @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, QList &chain); + 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, QList &chain); - void moveAfterClientInChain(AbstractClient *client, AbstractClient *reference, QList &chain); - void updateClientInChain(AbstractClient *client, Change change, QList &chain); - void insertClientIntoChain(AbstractClient *client, QList &chain); - typedef QHash > DesktopChains; - QList m_mostRecentlyUsed; - DesktopChains m_desktopFocusChains; + 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 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