From a4fed7188cb7da48ad1b47ddf0784a804d25e96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Sun, 19 Aug 2012 19:32:56 +0200 Subject: [PATCH 1/2] Use the first client as entrance to the focus chain if no active window The recently used mode of TabBox uses the active window as the entrance into the focus chain. If there is no active window it does not find any Clients. To solve this issue the ClientModel now uses the first entry of the focus chain in case there is no active window. BUG: 305449 FIXED-IN: 4.9.1 REVIEW: 106088 --- tabbox/clientmodel.cpp | 8 +++++++- tabbox/tabbox.cpp | 17 +++++++++++++++++ tabbox/tabbox.h | 2 ++ tabbox/tabboxhandler.h | 8 ++++++++ tabbox/tests/mock_tabboxhandler.cpp | 24 +++++++++++++++--------- tabbox/tests/mock_tabboxhandler.h | 3 +++ tabbox/tests/test_tabbox_clientmodel.cpp | 19 +++++++++++++++++++ tabbox/tests/test_tabbox_clientmodel.h | 7 +++++++ 8 files changed, 78 insertions(+), 10 deletions(-) diff --git a/tabbox/clientmodel.cpp b/tabbox/clientmodel.cpp index b78c1f5ce4..adeeca608d 100644 --- a/tabbox/clientmodel.cpp +++ b/tabbox/clientmodel.cpp @@ -138,7 +138,7 @@ int ClientModel::rowCount(const QModelIndex& parent) const count = qRound(sqrt(float(m_clientList.count()))); break; } - return qMax(count, 1); + return count; } QModelIndex ClientModel::parent(const QModelIndex& child) const @@ -188,6 +188,12 @@ void ClientModel::createClientList(int desktop, bool partialReset) switch(tabBox->config().clientSwitchingMode()) { case TabBoxConfig::FocusChainSwitching: { TabBoxClient* c = tabBox->nextClientFocusChain(start).data(); + if (!c) { + QSharedPointer firstClient = tabBox->firstClientFocusChain().toStrongRef(); + if (firstClient) { + c = firstClient.data(); + } + } TabBoxClient* stop = c; while (c) { QWeakPointer add = tabBox->clientToAddToList(c, desktop); diff --git a/tabbox/tabbox.cpp b/tabbox/tabbox.cpp index 098d7598c0..fda99da3f6 100644 --- a/tabbox/tabbox.cpp +++ b/tabbox/tabbox.cpp @@ -103,6 +103,15 @@ QWeakPointer TabBoxHandlerImpl::nextClientFocusChain(TabBoxClient* return QWeakPointer(); } +QWeakPointer< TabBoxClient > TabBoxHandlerImpl::firstClientFocusChain() const +{ + if (Client *c = m_tabBox->firstClientFocusChain()) { + return QWeakPointer(c->tabBoxClient()); + } else { + return QWeakPointer(); + } +} + int TabBoxHandlerImpl::nextDesktopFocusChain(int desktop) const { return m_tabBox->nextDesktopFocusChain(desktop); @@ -1519,6 +1528,14 @@ Client* TabBox::previousClientFocusChain(Client* c) const return globalFocusChain[ pos ]; } +Client *TabBox::firstClientFocusChain() const +{ + const ClientList &globalFocusChain = Workspace::self()->globalFocusChain(); + if (globalFocusChain.isEmpty()) + return NULL; + return globalFocusChain.first(); +} + /*! auxiliary functions to travers all clients according to the static order. Useful for the CDE-style Alt-tab feature. diff --git a/tabbox/tabbox.h b/tabbox/tabbox.h index bf69ad9184..6652f93d05 100644 --- a/tabbox/tabbox.h +++ b/tabbox/tabbox.h @@ -51,6 +51,7 @@ public: virtual QString desktopName(TabBoxClient* client) const; virtual QString desktopName(int desktop) const; virtual QWeakPointer< TabBoxClient > nextClientFocusChain(TabBoxClient* client) const; + virtual QWeakPointer< TabBoxClient > firstClientFocusChain() const; virtual int nextDesktopFocusChain(int desktop) const; virtual int numberOfDesktops() const; virtual TabBoxClientList stackingOrder() const; @@ -163,6 +164,7 @@ public: Client* nextClientFocusChain(Client*) const; Client* previousClientFocusChain(Client*) const; + Client* firstClientFocusChain() const; Client* nextClientStatic(Client*) const; Client* previousClientStatic(Client*) const; int nextDesktopFocusChain(int iDesktop) const; diff --git a/tabbox/tabboxhandler.h b/tabbox/tabboxhandler.h index 976f201735..7abddfcd0e 100644 --- a/tabbox/tabboxhandler.h +++ b/tabbox/tabboxhandler.h @@ -111,6 +111,14 @@ public: * @return The next TabBoxClient in focus chain */ virtual QWeakPointer nextClientFocusChain(TabBoxClient* client) const = 0; + /** + * This method is used by the ClientModel to find an entrance into the focus chain in case + * there is no active Client. + * + * @return The first Client of the focus chain + * @since 4.9.1 + **/ + virtual QWeakPointer firstClientFocusChain() const = 0; /** * @param client The client whose desktop name should be retrieved * @return The desktop name of the given TabBoxClient. If the client is diff --git a/tabbox/tests/mock_tabboxhandler.cpp b/tabbox/tests/mock_tabboxhandler.cpp index 1d27dc752b..c3ad7a9a46 100644 --- a/tabbox/tests/mock_tabboxhandler.cpp +++ b/tabbox/tests/mock_tabboxhandler.cpp @@ -39,10 +39,12 @@ void MockTabBoxHandler::grabbedKeyEvent(QKeyEvent *event) const QWeakPointer< TabBox::TabBoxClient > MockTabBoxHandler::activeClient() const { - if (!m_windows.isEmpty()) { - return QWeakPointer< TabBox::TabBoxClient >(m_windows.first()); - } - return QWeakPointer(); + return m_activeClient; +} + +void MockTabBoxHandler::setActiveClient(const QWeakPointer< TabBox::TabBoxClient >& client) +{ + m_activeClient = client; } QWeakPointer< TabBox::TabBoxClient > MockTabBoxHandler::clientToAddToList(TabBox::TabBoxClient *client, int desktop) const @@ -59,11 +61,6 @@ QWeakPointer< TabBox::TabBoxClient > MockTabBoxHandler::clientToAddToList(TabBox QWeakPointer< TabBox::TabBoxClient > MockTabBoxHandler::nextClientFocusChain(TabBox::TabBoxClient *client) const { - if (!client) { - if (!m_windows.isEmpty()) { - return QWeakPointer< TabBox::TabBoxClient >(m_windows.first()); - } - } QList< QSharedPointer< TabBox::TabBoxClient > >::const_iterator it = m_windows.constBegin(); for (; it != m_windows.constEnd(); ++it) { if ((*it).data() == client) { @@ -78,10 +75,19 @@ QWeakPointer< TabBox::TabBoxClient > MockTabBoxHandler::nextClientFocusChain(Tab return QWeakPointer< TabBox::TabBoxClient >(); } +QWeakPointer< TabBox::TabBoxClient > MockTabBoxHandler::firstClientFocusChain() const +{ + if (m_windows.isEmpty()) { + return QWeakPointer(); + } + return m_windows.first(); +} + QWeakPointer< TabBox::TabBoxClient > MockTabBoxHandler::createMockWindow(const QString &caption, WId id) { QSharedPointer< TabBox::TabBoxClient > client(new MockTabBoxClient(caption, id)); m_windows.append(client); + m_activeClient = client; return QWeakPointer< TabBox::TabBoxClient >(client); } diff --git a/tabbox/tests/mock_tabboxhandler.h b/tabbox/tests/mock_tabboxhandler.h index f13a820aac..a2236486cb 100644 --- a/tabbox/tests/mock_tabboxhandler.h +++ b/tabbox/tests/mock_tabboxhandler.h @@ -32,6 +32,7 @@ public: virtual void activateAndClose() { } virtual QWeakPointer< TabBox::TabBoxClient > activeClient() const; + void setActiveClient(const QWeakPointer &client); virtual int activeScreen() const { return 0; } @@ -58,6 +59,7 @@ public: virtual void hideOutline() { } virtual QWeakPointer< TabBox::TabBoxClient > nextClientFocusChain(TabBox::TabBoxClient *client) const; + virtual QWeakPointer firstClientFocusChain() const; virtual int nextDesktopFocusChain(int desktop) const { Q_UNUSED(desktop) return 1; @@ -88,6 +90,7 @@ public: void closeWindow(TabBox::TabBoxClient *client); private: QList< QSharedPointer > m_windows; + QWeakPointer m_activeClient; }; } // namespace KWin #endif diff --git a/tabbox/tests/test_tabbox_clientmodel.cpp b/tabbox/tests/test_tabbox_clientmodel.cpp index cd2c963629..79d02534e4 100644 --- a/tabbox/tests/test_tabbox_clientmodel.cpp +++ b/tabbox/tests/test_tabbox_clientmodel.cpp @@ -44,4 +44,23 @@ void TestTabBoxClientModel::testLongestCaptionWithNullClient() QCOMPARE(clientModel->longestCaption(), QString()); } +void TestTabBoxClientModel::testCreateClientListNoActiveClient() +{ + MockTabBoxHandler tabboxhandler; + tabboxhandler.setConfig(TabBox::TabBoxConfig()); + TabBox::ClientModel *clientModel = new TabBox::ClientModel(&tabboxhandler); + clientModel->createClientList(); + QCOMPARE(clientModel->rowCount(), 0); + // create two windows, rowCount() should go to two + QWeakPointer client = tabboxhandler.createMockWindow(QString("test"), 1); + tabboxhandler.createMockWindow(QString("test2"), 2); + clientModel->createClientList(); + QCOMPARE(clientModel->rowCount(), 2); + // let's ensure there is no active client + tabboxhandler.setActiveClient(QWeakPointer()); + // now it should still have two members in the list + clientModel->createClientList(); + QCOMPARE(clientModel->rowCount(), 2); +} + QTEST_MAIN(TestTabBoxClientModel) diff --git a/tabbox/tests/test_tabbox_clientmodel.h b/tabbox/tests/test_tabbox_clientmodel.h index 1bdf0d4aa4..2ec6608a34 100644 --- a/tabbox/tests/test_tabbox_clientmodel.h +++ b/tabbox/tests/test_tabbox_clientmodel.h @@ -33,6 +33,13 @@ private slots: * See bug #303840 **/ void testLongestCaptionWithNullClient(); + /** + * Tests the creation of the Client list for the case that + * there is no active Client, but that Clients actually exist. + * + * See BUG: 305449 + **/ + void testCreateClientListNoActiveClient(); }; #endif From 2f18fe002f7c3c0f77ce51acbb0344ebc955c80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 23 Aug 2012 08:39:07 +0200 Subject: [PATCH 2/2] Start building up of ClientModel with the first Client to include So far the first Client to be shown in the list (that is the currently active window) was inserted as the last client into the list by prepending it to the list. This meant that if another Client actually blocks the inclusion of the currently selected Client (e.g. only one window per app) the currently active Client never got included in this list. This change ensures that the recently used model switching has the starting Client as the first Client in the list and also simplifies the code. Stacking order switching mode is not adjusted as it seems rather broken, like the comment already says. BUG: 304950 FIXED-IN: 4.9.1 REVIEW: 106139 --- tabbox/clientmodel.cpp | 15 ++++----------- tabbox/tabbox.cpp | 3 +++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/tabbox/clientmodel.cpp b/tabbox/clientmodel.cpp index adeeca608d..9591babaa8 100644 --- a/tabbox/clientmodel.cpp +++ b/tabbox/clientmodel.cpp @@ -187,7 +187,7 @@ void ClientModel::createClientList(int desktop, bool partialReset) switch(tabBox->config().clientSwitchingMode()) { case TabBoxConfig::FocusChainSwitching: { - TabBoxClient* c = tabBox->nextClientFocusChain(start).data(); + TabBoxClient* c = start; if (!c) { QSharedPointer firstClient = tabBox->firstClientFocusChain().toStrongRef(); if (firstClient) { @@ -195,23 +195,16 @@ void ClientModel::createClientList(int desktop, bool partialReset) } } TabBoxClient* stop = c; - while (c) { + do { QWeakPointer add = tabBox->clientToAddToList(c, desktop); if (!add.isNull()) { - if (start == add.data()) { - m_clientList.removeAll(add); - m_clientList.prepend(add); - } else - m_clientList += add; + m_clientList += add; if (add.data()->isFirstInTabBox()) { stickyClients << add; } } c = tabBox->nextClientFocusChain(c).data(); - - if (c == stop) - break; - } + } while (c && c != stop); break; } case TabBoxConfig::StackingOrderSwitching: { diff --git a/tabbox/tabbox.cpp b/tabbox/tabbox.cpp index fda99da3f6..d96d0bdace 100644 --- a/tabbox/tabbox.cpp +++ b/tabbox/tabbox.cpp @@ -225,6 +225,9 @@ bool TabBoxHandlerImpl::checkMultiScreen(TabBoxClient* client) const QWeakPointer TabBoxHandlerImpl::clientToAddToList(TabBoxClient* client, int desktop) const { + if (!client) { + return QWeakPointer(); + } Client* ret = NULL; Client* current = (static_cast< TabBoxClientImpl* >(client))->client();