effects: Add Window View effect
The Window View effect is a companion effect for the task manager. It provides the task manager a way to ask the user to pick a window among windows identified by window ids passed to the activate() method. The main motivation for adding this effect is to provide a QtQuick based alternative for the present windows effect, which is needed to kill the latter. This change doesn't extend the overview effect to avoid repeating mistakes of the past, i.e. adding too many (unrelated) features to the present windows effect. While the overview effect provides you a way to select windows, it's not the only thing that it has. For example, it also allows changing virtual desktops, etc. On the other hand, the task manager doesn't need all of that. It only needs to ask the user to pick a window among the specified windows, nothing more. As is, the window view effect is simply WindowHeap with a d-bus api slapped on top of it.
This commit is contained in:
parent
2ac1f9b7d3
commit
a0f456b7dc
8 changed files with 314 additions and 0 deletions
|
@ -86,6 +86,8 @@ add_subdirectory(slideback)
|
|||
add_subdirectory(slidingpopups)
|
||||
add_subdirectory(thumbnailaside)
|
||||
add_subdirectory(touchpoints)
|
||||
add_subdirectory(windowgeometry)
|
||||
add_subdirectory(windowview)
|
||||
add_subdirectory(zoom)
|
||||
|
||||
# OpenGL-specific effects
|
||||
|
|
14
src/effects/windowview/CMakeLists.txt
Normal file
14
src/effects/windowview/CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
# SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
set(windowview_SOURCES
|
||||
main.cpp
|
||||
windowvieweffect.cpp
|
||||
)
|
||||
|
||||
qt_add_dbus_adaptor(windowview_SOURCES org.kde.KWin.Effect.WindowView1.xml windowvieweffect.h KWin::WindowViewEffect)
|
||||
|
||||
kwin4_add_effect_module(kwin4_effect_windowview ${windowview_SOURCES})
|
||||
|
||||
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/windowview)
|
18
src/effects/windowview/main.cpp
Normal file
18
src/effects/windowview/main.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "windowvieweffect.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KWIN_EFFECT_FACTORY_SUPPORTED(WindowViewEffect,
|
||||
"metadata.json.stripped",
|
||||
return WindowViewEffect::supported();)
|
||||
|
||||
} // namespace KWin
|
||||
|
||||
#include "main.moc"
|
13
src/effects/windowview/metadata.json
Normal file
13
src/effects/windowview/metadata.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"KPlugin": {
|
||||
"Category": "Window Management",
|
||||
"Description": "Helper effect for the task manager",
|
||||
"EnabledByDefault": true,
|
||||
"Id": "windowview",
|
||||
"License": "GPL",
|
||||
"Name": "Window View"
|
||||
},
|
||||
"org.kde.kwin.effect": {
|
||||
"internal": true
|
||||
}
|
||||
}
|
24
src/effects/windowview/org.kde.KWin.Effect.WindowView1.xml
Normal file
24
src/effects/windowview/org.kde.KWin.Effect.WindowView1.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
-->
|
||||
<node name="/org/kde/KWin/Effect/WindowView1">
|
||||
<!--
|
||||
org.kde.KWin.Effect.WindowView1:
|
||||
@short_description: Application window selector
|
||||
|
||||
This interface provides a way to select windows interactively.
|
||||
-->
|
||||
<interface name="org.kde.KWin.Effect.WindowView1">
|
||||
<!--
|
||||
activate:
|
||||
@windows: The list with window ids.
|
||||
-->
|
||||
<method name="activate">
|
||||
<arg name="handles" type="as" direction="in" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
113
src/effects/windowview/qml/main.qml
Normal file
113
src/effects/windowview/qml/main.qml
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtGraphicalEffects 1.12
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
import org.kde.kwin.private.effects 1.0
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
|
||||
Item {
|
||||
id: container
|
||||
|
||||
required property QtObject effect
|
||||
required property QtObject targetScreen
|
||||
required property var selectedIds
|
||||
|
||||
property bool animationEnabled: false
|
||||
property bool organized: false
|
||||
|
||||
readonly property int animationDuration: PlasmaCore.Units.longDuration
|
||||
|
||||
function start() {
|
||||
container.animationEnabled = true;
|
||||
container.organized = true;
|
||||
}
|
||||
|
||||
function stop() {
|
||||
container.organized = false;
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: effect.deactivate(animationDuration);
|
||||
|
||||
KWinComponents.DesktopBackgroundItem {
|
||||
activity: KWinComponents.Workspace.currentActivity
|
||||
desktop: KWinComponents.Workspace.currentVirtualDesktop
|
||||
outputName: targetScreen.name
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: FastBlur {
|
||||
radius: container.organized ? 64 : 0
|
||||
Behavior on radius {
|
||||
NumberAnimation { duration: effect.animationDuration; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: PlasmaCore.ColorScope.backgroundColor
|
||||
opacity: container.organized ? 0.75 : 0
|
||||
|
||||
TapHandler {
|
||||
onTapped: effect.deactivate(animationDuration);
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
OpacityAnimator { duration: animationDuration; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
WindowHeap {
|
||||
width: targetScreen.geometry.width
|
||||
height: targetScreen.geometry.height
|
||||
focus: true
|
||||
padding: PlasmaCore.Units.largeSpacing
|
||||
animationDuration: container.animationDuration
|
||||
animationEnabled: container.animationEnabled
|
||||
dragEnabled: false
|
||||
organized: container.organized
|
||||
showOnly: selectedIds
|
||||
model: KWinComponents.ClientFilterModel {
|
||||
activity: KWinComponents.Workspace.currentActivity
|
||||
desktop: KWinComponents.Workspace.currentVirtualDesktop
|
||||
screenName: targetScreen.name
|
||||
clientModel: stackModel
|
||||
windowType: ~KWinComponents.ClientFilterModel.Dock &
|
||||
~KWinComponents.ClientFilterModel.Desktop &
|
||||
~KWinComponents.ClientFilterModel.Notification;
|
||||
}
|
||||
onActivated: effect.deactivate(animationDuration);
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: KWinComponents.ClientFilterModel {
|
||||
desktop: KWinComponents.Workspace.currentVirtualDesktop
|
||||
screenName: targetScreen.name
|
||||
clientModel: stackModel
|
||||
windowType: KWinComponents.ClientFilterModel.Dock
|
||||
}
|
||||
|
||||
KWinComponents.WindowThumbnailItem {
|
||||
id: windowThumbnail
|
||||
wId: model.client.internalId
|
||||
x: model.client.x - targetScreen.geometry.x
|
||||
y: model.client.y - targetScreen.geometry.y
|
||||
visible: opacity > 0
|
||||
opacity: (model.client.hidden || container.organized) ? 0 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: animationDuration; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KWinComponents.ClientModel {
|
||||
id: stackModel
|
||||
}
|
||||
|
||||
Component.onCompleted: start();
|
||||
}
|
92
src/effects/windowview/windowvieweffect.cpp
Normal file
92
src/effects/windowview/windowvieweffect.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "windowvieweffect.h"
|
||||
#include "windowview1adaptor.h"
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QTimer>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
static const QString s_dbusServiceName = QStringLiteral("org.kde.KWin.Effect.WindowView1");
|
||||
static const QString s_dbusObjectPath = QStringLiteral("/org/kde/KWin/Effect/WindowView1");
|
||||
|
||||
WindowViewEffect::WindowViewEffect()
|
||||
: m_shutdownTimer(new QTimer(this))
|
||||
{
|
||||
new WindowView1Adaptor(this);
|
||||
|
||||
QDBusConnection::sessionBus().registerObject(s_dbusObjectPath, this);
|
||||
QDBusConnection::sessionBus().registerService(s_dbusServiceName);
|
||||
|
||||
m_shutdownTimer->setSingleShot(true);
|
||||
connect(m_shutdownTimer, &QTimer::timeout, this, &WindowViewEffect::realDeactivate);
|
||||
connect(effects, &EffectsHandler::screenAboutToLock, this, &WindowViewEffect::realDeactivate);
|
||||
|
||||
setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/windowview/qml/main.qml"))));
|
||||
}
|
||||
|
||||
WindowViewEffect::~WindowViewEffect()
|
||||
{
|
||||
QDBusConnection::sessionBus().unregisterService(s_dbusServiceName);
|
||||
QDBusConnection::sessionBus().unregisterObject(s_dbusObjectPath);
|
||||
}
|
||||
|
||||
QVariantMap WindowViewEffect::initialProperties(EffectScreen *screen)
|
||||
{
|
||||
return QVariantMap {
|
||||
{ QStringLiteral("effect"), QVariant::fromValue(this) },
|
||||
{ QStringLiteral("targetScreen"), QVariant::fromValue(screen) },
|
||||
{ QStringLiteral("selectedIds"), QVariant::fromValue(m_windowIds) },
|
||||
};
|
||||
}
|
||||
|
||||
int WindowViewEffect::requestedEffectChainPosition() const
|
||||
{
|
||||
return 70;
|
||||
}
|
||||
|
||||
void WindowViewEffect::activate(const QStringList &windowIds)
|
||||
{
|
||||
QList<QUuid> internalIds;
|
||||
internalIds.reserve(windowIds.count());
|
||||
for (const QString &windowId : windowIds) {
|
||||
if (const auto window = effects->findWindow(windowId)) {
|
||||
internalIds.append(window->internalId());
|
||||
continue;
|
||||
}
|
||||
|
||||
// On X11, the task manager can pass a list with X11 ids.
|
||||
bool ok;
|
||||
if (const long legacyId = windowId.toLong(&ok); ok) {
|
||||
if (const auto window = effects->findWindow(legacyId)) {
|
||||
internalIds.append(window->internalId());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!internalIds.isEmpty()) {
|
||||
m_windowIds = internalIds;
|
||||
setRunning(true);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowViewEffect::deactivate(int timeout)
|
||||
{
|
||||
const auto screenViews = views();
|
||||
for (QuickSceneView *view : screenViews) {
|
||||
QMetaObject::invokeMethod(view->rootItem(), "stop");
|
||||
}
|
||||
m_shutdownTimer->start(timeout);
|
||||
}
|
||||
|
||||
void WindowViewEffect::realDeactivate()
|
||||
{
|
||||
setRunning(false);
|
||||
}
|
||||
|
||||
} // namespace KWin
|
38
src/effects/windowview/windowvieweffect.h
Normal file
38
src/effects/windowview/windowvieweffect.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kwinquickeffect.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class WindowViewEffect : public QuickSceneEffect
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WindowViewEffect();
|
||||
~WindowViewEffect() override;
|
||||
|
||||
int requestedEffectChainPosition() const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void activate(const QStringList &windowIds);
|
||||
void deactivate(int timeout);
|
||||
|
||||
protected:
|
||||
QVariantMap initialProperties(EffectScreen *screen) override;
|
||||
|
||||
private:
|
||||
void realDeactivate();
|
||||
|
||||
QTimer *m_shutdownTimer;
|
||||
QList<QUuid> m_windowIds;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
Loading…
Reference in a new issue