Commit 6132329c authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Add Overview effect

This effect is meant to be as a replacement for the present windows and
the desktop grid effect. It is written using QML.

So far, this effect implements only the basic features of the present
windows effect. Desktop management features will be added later.

CCBUG: 295775
CCBUG: 303438
parent 30da8f49
......@@ -135,6 +135,7 @@ void TestBuiltInEffectLoader::testKnownEffects()
<< QStringLiteral("magnifier")
<< QStringLiteral("mouseclick")
<< QStringLiteral("mousemark")
<< QStringLiteral("overview")
<< QStringLiteral("presentwindows")
<< QStringLiteral("resize")
<< QStringLiteral("screenedge")
......@@ -201,6 +202,8 @@ void TestBuiltInEffectLoader::testSupported_data()
QTest::newRow("Magnifier") << QStringLiteral("magnifier") << false << qc << false;
QTest::newRow("MouseClick") << QStringLiteral("mouseclick") << true << qc << true;
QTest::newRow("MouseMark") << QStringLiteral("mousemark") << true << qc << true;
QTest::newRow("Overview") << QStringLiteral("overview") << false << qc << false;
QTest::newRow("OverviewGL") << QStringLiteral("overview") << true << oc << true;
QTest::newRow("PresentWindows") << QStringLiteral("presentwindows") << true << qc << true;
QTest::newRow("Resize") << QStringLiteral("resize") << true << qc << true;
QTest::newRow("ScreenEdge") << QStringLiteral("screenedge") << true << qc << true;
......@@ -278,6 +281,8 @@ void TestBuiltInEffectLoader::testLoadEffect_data()
QTest::newRow("Magnifier") << QStringLiteral("magnifier") << false << qc;
QTest::newRow("MouseClick") << QStringLiteral("mouseclick") << true << qc;
QTest::newRow("MouseMark") << QStringLiteral("mousemark") << true << qc;
QTest::newRow("Overview") << QStringLiteral("overview") << false << qc;
QTest::newRow("OverviewGL") << QStringLiteral("overview") << true << oc;
QTest::newRow("PresentWindows") << QStringLiteral("presentwindows") << true << qc;
QTest::newRow("Resize") << QStringLiteral("resize") << true << qc;
QTest::newRow("ScreenEdge") << QStringLiteral("screenedge") << true << qc;
......
......@@ -86,6 +86,8 @@ set(kwin4_effect_builtins_sources
magnifier/magnifier.cpp
mouseclick/mouseclick.cpp
mousemark/mousemark.cpp
overview/expolayout.cpp
overview/overvieweffect.cpp
presentwindows/presentwindows.cpp
presentwindows/presentwindows_proxy.cpp
resize/resize.cpp
......@@ -121,6 +123,7 @@ kconfig_add_kcfg_files(kwin4_effect_builtins_sources
magnifier/magnifierconfig.kcfgc
mouseclick/mouseclickconfig.kcfgc
mousemark/mousemarkconfig.kcfgc
overview/overviewconfig.kcfgc
presentwindows/presentwindowsconfig.kcfgc
resize/resizeconfig.kcfgc
showfps/showfpsconfig.kcfgc
......@@ -168,6 +171,7 @@ include(fallapart/CMakeLists.txt)
include(highlightwindow/CMakeLists.txt)
include(kscreen/CMakeLists.txt)
add_subdirectory(magiclamp)
add_subdirectory(overview)
add_subdirectory(presentwindows)
add_subdirectory(resize)
include(screenedge/CMakeLists.txt)
......
......@@ -13,6 +13,7 @@
#include "blur/blur.h"
#include "colorpicker/colorpicker.h"
#include "kscreen/kscreen.h"
#include "overview/overvieweffect.h"
#include "presentwindows/presentwindows.h"
#include "screenedge/screenedgeeffect.h"
#include "screenshot/screenshot.h"
......@@ -323,6 +324,22 @@ EFFECT_FALLBACK
#endif
EFFECT_FALLBACK
QStringLiteral("kwin_mousemark_config")
}, {
QStringLiteral("overview"),
i18ndc("kwin_effects", "Name of a KWin Effect", "Overview"),
i18ndc("kwin_effects", "Comment describing the KWin Effect", "Allows you to overview virtual desktops and windows (WIP)"),
QStringLiteral("Window Management"),
QString(),
QUrl(QStringLiteral("https://files.kde.org/plasma/kwin/effect-videos/present_windows.mp4")),
false,
false,
#ifdef EFFECT_BUILTINS
&createHelper<OverviewEffect>,
&OverviewEffect::supported,
nullptr,
#endif
EFFECT_FALLBACK
QStringLiteral("kwin_overview_config")
}, {
QStringLiteral("presentwindows"),
i18ndc("kwin_effects", "Name of a KWin Effect", "Present Windows"),
......
......@@ -38,6 +38,7 @@ enum class BuiltInEffect
Magnifier,
MouseClick,
MouseMark,
Overview,
PresentWindows,
Resize,
ScreenEdge,
......
# SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(kcm)
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/overview)
This diff is collapsed.
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QObject>
#include <QQuickItem>
#include <QRect>
#include <QTimer>
#include <optional>
class ExpoCell;
class ExpoLayout : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(LayoutMode mode READ mode WRITE setMode NOTIFY modeChanged)
Q_PROPERTY(bool fillGaps READ fillGaps WRITE setFillGaps NOTIFY fillGapsChanged)
public:
enum LayoutMode : uint {
LayoutClosest = 0,
LayoutKompose = 1,
LayoutNatural = 2,
};
Q_ENUM(LayoutMode)
explicit ExpoLayout(QQuickItem *parent = nullptr);
LayoutMode mode() const;
void setMode(LayoutMode mode);
bool fillGaps() const;
void setFillGaps(bool fill);
void addCell(ExpoCell *cell);
void removeCell(ExpoCell *cell);
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
public Q_SLOTS:
void update();
void scheduleUpdate();
Q_SIGNALS:
void modeChanged();
void fillGapsChanged();
private:
void calculateWindowTransformationsClosest();
void calculateWindowTransformationsKompose();
void calculateWindowTransformationsNatural();
QList<ExpoCell *> m_cells;
LayoutMode m_mode = LayoutNatural;
QTimer m_updateTimer;
int m_accuracy = 20;
bool m_fillGaps = false;
};
class ExpoCell : public QObject
{
Q_OBJECT
Q_PROPERTY(ExpoLayout *layout READ layout WRITE setLayout NOTIFY layoutChanged)
Q_PROPERTY(int naturalX READ naturalX WRITE setNaturalX NOTIFY naturalXChanged)
Q_PROPERTY(int naturalY READ naturalY WRITE setNaturalY NOTIFY naturalYChanged)
Q_PROPERTY(int naturalWidth READ naturalWidth WRITE setNaturalWidth NOTIFY naturalWidthChanged)
Q_PROPERTY(int naturalHeight READ naturalHeight WRITE setNaturalHeight NOTIFY naturalHeightChanged)
Q_PROPERTY(int x READ x NOTIFY xChanged)
Q_PROPERTY(int y READ y NOTIFY yChanged)
Q_PROPERTY(int width READ width NOTIFY widthChanged)
Q_PROPERTY(int height READ height NOTIFY heightChanged)
Q_PROPERTY(QString persistentKey READ persistentKey WRITE setPersistentKey NOTIFY persistentKeyChanged)
public:
explicit ExpoCell(QObject *parent = nullptr);
~ExpoCell() override;
ExpoLayout *layout() const;
void setLayout(ExpoLayout *layout);
int naturalX() const;
void setNaturalX(int x);
int naturalY() const;
void setNaturalY(int y);
int naturalWidth() const;
void setNaturalWidth(int width);
int naturalHeight() const;
void setNaturalHeight(int height);
QRect naturalRect() const;
int x() const;
void setX(int x);
int y() const;
void setY(int y);
int width() const;
void setWidth(int width);
int height() const;
void setHeight(int height);
QString persistentKey() const;
void setPersistentKey(const QString &key);
public Q_SLOTS:
void update();
Q_SIGNALS:
void layoutChanged();
void naturalXChanged();
void naturalYChanged();
void naturalWidthChanged();
void naturalHeightChanged();
void xChanged();
void yChanged();
void widthChanged();
void heightChanged();
void persistentKeyChanged();
private:
QString m_persistentKey;
int m_naturalX = 0;
int m_naturalY = 0;
int m_naturalWidth = 0;
int m_naturalHeight = 0;
std::optional<int> m_x;
std::optional<int> m_y;
std::optional<int> m_width;
std::optional<int> m_height;
QPointer<ExpoLayout> m_layout;
};
# SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
set(kwin_overview_config_SOURCES overvieweffectkcm.cpp)
ki18n_wrap_ui(kwin_overview_config_SOURCES overvieweffectkcm.ui)
kconfig_add_kcfg_files(kwin_overview_config_SOURCES ../overviewconfig.kcfgc)
add_library(kwin_overview_config MODULE ${kwin_overview_config_SOURCES})
target_link_libraries(kwin_overview_config
KF5::Completion
KF5::ConfigWidgets
KF5::GlobalAccel
KF5::I18n
KF5::XmlGui
KWinEffectsInterface
)
kcoreaddons_desktop_to_json(kwin_overview_config overvieweffectkcm.desktop SERVICE_TYPES kcmodule.desktop)
install(TARGETS kwin_overview_config DESTINATION ${KDE_INSTALL_PLUGINDIR}/kwin/effects/configs)
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "overvieweffectkcm.h"
#include "overviewconfig.h"
#include <config-kwin.h>
#include <kwineffects_interface.h>
#include <KAboutData>
#include <KActionCollection>
#include <KGlobalAccel>
#include <KLocalizedString>
#include <KPluginFactory>
#include <QAction>
K_PLUGIN_FACTORY_WITH_JSON(OverviewEffectConfigFactory,
"overvieweffectkcm.json",
registerPlugin<KWin::OverviewEffectConfig>();)
namespace KWin
{
OverviewEffectConfig::OverviewEffectConfig(QWidget *parent, const QVariantList &args)
: KCModule(parent, args)
{
ui.setupUi(this);
OverviewConfig::instance(KWIN_CONFIG);
addConfig(OverviewConfig::self(), this);
auto actionCollection = new KActionCollection(this, QStringLiteral("kwin"));
actionCollection->setComponentDisplayName(i18n("KWin"));
actionCollection->setConfigGroup(QStringLiteral("Overview"));
actionCollection->setConfigGlobal(true);
const QKeySequence defaultToggleShortcut = Qt::CTRL + Qt::META + Qt::Key_D;
QAction *toggleAction = actionCollection->addAction(QStringLiteral("Overview"));
toggleAction->setText(i18n("Toggle Overview"));
toggleAction->setProperty("isConfigurationAction", true);
KGlobalAccel::self()->setDefaultShortcut(toggleAction, {defaultToggleShortcut});
KGlobalAccel::self()->setShortcut(toggleAction, {defaultToggleShortcut});
ui.shortcutsEditor->addCollection(actionCollection);
connect(ui.shortcutsEditor, &KShortcutsEditor::keyChange, this, &OverviewEffectConfig::markAsChanged);
load();
}
OverviewEffectConfig::~OverviewEffectConfig()
{
// If save() is called, undo() has no effect.
ui.shortcutsEditor->undo();
}
void OverviewEffectConfig::save()
{
KCModule::save();
ui.shortcutsEditor->save();
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
QStringLiteral("/Effects"),
QDBusConnection::sessionBus());
interface.reconfigureEffect(QStringLiteral("overview"));
}
void OverviewEffectConfig::defaults()
{
ui.shortcutsEditor->allDefault();
KCModule::defaults();
}
} // namespace KWin
#include "overvieweffectkcm.moc"
# SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
#
# SPDX-License-Identifier: CC-0
[Desktop Entry]
Type=Service
X-KDE-ServiceTypes=KCModule
X-KDE-Library=kwin_overview_config
X-KDE-ParentComponents=overview
Name=overview
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <KCModule>
#include "ui_overvieweffectkcm.h"
namespace KWin
{
class OverviewEffectConfig : public KCModule
{
Q_OBJECT
public:
explicit OverviewEffectConfig(QWidget *parent = nullptr, const QVariantList &args = QVariantList());
~OverviewEffectConfig() override;
public Q_SLOTS:
void save() override;
void defaults() override;
private:
::Ui::OverviewEffectConfig ui;
};
} // namespace KWin
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<ui version="4.0">
<class>OverviewEffectConfig</class>
<widget class="QWidget" name="OverviewEffectConfig">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>455</width>
<height>177</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_LayoutMode">
<property name="text">
<string>Layout mode:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="kcfg_LayoutMode">
<item>
<property name="text">
<string>Closest</string>
</property>
</item>
<item>
<property name="text">
<string>Kompose</string>
</property>
</item>
<item>
<property name="text">
<string>Natural</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="KShortcutsEditor" name="shortcutsEditor" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="actionTypes">
<enum>KShortcutsEditor::GlobalAction</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KShortcutsEditor</class>
<extends>QWidget</extends>
<header location="global">KShortcutsEditor</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile arg="true"/>
<group name="Effect-Overview">
<entry name="LayoutMode" type="Int">
<default>2</default>
</entry>
<entry name="BorderActivate" type="IntList" />
<entry name="TouchBorderActivate" type="IntList" />
</group>
</kcfg>
# SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
#
# SPDX-License-Identifier: CC-0
File=overviewconfig.kcfg
ClassName=OverviewConfig
NameSpace=KWin
Singleton=true
Mutators=true
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "overvieweffect.h"
#include "expolayout.h"
#include "overviewconfig.h"
#include <KGlobalAccel>
#include <KLocalizedString>
#include <QAction>
#include <QDebug>
#include <QQmlContext>
#include <QQuickItem>
#include <QTimer>
#include <QWindow>
namespace KWin
{
OverviewScreenView::OverviewScreenView(EffectScreen *screen, QWindow *renderWindow, OverviewEffect *effect)
: EffectQuickScene(effect, renderWindow)
{
rootContext()->setContextProperty("effect", effect);
rootContext()->setContextProperty("targetScreen", screen);
setGeometry(screen->geometry());
setSource(QUrl(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/overview/qml/ScreenView.qml"))));
connect(screen, &EffectScreen::geometryChanged, this, [this, screen]() {
setGeometry(screen->geometry());
});
}
bool OverviewScreenView::isDirty() const
{
return m_dirty;
}
void OverviewScreenView::markDirty()
{
m_dirty = true;
}
void OverviewScreenView::resetDirty()
{
m_dirty = false;
}
void OverviewScreenView::scheduleRepaint()
{
markDirty();
effects->addRepaint(geometry());
}
void OverviewScreenView::stop()
{
QMetaObject::invokeMethod(rootItem(), "stop");
}
OverviewEffect::OverviewEffect()
: m_shutdownTimer(new QTimer(this))
{
qmlRegisterType<ExpoLayout>("org.kde.kwin.private.overview", 1, 0, "ExpoLayout");
qmlRegisterType<ExpoCell>("org.kde.kwin.private.overview", 1, 0, "ExpoCell");
m_shutdownTimer->setSingleShot(true);
connect(m_shutdownTimer, &QTimer::timeout, this, &OverviewEffect::realDeactivate);
const QKeySequence defaultToggleShortcut = Qt::CTRL + Qt::META + Qt::Key_D;
m_toggleAction = new QAction(this);
connect(m_toggleAction, &QAction::triggered, this, &OverviewEffect::toggle);
m_toggleAction->setObjectName(QStringLiteral("Overview"));
m_toggleAction->setText(i18n("Toggle Overview"));
KGlobalAccel::self()->setDefaultShortcut(m_toggleAction, {defaultToggleShortcut});
KGlobalAccel::self()->setShortcut(m_toggleAction, {defaultToggleShortcut});
m_toggleShortcut = KGlobalAccel::self()->shortcut(m_toggleAction);
effects->registerGlobalShortcut({defaultToggleShortcut}, m_toggleAction);
connect(effects, &EffectsHandler::screenAboutToLock, this, &OverviewEffect::realDeactivate);
initConfig<OverviewConfig>();
reconfigure(ReconfigureAll);
}
OverviewEffect::~OverviewEffect()
{
}
bool OverviewEffect::supported()
{
return effects->compositingType() == OpenGLCompositing;
}
void OverviewEffect::reconfigure(ReconfigureFlags)
{
OverviewConfig::self()->read();
setLayout(ExpoLayout::LayoutMode(OverviewConfig::layoutMode()));
setAnimationDuration(animationTime(300));
for (const ElectricBorder &border : qAsConst(m_borderActivate)) {
effects->unreserveElectricBorder(border, this);
}
for (const ElectricBorder &border : qAsConst(m_touchBorderActivate)) {
effects->unregisterTouchBorder(border, m_toggleAction);
}