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
|
|
|
#include "tabboxhandler.h"
|
2022-03-23 10:13:38 +00:00
|
|
|
|
2014-04-17 15:22:14 +00:00
|
|
|
#include <config-kwin.h>
|
2022-03-23 10:13:38 +00:00
|
|
|
|
|
|
|
// own
|
2009-09-13 11:36:45 +00:00
|
|
|
#include "clientmodel.h"
|
2014-03-03 12:42:13 +00:00
|
|
|
#include "scripting/scripting.h"
|
2013-12-10 06:14:44 +00:00
|
|
|
#include "switcheritem.h"
|
2015-07-31 11:03:35 +00:00
|
|
|
#include "tabbox_logging.h"
|
2023-03-25 20:46:54 +00:00
|
|
|
#include "window.h"
|
2009-09-13 11:36:45 +00:00
|
|
|
// Qt
|
|
|
|
#include <QKeyEvent>
|
2013-12-10 06:14:44 +00:00
|
|
|
#include <QQmlComponent>
|
2022-03-23 10:13:38 +00:00
|
|
|
#include <QQmlContext>
|
2013-12-10 06:14:44 +00:00
|
|
|
#include <QQmlEngine>
|
|
|
|
#include <QQuickItem>
|
|
|
|
#include <QQuickWindow>
|
2022-03-23 10:13:38 +00:00
|
|
|
#include <QStandardPaths>
|
|
|
|
#include <QTimer>
|
2018-11-04 16:37:07 +00:00
|
|
|
#include <qpa/qwindowsysteminterface.h>
|
2009-09-13 11:36:45 +00:00
|
|
|
// KDE
|
2013-12-10 06:14:44 +00:00
|
|
|
#include <KLocalizedString>
|
2015-07-07 06:28:38 +00:00
|
|
|
#include <KPackage/Package>
|
|
|
|
#include <KPackage/PackageLoader>
|
2022-03-23 10:13:38 +00:00
|
|
|
#include <KProcess>
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
namespace TabBox
|
|
|
|
{
|
|
|
|
|
|
|
|
class TabBoxHandlerPrivate
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
TabBoxHandlerPrivate(TabBoxHandler *q);
|
|
|
|
|
|
|
|
~TabBoxHandlerPrivate();
|
|
|
|
|
|
|
|
/**
|
2019-02-02 18:17:44 +00:00
|
|
|
* Updates the current highlight window state
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2011-01-30 14:34:42 +00:00
|
|
|
void updateHighlightWindows();
|
|
|
|
/**
|
2019-02-02 18:17:44 +00:00
|
|
|
* Ends window highlighting
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2011-01-30 14:34:42 +00:00
|
|
|
void endHighlightWindows(bool abort = false);
|
|
|
|
|
2013-12-10 06:14:44 +00:00
|
|
|
void show();
|
|
|
|
QQuickWindow *window() const;
|
|
|
|
SwitcherItem *switcherItem() const;
|
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
ClientModel *clientModel() const;
|
2011-01-30 14:34:42 +00:00
|
|
|
|
2022-07-02 22:58:42 +00:00
|
|
|
bool isHighlightWindows() const;
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
TabBoxHandler *q; // public pointer
|
|
|
|
// members
|
|
|
|
TabBoxConfig config;
|
2022-08-01 21:29:02 +00:00
|
|
|
std::unique_ptr<QQmlContext> m_qmlContext;
|
|
|
|
std::unique_ptr<QQmlComponent> m_qmlComponent;
|
2013-12-10 06:14:44 +00:00
|
|
|
QObject *m_mainItem;
|
2022-03-23 10:13:38 +00:00
|
|
|
QMap<QString, QObject *> m_clientTabBoxes;
|
|
|
|
ClientModel *m_clientModel;
|
2011-01-30 14:34:42 +00:00
|
|
|
QModelIndex index;
|
|
|
|
/**
|
2019-02-02 18:17:44 +00:00
|
|
|
* Indicates if the tabbox is shown.
|
2019-07-29 18:58:33 +00:00
|
|
|
*/
|
2011-01-30 14:34:42 +00:00
|
|
|
bool isShown;
|
2023-03-25 20:46:54 +00:00
|
|
|
Window *lastRaisedClient, *lastRaisedClientSucc;
|
2016-10-06 06:06:25 +00:00
|
|
|
int wheelAngleDelta = 0;
|
2013-12-10 06:14:44 +00:00
|
|
|
|
|
|
|
private:
|
2023-03-24 16:23:54 +00:00
|
|
|
QObject *createSwitcherItem();
|
2011-01-30 14:34:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
TabBoxHandlerPrivate::TabBoxHandlerPrivate(TabBoxHandler *q)
|
2014-03-03 12:42:13 +00:00
|
|
|
: m_qmlContext()
|
2022-07-12 18:41:11 +00:00
|
|
|
, m_qmlComponent(nullptr)
|
2013-12-10 06:14:44 +00:00
|
|
|
, m_mainItem(nullptr)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2010-10-17 19:49:07 +00:00
|
|
|
this->q = q;
|
2009-09-13 12:15:04 +00:00
|
|
|
isShown = false;
|
2014-02-24 15:42:43 +00:00
|
|
|
lastRaisedClient = nullptr;
|
|
|
|
lastRaisedClientSucc = nullptr;
|
2009-09-13 11:36:45 +00:00
|
|
|
config = TabBoxConfig();
|
2011-07-09 09:12:00 +00:00
|
|
|
m_clientModel = new ClientModel(q);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
TabBoxHandlerPrivate::~TabBoxHandlerPrivate()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2023-03-24 16:23:54 +00:00
|
|
|
qDeleteAll(m_clientTabBoxes);
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QQuickWindow *TabBoxHandlerPrivate::window() const
|
|
|
|
{
|
|
|
|
if (!m_mainItem) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2022-03-23 10:13:38 +00:00
|
|
|
if (QQuickWindow *w = qobject_cast<QQuickWindow *>(m_mainItem)) {
|
2013-12-10 06:14:44 +00:00
|
|
|
return w;
|
|
|
|
}
|
2022-03-23 10:13:38 +00:00
|
|
|
return m_mainItem->findChild<QQuickWindow *>();
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
|
|
|
|
2014-06-10 09:14:59 +00:00
|
|
|
#ifndef KWIN_UNIT_TEST
|
2013-12-10 06:14:44 +00:00
|
|
|
SwitcherItem *TabBoxHandlerPrivate::switcherItem() const
|
|
|
|
{
|
|
|
|
if (!m_mainItem) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2022-03-23 10:13:38 +00:00
|
|
|
if (SwitcherItem *i = qobject_cast<SwitcherItem *>(m_mainItem)) {
|
2013-12-10 06:14:44 +00:00
|
|
|
return i;
|
2022-03-23 10:13:38 +00:00
|
|
|
} else if (QQuickWindow *w = qobject_cast<QQuickWindow *>(m_mainItem)) {
|
|
|
|
return w->contentItem()->findChild<SwitcherItem *>();
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
2022-03-23 10:13:38 +00:00
|
|
|
return m_mainItem->findChild<SwitcherItem *>();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2014-06-10 09:14:59 +00:00
|
|
|
#endif
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
ClientModel *TabBoxHandlerPrivate::clientModel() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2011-07-09 09:12:00 +00:00
|
|
|
return m_clientModel;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2022-07-02 22:58:42 +00:00
|
|
|
bool TabBoxHandlerPrivate::isHighlightWindows() const
|
|
|
|
{
|
|
|
|
const QQuickWindow *w = window();
|
|
|
|
if (w && w->visibility() == QWindow::FullScreen) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return config.isHighlightWindows();
|
|
|
|
}
|
|
|
|
|
2009-09-13 11:36:45 +00:00
|
|
|
void TabBoxHandlerPrivate::updateHighlightWindows()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2023-03-24 16:23:54 +00:00
|
|
|
if (!isShown) {
|
2009-09-13 11:36:45 +00:00
|
|
|
return;
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2010-10-17 19:49:07 +00:00
|
|
|
|
2023-03-25 20:46:54 +00:00
|
|
|
Window *currentClient = q->client(index);
|
2013-12-10 06:14:44 +00:00
|
|
|
QWindow *w = window();
|
2011-01-30 14:34:42 +00:00
|
|
|
|
2013-04-12 18:15:31 +00:00
|
|
|
if (q->isKWinCompositing()) {
|
2022-03-25 12:20:32 +00:00
|
|
|
if (lastRaisedClient) {
|
2016-03-04 08:44:24 +00:00
|
|
|
q->elevateClient(lastRaisedClient, w, false);
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2012-04-10 23:19:15 +00:00
|
|
|
lastRaisedClient = currentClient;
|
2022-09-09 13:39:14 +00:00
|
|
|
// don't elevate desktop
|
2023-03-25 20:46:54 +00:00
|
|
|
const auto desktop = q->desktopClient();
|
2022-09-19 13:49:14 +00:00
|
|
|
if (currentClient && (!desktop || currentClient->internalId() != desktop->internalId())) {
|
2016-03-04 08:44:24 +00:00
|
|
|
q->elevateClient(currentClient, w, true);
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2012-04-10 23:19:15 +00:00
|
|
|
} else {
|
2011-01-30 14:34:42 +00:00
|
|
|
if (lastRaisedClient) {
|
2015-02-06 22:10:59 +00:00
|
|
|
q->shadeClient(lastRaisedClient, true);
|
2022-03-25 12:20:32 +00:00
|
|
|
if (lastRaisedClientSucc) {
|
2011-01-30 14:34:42 +00:00
|
|
|
q->restack(lastRaisedClient, lastRaisedClientSucc);
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
// TODO lastRaisedClient->setMinimized( lastRaisedClientWasMinimized );
|
|
|
|
}
|
|
|
|
|
2010-10-17 19:49:07 +00:00
|
|
|
lastRaisedClient = currentClient;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (lastRaisedClient) {
|
2015-02-06 22:10:59 +00:00
|
|
|
q->shadeClient(lastRaisedClient, false);
|
2010-10-17 19:49:07 +00:00
|
|
|
// TODO if ( (lastRaisedClientWasMinimized = lastRaisedClient->isMinimized()) )
|
|
|
|
// lastRaisedClient->setMinimized( false );
|
2023-03-25 20:46:54 +00:00
|
|
|
QList<Window *> order = q->stackingOrder();
|
2012-05-20 13:52:24 +00:00
|
|
|
int succIdx = order.count() + 1;
|
2022-03-23 10:13:38 +00:00
|
|
|
for (int i = 0; i < order.count(); ++i) {
|
2023-03-25 20:46:54 +00:00
|
|
|
if (order.at(i) == lastRaisedClient) {
|
2012-05-20 13:52:24 +00:00
|
|
|
succIdx = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-03-25 20:46:54 +00:00
|
|
|
lastRaisedClientSucc = (succIdx < order.count()) ? order.at(succIdx) : nullptr;
|
2011-01-30 14:34:42 +00:00
|
|
|
q->raiseClient(lastRaisedClient);
|
2010-10-17 19:49:07 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2010-10-17 19:49:07 +00:00
|
|
|
|
2011-10-30 15:07:14 +00:00
|
|
|
if (config.isShowTabBox() && w) {
|
2016-08-30 13:50:31 +00:00
|
|
|
q->highlightWindows(currentClient, w);
|
2011-01-30 14:34:42 +00:00
|
|
|
} else {
|
2016-08-30 13:50:31 +00:00
|
|
|
q->highlightWindows(currentClient);
|
2010-10-17 19:49:07 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void TabBoxHandlerPrivate::endHighlightWindows(bool abort)
|
|
|
|
{
|
2023-03-25 20:46:54 +00:00
|
|
|
Window *currentClient = q->client(index);
|
2022-07-02 22:58:42 +00:00
|
|
|
if (isHighlightWindows() && q->isKWinCompositing()) {
|
2021-11-03 11:55:31 +00:00
|
|
|
const auto stackingOrder = q->stackingOrder();
|
2023-03-25 20:46:54 +00:00
|
|
|
for (Window *window : stackingOrder) {
|
|
|
|
if (window != currentClient) { // to not mess up with wanted ShadeActive/ShadeHover state
|
|
|
|
q->shadeClient(window, true);
|
2021-11-03 11:55:31 +00:00
|
|
|
}
|
2015-02-06 22:10:59 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-10 06:14:44 +00:00
|
|
|
QWindow *w = window();
|
2022-03-25 12:20:32 +00:00
|
|
|
if (currentClient) {
|
2016-03-04 08:44:24 +00:00
|
|
|
q->elevateClient(currentClient, w, false);
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
|
|
|
if (abort && lastRaisedClient && lastRaisedClientSucc) {
|
2011-01-30 14:34:42 +00:00
|
|
|
q->restack(lastRaisedClient, lastRaisedClientSucc);
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2014-02-24 15:42:43 +00:00
|
|
|
lastRaisedClient = nullptr;
|
|
|
|
lastRaisedClientSucc = nullptr;
|
2009-09-13 11:36:45 +00:00
|
|
|
// highlight windows
|
2016-08-30 13:50:31 +00:00
|
|
|
q->highlightWindows();
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
|
|
|
|
2014-06-10 09:14:59 +00:00
|
|
|
#ifndef KWIN_UNIT_TEST
|
2023-03-24 16:23:54 +00:00
|
|
|
QObject *TabBoxHandlerPrivate::createSwitcherItem()
|
2013-12-10 06:14:44 +00:00
|
|
|
{
|
2014-10-29 08:52:06 +00:00
|
|
|
// first try look'n'feel package
|
2021-08-22 13:15:16 +00:00
|
|
|
QString file = QStandardPaths::locate(
|
|
|
|
QStandardPaths::GenericDataLocation,
|
2023-03-24 16:23:54 +00:00
|
|
|
QStringLiteral("plasma/look-and-feel/%1/contents/windowswitcher/WindowSwitcher.qml").arg(config.layoutName()));
|
2014-10-28 15:45:30 +00:00
|
|
|
if (file.isNull()) {
|
2023-03-24 16:23:54 +00:00
|
|
|
const QString folderName = QLatin1String("kwin/tabbox/");
|
|
|
|
auto findSwitcher = [this, folderName] {
|
|
|
|
const QString type = QStringLiteral("KWin/WindowSwitcher");
|
2022-03-23 10:13:38 +00:00
|
|
|
auto offers = KPackage::PackageLoader::self()->findPackages(type, folderName,
|
|
|
|
[this](const KPluginMetaData &data) {
|
|
|
|
return data.pluginId().compare(config.layoutName(), Qt::CaseInsensitive) == 0;
|
|
|
|
});
|
2013-12-10 06:14:44 +00:00
|
|
|
if (offers.isEmpty()) {
|
2014-10-28 15:45:30 +00:00
|
|
|
// load default
|
2022-03-23 10:13:38 +00:00
|
|
|
offers = KPackage::PackageLoader::self()->findPackages(type, folderName,
|
|
|
|
[](const KPluginMetaData &data) {
|
|
|
|
return data.pluginId().compare(QStringLiteral("informative"), Qt::CaseInsensitive) == 0;
|
|
|
|
});
|
2014-10-28 15:45:30 +00:00
|
|
|
if (offers.isEmpty()) {
|
2015-07-31 11:03:35 +00:00
|
|
|
qCDebug(KWIN_TABBOX) << "could not find default window switcher layout";
|
2015-07-07 06:28:38 +00:00
|
|
|
return KPluginMetaData();
|
2014-10-28 15:45:30 +00:00
|
|
|
}
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
2014-10-28 15:45:30 +00:00
|
|
|
return offers.first();
|
|
|
|
};
|
2015-07-07 06:28:38 +00:00
|
|
|
auto service = findSwitcher();
|
|
|
|
if (!service.isValid()) {
|
2014-10-28 15:45:30 +00:00
|
|
|
return nullptr;
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
2015-11-05 14:14:06 +00:00
|
|
|
if (service.value(QStringLiteral("X-Plasma-API")) != QLatin1String("declarativeappletscript")) {
|
2015-07-31 11:03:35 +00:00
|
|
|
qCDebug(KWIN_TABBOX) << "Window Switcher Layout is no declarativeappletscript";
|
2014-10-28 15:45:30 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2018-10-31 08:26:13 +00:00
|
|
|
auto findScriptFile = [service, folderName] {
|
2015-07-07 06:28:38 +00:00
|
|
|
const QString pluginName = service.pluginId();
|
|
|
|
const QString scriptName = service.value(QStringLiteral("X-Plasma-MainScript"));
|
2015-11-05 14:14:06 +00:00
|
|
|
return QStandardPaths::locate(QStandardPaths::GenericDataLocation, folderName + pluginName + QLatin1String("/contents/") + scriptName);
|
2014-10-28 15:45:30 +00:00
|
|
|
};
|
|
|
|
file = findScriptFile();
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
|
|
|
if (file.isNull()) {
|
2015-07-31 11:03:35 +00:00
|
|
|
qCDebug(KWIN_TABBOX) << "Could not find QML file for window switcher";
|
2013-12-10 06:14:44 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
m_qmlComponent->loadUrl(QUrl::fromLocalFile(file));
|
|
|
|
if (m_qmlComponent->isError()) {
|
2023-03-01 15:24:36 +00:00
|
|
|
qCWarning(KWIN_TABBOX) << "Component failed to load: " << m_qmlComponent->errors();
|
2013-12-10 06:14:44 +00:00
|
|
|
QStringList args;
|
|
|
|
args << QStringLiteral("--passivepopup") << i18n("The Window Switcher installation is broken, resources are missing.\n"
|
2022-03-23 10:13:38 +00:00
|
|
|
"Contact your distribution about this.")
|
|
|
|
<< QStringLiteral("20");
|
2013-12-10 06:14:44 +00:00
|
|
|
KProcess::startDetached(QStringLiteral("kdialog"), args);
|
2022-07-12 18:41:11 +00:00
|
|
|
m_qmlComponent.reset(nullptr);
|
2013-12-10 06:14:44 +00:00
|
|
|
} else {
|
2022-08-01 21:29:02 +00:00
|
|
|
QObject *object = m_qmlComponent->create(m_qmlContext.get());
|
2023-03-24 16:23:54 +00:00
|
|
|
m_clientTabBoxes.insert(config.layoutName(), object);
|
2013-12-10 06:14:44 +00:00
|
|
|
return object;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-06-10 09:14:59 +00:00
|
|
|
#endif
|
2013-12-10 06:14:44 +00:00
|
|
|
|
|
|
|
void TabBoxHandlerPrivate::show()
|
|
|
|
{
|
2014-06-10 09:14:59 +00:00
|
|
|
#ifndef KWIN_UNIT_TEST
|
2022-08-01 21:29:02 +00:00
|
|
|
if (!m_qmlContext) {
|
2022-01-04 20:07:45 +00:00
|
|
|
qmlRegisterType<SwitcherItem>("org.kde.kwin", 3, 0, "TabBoxSwitcher");
|
2014-03-03 12:42:13 +00:00
|
|
|
m_qmlContext.reset(new QQmlContext(Scripting::self()->qmlEngine()));
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
2022-08-01 21:29:02 +00:00
|
|
|
if (!m_qmlComponent) {
|
2014-03-03 12:42:13 +00:00
|
|
|
m_qmlComponent.reset(new QQmlComponent(Scripting::self()->qmlEngine()));
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
2022-03-23 10:13:38 +00:00
|
|
|
auto findMainItem = [this](const QMap<QString, QObject *> &tabBoxes) -> QObject * {
|
2013-12-10 06:14:44 +00:00
|
|
|
auto it = tabBoxes.constFind(config.layoutName());
|
|
|
|
if (it != tabBoxes.constEnd()) {
|
|
|
|
return it.value();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
};
|
|
|
|
m_mainItem = nullptr;
|
2023-03-24 16:23:54 +00:00
|
|
|
m_mainItem = findMainItem(m_clientTabBoxes);
|
2013-12-10 06:14:44 +00:00
|
|
|
if (!m_mainItem) {
|
2023-03-24 16:23:54 +00:00
|
|
|
m_mainItem = createSwitcherItem();
|
2013-12-10 06:14:44 +00:00
|
|
|
if (!m_mainItem) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (SwitcherItem *item = switcherItem()) {
|
2017-01-16 18:11:07 +00:00
|
|
|
// In case the model isn't yet set (see below), index will be reset and therefore we
|
|
|
|
// need to save the current index row (https://bugs.kde.org/show_bug.cgi?id=333511).
|
|
|
|
int indexRow = index.row();
|
2013-12-10 06:14:44 +00:00
|
|
|
if (!item->model()) {
|
2023-03-24 16:23:54 +00:00
|
|
|
item->setModel(clientModel());
|
2013-12-10 06:14:44 +00:00
|
|
|
}
|
|
|
|
item->setAllDesktops(config.clientDesktopMode() == TabBoxConfig::AllDesktopsClients);
|
2017-01-16 18:11:07 +00:00
|
|
|
item->setCurrentIndex(indexRow);
|
2017-04-12 16:14:37 +00:00
|
|
|
item->setNoModifierGrab(q->noModifierGrab());
|
2013-12-10 06:14:44 +00:00
|
|
|
// everything is prepared, so let's make the whole thing visible
|
|
|
|
item->setVisible(true);
|
|
|
|
}
|
2016-10-06 06:06:25 +00:00
|
|
|
if (QWindow *w = window()) {
|
|
|
|
wheelAngleDelta = 0;
|
|
|
|
w->installEventFilter(q);
|
2018-11-04 16:37:07 +00:00
|
|
|
// pretend to activate the window to enable accessibility notifications
|
|
|
|
QWindowSystemInterface::handleWindowActivated(w, Qt::TabFocusReason);
|
2016-10-06 06:06:25 +00:00
|
|
|
}
|
2014-06-10 09:14:59 +00:00
|
|
|
#endif
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
/***********************************************
|
2022-03-23 10:13:38 +00:00
|
|
|
* TabBoxHandler
|
|
|
|
***********************************************/
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2014-05-27 08:10:07 +00:00
|
|
|
TabBoxHandler::TabBoxHandler(QObject *parent)
|
|
|
|
: QObject(parent)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2009-09-13 11:36:45 +00:00
|
|
|
KWin::TabBox::tabBox = this;
|
2011-01-30 14:34:42 +00:00
|
|
|
d = new TabBoxHandlerPrivate(this);
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
TabBoxHandler::~TabBoxHandler()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2009-09-13 11:36:45 +00:00
|
|
|
delete d;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
const KWin::TabBox::TabBoxConfig &TabBoxHandler::config() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2009-09-13 11:36:45 +00:00
|
|
|
return d->config;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
void TabBoxHandler::setConfig(const TabBoxConfig &config)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2009-09-13 11:36:45 +00:00
|
|
|
d->config = config;
|
2021-06-08 07:02:14 +00:00
|
|
|
Q_EMIT configChanged();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
void TabBoxHandler::show()
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2009-09-13 11:36:45 +00:00
|
|
|
d->isShown = true;
|
2014-02-24 15:42:43 +00:00
|
|
|
d->lastRaisedClient = nullptr;
|
|
|
|
d->lastRaisedClientSucc = nullptr;
|
2011-01-30 14:34:42 +00:00
|
|
|
if (d->config.isShowTabBox()) {
|
2013-12-10 06:14:44 +00:00
|
|
|
d->show();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2022-07-02 22:58:42 +00:00
|
|
|
if (d->isHighlightWindows()) {
|
2012-05-03 23:08:28 +00:00
|
|
|
// TODO this should be
|
2015-02-06 22:10:59 +00:00
|
|
|
// QMetaObject::invokeMethod(this, "initHighlightWindows", Qt::QueuedConnection);
|
2012-05-03 23:08:28 +00:00
|
|
|
// but we somehow need to cross > 1 event cycle (likely because of queued invocation in the effects)
|
|
|
|
// to ensure the EffectWindow is present when updateHighlightWindows, thus elevating the window/tabbox
|
2020-09-23 18:39:59 +00:00
|
|
|
QTimer::singleShot(1, this, &TabBoxHandler::initHighlightWindows);
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2015-02-06 22:10:59 +00:00
|
|
|
void TabBoxHandler::initHighlightWindows()
|
2012-05-03 23:08:28 +00:00
|
|
|
{
|
2015-02-06 22:10:59 +00:00
|
|
|
if (isKWinCompositing()) {
|
2021-11-03 11:55:31 +00:00
|
|
|
const auto stack = stackingOrder();
|
2023-03-25 20:46:54 +00:00
|
|
|
for (Window *window : stack) {
|
|
|
|
shadeClient(window, false);
|
2015-02-06 22:10:59 +00:00
|
|
|
}
|
|
|
|
}
|
2012-05-03 23:08:28 +00:00
|
|
|
d->updateHighlightWindows();
|
|
|
|
}
|
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void TabBoxHandler::hide(bool abort)
|
|
|
|
{
|
2009-09-13 11:36:45 +00:00
|
|
|
d->isShown = false;
|
2022-07-02 22:58:42 +00:00
|
|
|
if (d->isHighlightWindows()) {
|
2011-01-30 14:34:42 +00:00
|
|
|
d->endHighlightWindows(abort);
|
|
|
|
}
|
2014-06-10 09:14:59 +00:00
|
|
|
#ifndef KWIN_UNIT_TEST
|
2013-12-10 06:14:44 +00:00
|
|
|
if (SwitcherItem *item = d->switcherItem()) {
|
|
|
|
item->setVisible(false);
|
|
|
|
}
|
2014-06-10 09:14:59 +00:00
|
|
|
#endif
|
2013-12-10 06:14:44 +00:00
|
|
|
if (QQuickWindow *w = d->window()) {
|
|
|
|
w->hide();
|
|
|
|
w->destroy();
|
|
|
|
}
|
|
|
|
d->m_mainItem = nullptr;
|
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 TabBoxHandler::nextPrev(bool forward) const
|
|
|
|
{
|
2009-09-13 11:36:45 +00:00
|
|
|
QModelIndex ret;
|
2023-03-24 16:23:54 +00:00
|
|
|
QAbstractItemModel *model = d->clientModel();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (forward) {
|
2009-09-13 11:36:45 +00:00
|
|
|
int column = d->index.column() + 1;
|
|
|
|
int row = d->index.row();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (column == model->columnCount()) {
|
2009-09-13 11:36:45 +00:00
|
|
|
column = 0;
|
|
|
|
row++;
|
2022-03-25 12:20:32 +00:00
|
|
|
if (row == model->rowCount()) {
|
2009-09-13 11:36:45 +00:00
|
|
|
row = 0;
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
ret = model->index(row, column);
|
2022-03-25 12:20:32 +00:00
|
|
|
if (!ret.isValid()) {
|
2011-01-30 14:34:42 +00:00
|
|
|
ret = model->index(0, 0);
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
} else {
|
2009-09-13 11:36:45 +00:00
|
|
|
int column = d->index.column() - 1;
|
|
|
|
int row = d->index.row();
|
2011-01-30 14:34:42 +00:00
|
|
|
if (column < 0) {
|
2009-09-13 11:36:45 +00:00
|
|
|
column = model->columnCount() - 1;
|
|
|
|
row--;
|
2022-03-25 12:20:32 +00:00
|
|
|
if (row < 0) {
|
2009-09-13 11:36:45 +00:00
|
|
|
row = model->rowCount() - 1;
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
|
|
|
ret = model->index(row, column);
|
|
|
|
if (!ret.isValid()) {
|
2009-10-29 17:02:54 +00:00
|
|
|
row = model->rowCount() - 1;
|
2011-01-30 14:34:42 +00:00
|
|
|
for (int i = model->columnCount() - 1; i >= 0; i--) {
|
|
|
|
ret = model->index(row, i);
|
2022-03-25 12:20:32 +00:00
|
|
|
if (ret.isValid()) {
|
2009-10-29 17:02:54 +00:00
|
|
|
break;
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2009-10-29 17:02:54 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2022-03-25 12:20:32 +00:00
|
|
|
if (ret.isValid()) {
|
2009-09-13 11:36:45 +00:00
|
|
|
return ret;
|
2022-03-25 12:20:32 +00:00
|
|
|
} else {
|
2009-09-13 11:36:45 +00:00
|
|
|
return d->index;
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
void TabBoxHandler::setCurrentIndex(const QModelIndex &index)
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2011-10-31 13:34:37 +00:00
|
|
|
if (d->index == index) {
|
|
|
|
return;
|
|
|
|
}
|
2011-11-04 18:27:02 +00:00
|
|
|
if (!index.isValid()) {
|
|
|
|
return;
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
d->index = index;
|
2023-03-24 16:23:54 +00:00
|
|
|
if (d->isHighlightWindows()) {
|
|
|
|
d->updateHighlightWindows();
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2021-06-08 07:02:14 +00:00
|
|
|
Q_EMIT selectedIndexChanged();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
const QModelIndex &TabBoxHandler::currentIndex() const
|
2011-10-31 13:34:37 +00:00
|
|
|
{
|
|
|
|
return d->index;
|
|
|
|
}
|
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
void TabBoxHandler::grabbedKeyEvent(QKeyEvent *event) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2014-06-02 15:21:53 +00:00
|
|
|
if (!d->m_mainItem || !d->window()) {
|
2013-12-10 06:14:44 +00:00
|
|
|
return;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2018-11-07 16:22:34 +00:00
|
|
|
QCoreApplication::sendEvent(d->window(), event);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
bool TabBoxHandler::containsPos(const QPoint &pos) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2013-12-10 06:14:44 +00:00
|
|
|
if (!d->m_mainItem) {
|
2011-07-09 09:12:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-12-10 06:14:44 +00:00
|
|
|
QWindow *w = d->window();
|
|
|
|
if (w) {
|
|
|
|
return w->geometry().contains(pos);
|
|
|
|
}
|
|
|
|
return false;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2023-03-25 20:46:54 +00:00
|
|
|
QModelIndex TabBoxHandler::index(Window *client) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
|
|
|
return d->clientModel()->index(client);
|
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2023-03-25 20:46:54 +00:00
|
|
|
QList<Window *> TabBoxHandler::clientList() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2009-09-13 11:36:45 +00:00
|
|
|
return d->clientModel()->clientList();
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2023-03-25 20:46:54 +00:00
|
|
|
Window *TabBoxHandler::client(const QModelIndex &index) const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2023-03-24 16:23:54 +00:00
|
|
|
if (!index.isValid()) {
|
2014-02-24 15:42:43 +00:00
|
|
|
return nullptr;
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2023-03-25 20:46:54 +00:00
|
|
|
Window *c = static_cast<Window *>(
|
2022-03-23 10:13:38 +00:00
|
|
|
d->clientModel()->data(index, ClientModel::ClientRole).value<void *>());
|
2009-09-13 11:36:45 +00:00
|
|
|
return c;
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2011-01-30 14:34:42 +00:00
|
|
|
void TabBoxHandler::createModel(bool partialReset)
|
|
|
|
{
|
2023-03-24 16:23:54 +00:00
|
|
|
d->clientModel()->createClientList(partialReset);
|
|
|
|
// TODO: C++11 use lambda function
|
|
|
|
bool lastRaised = false;
|
|
|
|
bool lastRaisedSucc = false;
|
|
|
|
const auto clients = stackingOrder();
|
2023-03-25 20:46:54 +00:00
|
|
|
for (Window *window : clients) {
|
|
|
|
if (window == d->lastRaisedClient) {
|
2023-03-24 16:23:54 +00:00
|
|
|
lastRaised = true;
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2023-03-25 20:46:54 +00:00
|
|
|
if (window == d->lastRaisedClientSucc) {
|
2023-03-24 16:23:54 +00:00
|
|
|
lastRaisedSucc = true;
|
2022-03-25 12:20:32 +00:00
|
|
|
}
|
2012-05-20 13:52:24 +00:00
|
|
|
}
|
2023-03-24 16:23:54 +00:00
|
|
|
if (d->lastRaisedClient && !lastRaised) {
|
|
|
|
d->lastRaisedClient = nullptr;
|
|
|
|
}
|
|
|
|
if (d->lastRaisedClientSucc && !lastRaisedSucc) {
|
|
|
|
d->lastRaisedClientSucc = nullptr;
|
2009-09-13 11:36:45 +00:00
|
|
|
}
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
QModelIndex TabBoxHandler::first() const
|
2011-01-30 14:34:42 +00:00
|
|
|
{
|
2023-03-24 16:23:54 +00:00
|
|
|
return d->clientModel()->index(0, 0);
|
2011-01-30 14:34:42 +00:00
|
|
|
}
|
2009-09-13 11:36:45 +00:00
|
|
|
|
2016-10-06 06:06:25 +00:00
|
|
|
bool TabBoxHandler::eventFilter(QObject *watched, QEvent *e)
|
|
|
|
{
|
|
|
|
if (e->type() == QEvent::Wheel && watched == d->window()) {
|
2022-03-23 10:13:38 +00:00
|
|
|
QWheelEvent *event = static_cast<QWheelEvent *>(e);
|
2016-10-06 06:06:25 +00:00
|
|
|
// On x11 the delta for vertical scrolling might also be on X for whatever reason
|
2022-11-21 17:23:00 +00:00
|
|
|
const int delta = std::abs(event->angleDelta().x()) > std::abs(event->angleDelta().y()) ? event->angleDelta().x() : event->angleDelta().y();
|
2016-10-06 06:06:25 +00:00
|
|
|
d->wheelAngleDelta += delta;
|
|
|
|
while (d->wheelAngleDelta <= -120) {
|
|
|
|
d->wheelAngleDelta += 120;
|
|
|
|
const QModelIndex index = nextPrev(true);
|
|
|
|
if (index.isValid()) {
|
|
|
|
setCurrentIndex(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (d->wheelAngleDelta >= 120) {
|
|
|
|
d->wheelAngleDelta -= 120;
|
|
|
|
const QModelIndex index = nextPrev(false);
|
|
|
|
if (index.isValid()) {
|
|
|
|
setCurrentIndex(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// pass on
|
|
|
|
return QObject::eventFilter(watched, e);
|
|
|
|
}
|
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
TabBoxHandler *tabBox = nullptr;
|
2009-09-13 11:36:45 +00:00
|
|
|
|
|
|
|
} // namespace TabBox
|
|
|
|
} // namespace KWin
|