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
This commit is contained in:
Martin Gräßlin 2012-08-19 19:32:56 +02:00
parent 74fe348b96
commit a4fed7188c
8 changed files with 78 additions and 10 deletions

View file

@ -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<TabBoxClient> firstClient = tabBox->firstClientFocusChain().toStrongRef();
if (firstClient) {
c = firstClient.data();
}
}
TabBoxClient* stop = c;
while (c) {
QWeakPointer<TabBoxClient> add = tabBox->clientToAddToList(c, desktop);

View file

@ -103,6 +103,15 @@ QWeakPointer<TabBoxClient> TabBoxHandlerImpl::nextClientFocusChain(TabBoxClient*
return QWeakPointer<TabBoxClient>();
}
QWeakPointer< TabBoxClient > TabBoxHandlerImpl::firstClientFocusChain() const
{
if (Client *c = m_tabBox->firstClientFocusChain()) {
return QWeakPointer<TabBoxClient>(c->tabBoxClient());
} else {
return QWeakPointer<TabBoxClient>();
}
}
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.

View file

@ -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;

View file

@ -111,6 +111,14 @@ public:
* @return The next TabBoxClient in focus chain
*/
virtual QWeakPointer<TabBoxClient> 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<TabBoxClient> 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

View file

@ -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 m_activeClient;
}
return QWeakPointer<TabBox::TabBoxClient>();
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<TabBox::TabBoxClient>();
}
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);
}

View file

@ -32,6 +32,7 @@ public:
virtual void activateAndClose() {
}
virtual QWeakPointer< TabBox::TabBoxClient > activeClient() const;
void setActiveClient(const QWeakPointer<TabBox::TabBoxClient> &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<TabBox::TabBoxClient> 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<TabBox::TabBoxClient> > m_windows;
QWeakPointer<TabBox::TabBoxClient> m_activeClient;
};
} // namespace KWin
#endif

View file

@ -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<TabBox::TabBoxClient> 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<TabBox::TabBoxClient>());
// now it should still have two members in the list
clientModel->createClientList();
QCOMPARE(clientModel->rowCount(), 2);
}
QTEST_MAIN(TestTabBoxClientModel)

View file

@ -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