2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2009 Martin Gräßlin <mgraesslin@kde.org>
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
// own
|
|
|
|
#include "clientmodel.h"
|
|
|
|
// tabbox
|
|
|
|
#include "tabboxconfig.h"
|
|
|
|
#include "tabboxhandler.h"
|
|
|
|
// Qt
|
2013-12-06 14:26:08 +00:00
|
|
|
#include <QIcon>
|
2019-01-20 13:04:13 +00:00
|
|
|
#include <QUuid>
|
2012-11-23 07:23:34 +00:00
|
|
|
// TODO: remove with Qt 5, only for HTML escaping the caption
|
|
|
|
#include <QTextDocument>
|
2009-09-13 11:36:45 +00:00
|
|
|
// other
|
2019-07-09 19:19:26 +00:00
|
|
|
#include <cmath>
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
namespace TabBox
|
|
|
|
{
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
ClientModel::ClientModel(QObject* parent)
|
|
|
|
: QAbstractItemModel(parent)
|
|
|
|
{
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
ClientModel::~ClientModel()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QVariant ClientModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
2009-09-13 11:36:45 +00:00
|
|
|
return QVariant();
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
if (m_clientList.isEmpty()) {
|
2012-03-17 09:31:15 +00:00
|
|
|
return QVariant();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2013-01-17 07:53:09 +00:00
|
|
|
int clientIndex = index.row();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (clientIndex >= m_clientList.count())
|
2009-09-13 11:36:45 +00:00
|
|
|
return QVariant();
|
2012-05-20 13:52:24 +00:00
|
|
|
QSharedPointer<TabBoxClient> client = m_clientList[ clientIndex ].toStrongRef();
|
|
|
|
if (!client) {
|
|
|
|
return QVariant();
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
switch(role) {
|
|
|
|
case Qt::DisplayRole:
|
2012-11-23 07:23:34 +00:00
|
|
|
case CaptionRole: {
|
|
|
|
QString caption = client->caption();
|
|
|
|
if (Qt::mightBeRichText(caption)) {
|
2019-07-09 21:24:32 +00:00
|
|
|
caption = caption.toHtmlEscaped();
|
2012-11-23 07:23:34 +00:00
|
|
|
}
|
|
|
|
return caption;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
case ClientRole:
|
2019-09-18 08:08:17 +00:00
|
|
|
return QVariant::fromValue<void *>(client.data());
|
2011-01-30 14:34:42 +00:00
|
|
|
case DesktopNameRole: {
|
2012-05-20 13:52:24 +00:00
|
|
|
return tabBox->desktopName(client.data());
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
case WIdRole:
|
2019-01-20 13:04:13 +00:00
|
|
|
return client->internalId();
|
2011-01-30 14:34:42 +00:00
|
|
|
case MinimizedRole:
|
2012-05-20 13:52:24 +00:00
|
|
|
return client->isMinimized();
|
2011-11-27 13:15:49 +00:00
|
|
|
case CloseableRole:
|
2012-02-27 21:20:11 +00:00
|
|
|
//clients that claim to be first are not closeable
|
2012-05-20 13:52:24 +00:00
|
|
|
return client->isCloseable() && !client->isFirstInTabBox();
|
2013-12-06 14:26:08 +00:00
|
|
|
case IconRole:
|
|
|
|
return client->icon();
|
2011-01-30 14:34:42 +00:00
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-10-30 15:07:14 +00:00
|
|
|
QString ClientModel::longestCaption() const
|
|
|
|
{
|
|
|
|
QString caption;
|
2012-12-29 06:51:05 +00:00
|
|
|
foreach (const QWeakPointer<TabBoxClient> &clientPointer, m_clientList) {
|
2012-05-20 13:52:24 +00:00
|
|
|
QSharedPointer<TabBoxClient> client = clientPointer.toStrongRef();
|
2012-07-21 09:25:17 +00:00
|
|
|
if (!client) {
|
|
|
|
continue;
|
|
|
|
}
|
2011-10-30 15:07:14 +00:00
|
|
|
if (client->caption().size() > caption.size()) {
|
|
|
|
caption = client->caption();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return caption;
|
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
int ClientModel::columnCount(const QModelIndex& parent) const
|
|
|
|
{
|
|
|
|
Q_UNUSED(parent)
|
2012-08-09 07:01:50 +00:00
|
|
|
return 1;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
int ClientModel::rowCount(const QModelIndex& parent) const
|
|
|
|
{
|
2013-02-20 11:37:47 +00:00
|
|
|
if (parent.isValid()) {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-08-09 07:01:50 +00:00
|
|
|
return m_clientList.count();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QModelIndex ClientModel::parent(const QModelIndex& child) const
|
|
|
|
{
|
|
|
|
Q_UNUSED(child)
|
2009-09-13 11:36:45 +00:00
|
|
|
return QModelIndex();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
QModelIndex ClientModel::index(int row, int column, const QModelIndex& parent) const
|
|
|
|
{
|
2013-02-20 11:37:47 +00:00
|
|
|
if (row < 0 || column != 0 || parent.isValid()) {
|
|
|
|
return QModelIndex();
|
|
|
|
}
|
|
|
|
int index = row * columnCount();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (index >= m_clientList.count() && !m_clientList.isEmpty())
|
2009-09-13 11:36:45 +00:00
|
|
|
return QModelIndex();
|
2013-02-20 11:37:47 +00:00
|
|
|
return createIndex(row, 0);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2019-07-09 21:56:00 +00:00
|
|
|
QHash<int, QByteArray> ClientModel::roleNames() const
|
|
|
|
{
|
|
|
|
return {
|
|
|
|
{ CaptionRole, QByteArrayLiteral("caption") },
|
|
|
|
{ DesktopNameRole, QByteArrayLiteral("desktopName") },
|
|
|
|
{ MinimizedRole, QByteArrayLiteral("minimized") },
|
|
|
|
{ WIdRole, QByteArrayLiteral("windowId") },
|
|
|
|
{ CloseableRole, QByteArrayLiteral("closeable") },
|
|
|
|
{ IconRole, QByteArrayLiteral("icon") },
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-05-20 13:52:24 +00:00
|
|
|
QModelIndex ClientModel::index(QWeakPointer<TabBoxClient> client) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
if (!m_clientList.contains(client))
|
2009-09-13 11:36:45 +00:00
|
|
|
return QModelIndex();
|
2011-01-30 14:34:42 +00:00
|
|
|
int index = m_clientList.indexOf(client);
|
2009-09-13 11:36:45 +00:00
|
|
|
int row = index / columnCount();
|
|
|
|
int column = index % columnCount();
|
2011-01-30 14:34:42 +00:00
|
|
|
return createIndex(row, column);
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void ClientModel::createClientList(bool partialReset)
|
|
|
|
{
|
|
|
|
createClientList(tabBox->currentDesktop(), partialReset);
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void ClientModel::createClientList(int desktop, bool partialReset)
|
|
|
|
{
|
2020-03-15 19:59:29 +00:00
|
|
|
auto start = tabBox->activeClient().toStrongRef();
|
2009-09-13 11:36:45 +00:00
|
|
|
// TODO: new clients are not added at correct position
|
2012-05-20 13:52:24 +00:00
|
|
|
if (partialReset && !m_clientList.isEmpty()) {
|
2020-03-15 19:59:29 +00:00
|
|
|
QSharedPointer<TabBoxClient> firstClient = m_clientList.constFirst();
|
2012-05-20 13:52:24 +00:00
|
|
|
if (firstClient) {
|
2020-03-15 19:59:29 +00:00
|
|
|
start = firstClient;
|
2012-05-20 13:52:24 +00:00
|
|
|
}
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2019-07-10 12:34:35 +00:00
|
|
|
beginResetModel();
|
2009-09-13 11:36:45 +00:00
|
|
|
m_clientList.clear();
|
2012-05-20 13:52:24 +00:00
|
|
|
QList< QWeakPointer< TabBoxClient > > stickyClients;
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
switch(tabBox->config().clientSwitchingMode()) {
|
|
|
|
case TabBoxConfig::FocusChainSwitching: {
|
2020-03-15 19:59:29 +00:00
|
|
|
auto c = start;
|
|
|
|
if (!tabBox->isInFocusChain(c.data())) {
|
2012-08-19 17:32:56 +00:00
|
|
|
QSharedPointer<TabBoxClient> firstClient = tabBox->firstClientFocusChain().toStrongRef();
|
|
|
|
if (firstClient) {
|
2020-03-15 19:59:29 +00:00
|
|
|
c = firstClient;
|
2012-08-19 17:32:56 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-15 19:59:29 +00:00
|
|
|
auto stop = c;
|
2012-08-23 06:39:07 +00:00
|
|
|
do {
|
2020-03-15 19:59:29 +00:00
|
|
|
QSharedPointer<TabBoxClient> add = tabBox->clientToAddToList(c.data(), desktop);
|
2012-05-20 13:52:24 +00:00
|
|
|
if (!add.isNull()) {
|
2012-08-23 06:39:07 +00:00
|
|
|
m_clientList += add;
|
2012-05-20 13:52:24 +00:00
|
|
|
if (add.data()->isFirstInTabBox()) {
|
2011-12-01 12:15:11 +00:00
|
|
|
stickyClients << add;
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2020-03-15 19:59:29 +00:00
|
|
|
c = tabBox->nextClientFocusChain(c.data());
|
2012-08-23 06:39:07 +00:00
|
|
|
} while (c && c != stop);
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TabBoxConfig::StackingOrderSwitching: {
|
|
|
|
// TODO: needs improvement
|
2020-03-15 19:59:29 +00:00
|
|
|
const TabBoxClientList stacking = tabBox->stackingOrder();
|
|
|
|
auto c = stacking.first().toStrongRef();
|
|
|
|
auto stop = c;
|
2011-01-30 14:34:42 +00:00
|
|
|
int index = 0;
|
|
|
|
while (c) {
|
2020-03-15 19:59:29 +00:00
|
|
|
QSharedPointer<TabBoxClient> add = tabBox->clientToAddToList(c.data(), desktop);
|
2012-05-20 13:52:24 +00:00
|
|
|
if (!add.isNull()) {
|
|
|
|
if (start == add.data()) {
|
2011-01-30 14:34:42 +00:00
|
|
|
m_clientList.removeAll(add);
|
|
|
|
m_clientList.prepend(add);
|
|
|
|
} else
|
|
|
|
m_clientList += add;
|
2012-05-20 13:52:24 +00:00
|
|
|
if (add.data()->isFirstInTabBox()) {
|
2011-12-01 12:15:11 +00:00
|
|
|
stickyClients << add;
|
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
if (index >= stacking.size() - 1) {
|
2014-02-24 15:42:43 +00:00
|
|
|
c = nullptr;
|
2011-01-30 14:34:42 +00:00
|
|
|
} else {
|
2020-03-15 19:59:29 +00:00
|
|
|
c = stacking[++index];
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
|
|
|
|
if (c == stop)
|
|
|
|
break;
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-12-29 06:51:05 +00:00
|
|
|
foreach (const QWeakPointer< TabBoxClient > &c, stickyClients) {
|
2011-12-01 12:15:11 +00:00
|
|
|
m_clientList.removeAll(c);
|
|
|
|
m_clientList.prepend(c);
|
|
|
|
}
|
2018-01-08 09:31:16 +00:00
|
|
|
if (tabBox->config().clientApplicationsMode() != TabBoxConfig::AllWindowsCurrentApplication
|
|
|
|
&& (tabBox->config().showDesktopMode() == TabBoxConfig::ShowDesktopClient || m_clientList.isEmpty())) {
|
2012-05-20 13:52:24 +00:00
|
|
|
QWeakPointer<TabBoxClient> desktopClient = tabBox->desktopClient();
|
|
|
|
if (!desktopClient.isNull())
|
2011-01-30 14:34:42 +00:00
|
|
|
m_clientList.append(desktopClient);
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2019-07-10 12:34:35 +00:00
|
|
|
endResetModel();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-11-27 14:00:09 +00:00
|
|
|
void ClientModel::close(int i)
|
|
|
|
{
|
|
|
|
QModelIndex ind = index(i, 0);
|
|
|
|
if (!ind.isValid()) {
|
|
|
|
return;
|
|
|
|
}
|
2012-05-20 13:52:24 +00:00
|
|
|
QSharedPointer<TabBoxClient> client = m_clientList.at(i).toStrongRef();
|
|
|
|
if (client) {
|
|
|
|
client->close();
|
|
|
|
}
|
2011-11-27 14:00:09 +00:00
|
|
|
}
|
|
|
|
|
2011-11-27 16:03:35 +00:00
|
|
|
void ClientModel::activate(int i)
|
|
|
|
{
|
|
|
|
QModelIndex ind = index(i, 0);
|
|
|
|
if (!ind.isValid()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
tabBox->setCurrentIndex(ind);
|
|
|
|
tabBox->activateAndClose();
|
|
|
|
}
|
|
|
|
|
2009-09-13 11:36:45 +00:00
|
|
|
} // namespace Tabbox
|
|
|
|
} // namespace KWin
|