Advance Wayland and KDE package bring-up

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-14 10:51:06 +01:00
parent 51f3c21121
commit cf12defd28
15214 changed files with 20594243 additions and 269 deletions
@@ -0,0 +1,17 @@
remove_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_STRICT_ITERATORS -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_KEYWORDS)
add_subdirectory(common)
add_subdirectory(compositing)
add_subdirectory(options)
add_subdirectory(decoration)
add_subdirectory(rules)
add_subdirectory(screenedges)
add_subdirectory(scripts)
add_subdirectory(desktop)
add_subdirectory(effects)
add_subdirectory(virtualkeyboard)
add_subdirectory(xwayland)
if (KWIN_BUILD_TABBOX)
add_subdirectory(tabbox)
endif()
@@ -0,0 +1,40 @@
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwincommon\")
set(kcmkwincommon_SRC
effectsmodel.cpp
)
qt_add_dbus_interface(kcmkwincommon_SRC
${KWin_SOURCE_DIR}/src/org.kde.kwin.Effects.xml kwin_effects_interface
)
add_library(kcmkwincommon SHARED ${kcmkwincommon_SRC})
target_link_libraries(kcmkwincommon
Qt::Core
Qt::DBus
KF6::CoreAddons
KF6::ConfigCore
KF6::I18n
KF6::Package
KF6::KCMUtils
)
set_target_properties(kcmkwincommon PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION 6
)
install(TARGETS kcmkwincommon ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
set(kcm_kwin4_genericscripted_SRCS genericscriptedconfig.cpp)
qt_add_dbus_interface(kcm_kwin4_genericscripted_SRCS ${kwin_effects_dbus_xml} kwineffects_interface)
add_library(kcm_kwin4_genericscripted MODULE ${kcm_kwin4_genericscripted_SRCS})
target_link_libraries(kcm_kwin4_genericscripted
KF6::KCMUtils #KCModule
KF6::I18n
Qt::DBus
Qt::UiTools
)
install(TARGETS kcm_kwin4_genericscripted DESTINATION ${KDE_INSTALL_PLUGINDIR}/kwin/effects/configs)
@@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT `find . -name \*.cpp` -o $podir/kcmkwincommon.pot
@@ -0,0 +1,610 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2013 Antonis Tsiapaliokas <kok3rs@gmail.com>
SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "effectsmodel.h"
#include "config-kwin.h"
#include <kwin_effects_interface.h>
#include <KAboutData>
#include <KCMultiDialog>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KPackage/PackageLoader>
#include <KPluginMetaData>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusMessage>
#include <QDBusPendingCall>
#include <QDirIterator>
#include <QStandardPaths>
namespace KWin
{
static QString translatedCategory(const QString &category)
{
static const QList<QString> knownCategories = {
QStringLiteral("Accessibility"),
QStringLiteral("Appearance"),
QStringLiteral("Focus"),
QStringLiteral("Show Desktop Animation"),
QStringLiteral("Tools"),
QStringLiteral("Virtual Desktop Switching Animation"),
QStringLiteral("Window Management"),
QStringLiteral("Window Open/Close Animation")};
static const QList<QString> translatedCategories = {
i18nc("Category of Desktop Effects, used as section header", "Accessibility"),
i18nc("Category of Desktop Effects, used as section header", "Appearance"),
i18nc("Category of Desktop Effects, used as section header", "Focus"),
i18nc("Category of Desktop Effects, used as section header", "Peek at Desktop Animation"),
i18nc("Category of Desktop Effects, used as section header", "Tools"),
i18nc("Category of Desktop Effects, used as section header", "Virtual Desktop Switching Animation"),
i18nc("Category of Desktop Effects, used as section header", "Window Management"),
i18nc("Category of Desktop Effects, used as section header", "Window Open/Close Animation")};
const int index = knownCategories.indexOf(category);
if (index == -1) {
qDebug() << "Unknown category '" << category << "' and thus not translated";
return category;
}
return translatedCategories[index];
}
static EffectsModel::Status effectStatus(bool enabled)
{
return enabled ? EffectsModel::Status::Enabled : EffectsModel::Status::Disabled;
}
EffectsModel::EffectsModel(QObject *parent)
: QAbstractItemModel(parent)
{
}
QHash<int, QByteArray> EffectsModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames[NameRole] = "NameRole";
roleNames[DescriptionRole] = "DescriptionRole";
roleNames[AuthorNameRole] = "AuthorNameRole";
roleNames[AuthorEmailRole] = "AuthorEmailRole";
roleNames[LicenseRole] = "LicenseRole";
roleNames[VersionRole] = "VersionRole";
roleNames[CategoryRole] = "CategoryRole";
roleNames[ServiceNameRole] = "ServiceNameRole";
roleNames[IconNameRole] = "IconNameRole";
roleNames[StatusRole] = "StatusRole";
roleNames[VideoRole] = "VideoRole";
roleNames[WebsiteRole] = "WebsiteRole";
roleNames[SupportedRole] = "SupportedRole";
roleNames[ExclusiveRole] = "ExclusiveRole";
roleNames[ConfigurableRole] = "ConfigurableRole";
roleNames[EnabledByDefaultRole] = "EnabledByDefaultRole";
roleNames[EnabledByDefaultFunctionRole] = "EnabledByDefaultFunctionRole";
roleNames[ConfigModuleRole] = "ConfigModuleRole";
return roleNames;
}
QModelIndex EffectsModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_effects.count()) {
return {};
}
return createIndex(row, column);
}
QModelIndex EffectsModel::parent(const QModelIndex &child) const
{
return {};
}
int EffectsModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
int EffectsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_effects.count();
}
QVariant EffectsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return {};
}
const EffectData effect = m_effects.at(index.row());
switch (role) {
case Qt::DisplayRole:
case NameRole:
return effect.name;
case DescriptionRole:
return effect.description;
case AuthorNameRole:
return effect.authorName;
case AuthorEmailRole:
return effect.authorEmail;
case LicenseRole:
return effect.license;
case VersionRole:
return effect.version;
case CategoryRole:
return effect.category;
case ServiceNameRole:
return effect.serviceName;
case IconNameRole:
return effect.iconName;
case StatusRole:
return static_cast<int>(effect.status);
case VideoRole:
return effect.video;
case WebsiteRole:
return effect.website;
case SupportedRole:
return effect.supported;
case ExclusiveRole:
return effect.exclusiveGroup;
case InternalRole:
return effect.internal;
case ConfigurableRole:
return !effect.configModule.isEmpty();
case EnabledByDefaultRole:
return effect.enabledByDefault;
case EnabledByDefaultFunctionRole:
return effect.enabledByDefaultFunction;
case ConfigModuleRole:
return effect.configModule;
default:
return {};
}
}
bool EffectsModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid()) {
return QAbstractItemModel::setData(index, value, role);
}
if (role == StatusRole) {
// note: whenever the StatusRole is modified (even to the same value) the entry
// gets marked as changed and will get saved to the config file. This means the
// config file could get polluted
EffectData &data = m_effects[index.row()];
data.status = Status(value.toInt());
data.changed = data.status != data.originalStatus;
Q_EMIT dataChanged(index, index);
if (data.status == Status::Enabled && !data.exclusiveGroup.isEmpty()) {
// need to disable all other exclusive effects in the same category
for (int i = 0; i < m_effects.size(); ++i) {
if (i == index.row()) {
continue;
}
EffectData &otherData = m_effects[i];
if (otherData.exclusiveGroup == data.exclusiveGroup) {
otherData.status = Status::Disabled;
otherData.changed = otherData.status != otherData.originalStatus;
Q_EMIT dataChanged(this->index(i, 0), this->index(i, 0));
}
}
}
return true;
}
return QAbstractItemModel::setData(index, value, role);
}
void EffectsModel::loadBuiltInEffects(const KConfigGroup &kwinConfig)
{
const QString rootDirectory = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
QStringLiteral("kwin/builtin-effects"),
QStandardPaths::LocateDirectory);
const QStringList nameFilters{QStringLiteral("*.json")};
QDirIterator it(rootDirectory, nameFilters, QDir::Files);
while (it.hasNext()) {
it.next();
const KPluginMetaData metaData = KPluginMetaData::fromJsonFile(it.filePath());
if (!metaData.isValid()) {
continue;
}
EffectData effect;
effect.name = metaData.name();
effect.description = metaData.description();
effect.authorName = i18n("KWin development team");
effect.authorEmail = QString(); // not used at all
effect.license = metaData.license();
effect.version = metaData.version();
effect.untranslatedCategory = metaData.category();
effect.category = translatedCategory(metaData.category());
effect.serviceName = metaData.pluginId();
effect.iconName = metaData.iconName();
effect.enabledByDefault = metaData.isEnabledByDefault();
effect.supported = true;
effect.enabledByDefaultFunction = false;
effect.internal = false;
effect.configModule = metaData.value(QStringLiteral("X-KDE-ConfigModule"));
effect.website = QUrl(metaData.website());
if (metaData.rawData().contains("org.kde.kwin.effect")) {
const QJsonObject d(metaData.rawData().value("org.kde.kwin.effect").toObject());
effect.exclusiveGroup = d.value("exclusiveGroup").toString();
effect.video = QUrl::fromUserInput(d.value("video").toString());
effect.enabledByDefaultFunction = d.value("enabledByDefaultMethod").toBool();
effect.internal = d.value("internal").toBool();
}
const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName);
if (kwinConfig.hasKey(enabledKey)) {
effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault));
} else if (effect.enabledByDefaultFunction) {
effect.status = Status::EnabledUndeterminded;
} else {
effect.status = effectStatus(effect.enabledByDefault);
}
effect.originalStatus = effect.status;
if (shouldStore(effect)) {
m_pendingEffects << effect;
}
}
}
void EffectsModel::loadJavascriptEffects(const KConfigGroup &kwinConfig)
{
const auto plugins = KPackage::PackageLoader::self()->listPackages(
QStringLiteral("KWin/Effect"),
QStringLiteral("kwin/effects"));
for (const KPluginMetaData &plugin : plugins) {
EffectData effect;
effect.name = plugin.name();
effect.description = plugin.description();
const auto authors = plugin.authors();
effect.authorName = !authors.isEmpty() ? authors.first().name() : QString();
effect.authorEmail = !authors.isEmpty() ? authors.first().emailAddress() : QString();
effect.license = plugin.license();
effect.version = plugin.version();
effect.untranslatedCategory = plugin.category();
effect.category = translatedCategory(plugin.category());
effect.serviceName = plugin.pluginId();
effect.iconName = plugin.iconName();
effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", plugin.isEnabledByDefault()));
effect.originalStatus = effect.status;
effect.enabledByDefault = plugin.isEnabledByDefault();
effect.enabledByDefaultFunction = false;
effect.video = QUrl(plugin.value(QStringLiteral("X-KWin-Video-Url")));
effect.website = QUrl(plugin.website());
effect.supported = true;
effect.exclusiveGroup = plugin.value(QStringLiteral("X-KWin-Exclusive-Category"));
effect.internal = plugin.value(QStringLiteral("X-KWin-Internal"), false);
if (const QString configModule = plugin.value(QStringLiteral("X-KDE-ConfigModule")); !configModule.isEmpty()) {
if (configModule == QLatin1StringView("kcm_kwin4_genericscripted")) {
const QString xmlFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("kwin/effects/") + plugin.pluginId() + QLatin1String("/contents/config/main.xml"));
const QString uiFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("kwin/effects/") + plugin.pluginId() + QLatin1String("/contents/ui/config.ui"));
if (QFileInfo::exists(xmlFile) && QFileInfo::exists(uiFile)) {
effect.configModule = configModule;
effect.configArgs = QVariantList{plugin.pluginId(), QStringLiteral("KWin/Effect")};
}
} else {
effect.configModule = configModule;
}
}
if (shouldStore(effect)) {
m_pendingEffects << effect;
}
}
}
void EffectsModel::loadPluginEffects(const KConfigGroup &kwinConfig)
{
const auto pluginEffects = KPluginMetaData::findPlugins(QStringLiteral("kwin/effects/plugins"));
for (const KPluginMetaData &pluginEffect : pluginEffects) {
if (!pluginEffect.isValid()) {
continue;
}
EffectData effect;
effect.name = pluginEffect.name();
effect.description = pluginEffect.description();
effect.license = pluginEffect.license();
effect.version = pluginEffect.version();
effect.untranslatedCategory = pluginEffect.category();
effect.category = translatedCategory(pluginEffect.category());
effect.serviceName = pluginEffect.pluginId();
effect.iconName = pluginEffect.iconName();
effect.enabledByDefault = pluginEffect.isEnabledByDefault();
effect.supported = true;
effect.enabledByDefaultFunction = false;
effect.internal = false;
effect.configModule = pluginEffect.value(QStringLiteral("X-KDE-ConfigModule"));
for (int i = 0; i < pluginEffect.authors().count(); ++i) {
effect.authorName.append(pluginEffect.authors().at(i).name());
effect.authorEmail.append(pluginEffect.authors().at(i).emailAddress());
if (i + 1 < pluginEffect.authors().count()) {
effect.authorName.append(", ");
effect.authorEmail.append(", ");
}
}
if (pluginEffect.rawData().contains("org.kde.kwin.effect")) {
const QJsonObject d(pluginEffect.rawData().value("org.kde.kwin.effect").toObject());
effect.exclusiveGroup = d.value("exclusiveGroup").toString();
effect.video = QUrl::fromUserInput(d.value("video").toString());
effect.enabledByDefaultFunction = d.value("enabledByDefaultMethod").toBool();
}
effect.website = QUrl(pluginEffect.website());
const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName);
if (kwinConfig.hasKey(enabledKey)) {
effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault));
} else if (effect.enabledByDefaultFunction) {
effect.status = Status::EnabledUndeterminded;
} else {
effect.status = effectStatus(effect.enabledByDefault);
}
effect.originalStatus = effect.status;
if (shouldStore(effect)) {
m_pendingEffects << effect;
}
}
}
void EffectsModel::load(LoadOptions options)
{
KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), QStringLiteral("Plugins"));
m_pendingEffects.clear();
loadBuiltInEffects(kwinConfig);
loadJavascriptEffects(kwinConfig);
loadPluginEffects(kwinConfig);
std::sort(m_pendingEffects.begin(), m_pendingEffects.end(),
[](const EffectData &a, const EffectData &b) {
if (a.category == b.category) {
if (a.exclusiveGroup == b.exclusiveGroup) {
return a.name < b.name;
}
return a.exclusiveGroup < b.exclusiveGroup;
}
return a.category < b.category;
});
auto commit = [this, options] {
if (options == LoadOptions::KeepDirty) {
for (const EffectData &oldEffect : std::as_const(m_effects)) {
if (!oldEffect.changed) {
continue;
}
auto effectIt = std::find_if(m_pendingEffects.begin(), m_pendingEffects.end(),
[oldEffect](const EffectData &data) {
return data.serviceName == oldEffect.serviceName;
});
if (effectIt == m_pendingEffects.end()) {
continue;
}
effectIt->status = oldEffect.status;
effectIt->changed = effectIt->status != effectIt->originalStatus;
}
}
beginResetModel();
m_effects = m_pendingEffects;
m_pendingEffects.clear();
endResetModel();
Q_EMIT loaded();
};
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
QStringLiteral("/Effects"),
QDBusConnection::sessionBus());
if (interface.isValid()) {
QStringList effectNames;
effectNames.reserve(m_pendingEffects.count());
for (const EffectData &data : std::as_const(m_pendingEffects)) {
effectNames.append(data.serviceName);
}
const int serial = ++m_lastSerial;
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(interface.areEffectsSupported(effectNames), this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [=, this](QDBusPendingCallWatcher *self) {
self->deleteLater();
if (m_lastSerial != serial) {
return;
}
const QDBusPendingReply<QList<bool>> reply = *self;
if (reply.isError()) {
commit();
return;
}
const QList<bool> supportedValues = reply.value();
if (supportedValues.count() != effectNames.count()) {
return;
}
for (int i = 0; i < effectNames.size(); ++i) {
const bool supported = supportedValues.at(i);
const QString effectName = effectNames.at(i);
auto it = std::find_if(m_pendingEffects.begin(), m_pendingEffects.end(),
[effectName](const EffectData &data) {
return data.serviceName == effectName;
});
if (it == m_pendingEffects.end()) {
continue;
}
if ((*it).supported != supported) {
(*it).supported = supported;
}
}
commit();
});
} else {
commit();
}
}
void EffectsModel::updateEffectStatus(const QModelIndex &rowIndex, Status effectState)
{
setData(rowIndex, static_cast<int>(effectState), StatusRole);
}
void EffectsModel::save()
{
KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), QStringLiteral("Plugins"));
QList<EffectData> dirtyEffects;
for (EffectData &effect : m_effects) {
if (!effect.changed) {
continue;
}
effect.changed = false;
effect.originalStatus = effect.status;
const QString key = effect.serviceName + QStringLiteral("Enabled");
const bool shouldEnable = (effect.status != Status::Disabled);
const bool restoreToDefault = effect.enabledByDefaultFunction
? effect.status == Status::EnabledUndeterminded
: shouldEnable == effect.enabledByDefault;
if (restoreToDefault) {
kwinConfig.deleteEntry(key);
} else {
kwinConfig.writeEntry(key, shouldEnable);
}
dirtyEffects.append(effect);
}
if (dirtyEffects.isEmpty()) {
return;
}
kwinConfig.sync();
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
QStringLiteral("/Effects"),
QDBusConnection::sessionBus());
if (!interface.isValid()) {
return;
}
// Unload effects first, it's need to ensure that switching between mutually exclusive
// effects works as expected, for example so global shortcuts are handed over, etc.
auto split = std::partition(dirtyEffects.begin(), dirtyEffects.end(), [](const EffectData &data) {
return data.status == Status::Disabled;
});
for (auto it = dirtyEffects.begin(); it != split; ++it) {
interface.unloadEffect(it->serviceName);
}
for (auto it = split; it != dirtyEffects.end(); ++it) {
interface.loadEffect(it->serviceName);
}
}
void EffectsModel::defaults()
{
for (int i = 0; i < m_effects.count(); ++i) {
const auto &effect = m_effects.at(i);
if (effect.enabledByDefaultFunction && effect.status != Status::EnabledUndeterminded) {
updateEffectStatus(index(i, 0), Status::EnabledUndeterminded);
} else if (static_cast<bool>(effect.status) != effect.enabledByDefault) {
updateEffectStatus(index(i, 0), effect.enabledByDefault ? Status::Enabled : Status::Disabled);
}
}
}
bool EffectsModel::isDefaults() const
{
return std::all_of(m_effects.constBegin(), m_effects.constEnd(), [](const EffectData &effect) {
if (effect.enabledByDefaultFunction && effect.status != Status::EnabledUndeterminded) {
return false;
}
if (static_cast<bool>(effect.status) != effect.enabledByDefault) {
return false;
}
return true;
});
}
bool EffectsModel::needsSave() const
{
return std::any_of(m_effects.constBegin(), m_effects.constEnd(),
[](const EffectData &data) {
return data.changed;
});
}
QModelIndex EffectsModel::findByPluginId(const QString &pluginId) const
{
auto it = std::find_if(m_effects.constBegin(), m_effects.constEnd(),
[pluginId](const EffectData &data) {
return data.serviceName == pluginId;
});
if (it == m_effects.constEnd()) {
return {};
}
return index(std::distance(m_effects.constBegin(), it), 0);
}
void EffectsModel::requestConfigure(const QModelIndex &index, QWindow *transientParent)
{
if (!index.isValid()) {
return;
}
const EffectData &effect = m_effects.at(index.row());
Q_ASSERT(!effect.configModule.isEmpty());
KCMultiDialog *dialog = new KCMultiDialog();
dialog->addModule(KPluginMetaData(QStringLiteral("kwin/effects/configs/") + effect.configModule), effect.configArgs);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->winId();
dialog->windowHandle()->setTransientParent(transientParent);
dialog->show();
}
bool EffectsModel::shouldStore(const EffectData &data) const
{
return !data.internal;
}
}
#include "moc_effectsmodel.cpp"
@@ -0,0 +1,262 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2013 Antonis Tsiapaliokas <kok3rs@gmail.com>
SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <kwin_export.h>
#include <KSharedConfig>
#include <QAbstractItemModel>
#include <QString>
#include <QUrl>
#include <QWindow>
namespace KWin
{
class KWIN_EXPORT EffectsModel : public QAbstractItemModel
{
Q_OBJECT
public:
/**
* This enum type is used to specify data roles.
*/
enum AdditionalRoles {
/**
* The user-friendly name of the effect.
*/
NameRole = Qt::UserRole + 1,
/**
* The description of the effect.
*/
DescriptionRole,
/**
* The name of the effect's author. If there are several authors, they
* will be comma separated.
*/
AuthorNameRole,
/**
* The email of the effect's author. If there are several authors, the
* emails will be comma separated.
*/
AuthorEmailRole,
/**
* The license of the effect.
*/
LicenseRole,
/**
* The version of the effect.
*/
VersionRole,
/**
* The category of the effect.
*/
CategoryRole,
/**
* The service name(plugin name) of the effect.
*/
ServiceNameRole,
/**
* The icon name of the effect.
*/
IconNameRole,
/**
* Whether the effect is enabled or disabled.
*/
StatusRole,
/**
* Link to a video demonstration of the effect.
*/
VideoRole,
/**
* Link to the home page of the effect.
*/
WebsiteRole,
/**
* Whether the effect is supported.
*/
SupportedRole,
/**
* The exclusive group of the effect.
*/
ExclusiveRole,
/**
* Whether the effect is internal.
*/
InternalRole,
/**
* Whether the effect has a KCM.
*/
ConfigurableRole,
/**
* Whether the effect is enabled by default.
*/
EnabledByDefaultRole,
/**
* Id of the effect's config module, empty if the effect has no config.
*/
ConfigModuleRole,
/**
* Whether the effect has a function to determine if the effect is enabled by default.
*/
EnabledByDefaultFunctionRole,
};
/**
* This enum type is used to specify the status of a given effect.
*/
enum class Status {
/**
* The effect is disabled.
*/
Disabled = Qt::Unchecked,
/**
* An enable function is used to determine whether the effect is enabled.
* For example, such function can be useful to disable the blur effect
* when running in a virtual machine.
*/
EnabledUndeterminded = Qt::PartiallyChecked,
/**
* The effect is enabled.
*/
Enabled = Qt::Checked
};
explicit EffectsModel(QObject *parent = nullptr);
// Reimplemented from QAbstractItemModel.
QHash<int, QByteArray> roleNames() const override;
QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent = {}) const override;
int columnCount(const QModelIndex &parent = {}) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
/**
* Changes the status of a given effect.
*
* @param rowIndex An effect represented by the given index.
* @param effectState The new state.
* @note In order to actually apply the change, you have to call save().
*/
void updateEffectStatus(const QModelIndex &rowIndex, Status effectState);
/**
* This enum type is used to specify load options.
*/
enum class LoadOptions {
None,
/**
* Do not discard unsaved changes when reloading the model.
*/
KeepDirty
};
/**
* Loads effects.
*
* You have to call this method in order to populate the model.
*/
void load(LoadOptions options = LoadOptions::None);
/**
* Saves status of each modified effect.
*/
void save();
/**
* Resets the status of each effect to the default state.
*
* @note In order to actually apply the change, you have to call save().
*/
void defaults();
/**
* Whether the status of each effect is its default state.
*/
bool isDefaults() const;
/**
* Whether the model has unsaved changes.
*/
bool needsSave() const;
/**
* Finds an effect with the given plugin id.
*/
QModelIndex findByPluginId(const QString &pluginId) const;
/**
* Shows a configuration dialog for a given effect.
*
* @param index An effect represented by the given index.
* @param transientParent The transient parent of the configuration dialog.
*/
void requestConfigure(const QModelIndex &index, QWindow *transientParent);
Q_SIGNALS:
/**
* This signal is emitted when the model is loaded or reloaded.
*
* @see load
*/
void loaded();
protected:
struct EffectData
{
QString name;
QString description;
QString authorName;
QString authorEmail;
QString license;
QString version;
QString untranslatedCategory;
QString category;
QString serviceName;
QString iconName;
Status status;
Status originalStatus;
bool enabledByDefault;
bool enabledByDefaultFunction;
QUrl video;
QUrl website;
bool supported;
QString exclusiveGroup;
bool internal;
bool changed = false;
QString configModule;
QVariantList configArgs;
};
/**
* Returns whether the given effect should be stored in the model.
*
* @param data The effect.
* @returns @c true if the effect should be stored, otherwise @c false.
*/
virtual bool shouldStore(const EffectData &data) const;
private:
void loadBuiltInEffects(const KConfigGroup &kwinConfig);
void loadJavascriptEffects(const KConfigGroup &kwinConfig);
void loadPluginEffects(const KConfigGroup &kwinConfig);
QList<EffectData> m_effects;
QList<EffectData> m_pendingEffects;
int m_lastSerial = -1;
Q_DISABLE_COPY(EffectsModel)
};
}
@@ -0,0 +1,185 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "genericscriptedconfig.h"
#include "config-kwin.h"
#include <kwineffects_interface.h>
#include <KLocalizedString>
#include <KLocalizedTranslator>
#include <kconfigloader.h>
#include <QFile>
#include <QLabel>
#include <QStandardPaths>
#include <QUiLoader>
#include <QVBoxLayout>
namespace KWin
{
QObject *GenericScriptedConfigFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args)
{
if (qstrcmp(iface, "KCModule") == 0) {
if (args.count() < 2) {
qWarning() << Q_FUNC_INFO << "expects two arguments (plugin id, package type)";
return nullptr;
}
const QString pluginId = args.at(0).toString();
const QString packageType = args.at(1).toString();
if (packageType == QLatin1StringView("KWin/Effect")) {
return new ScriptedEffectConfig(pluginId, parentWidget, args);
} else if (packageType == QLatin1StringView("KWin/Script")) {
return new ScriptingConfig(pluginId, parentWidget, args);
} else {
qWarning() << Q_FUNC_INFO << "got unknown package type:" << packageType;
}
}
return nullptr;
}
GenericScriptedConfig::GenericScriptedConfig(const QString &keyword, QWidget *parent, const QVariantList &args)
: KCModule(parent, KPluginMetaData())
, m_packageName(keyword)
, m_translator(new KLocalizedTranslator(this))
{
QCoreApplication::instance()->installTranslator(m_translator);
}
GenericScriptedConfig::~GenericScriptedConfig()
{
}
void GenericScriptedConfig::createUi()
{
QVBoxLayout *layout = new QVBoxLayout(widget());
const QString packageRoot = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
QLatin1String("kwin/") + typeName() + QLatin1Char('/') + m_packageName,
QStandardPaths::LocateDirectory);
if (packageRoot.isEmpty()) {
layout->addWidget(new QLabel(i18nc("Error message", "Could not locate package metadata")));
return;
}
const KPluginMetaData metaData = KPluginMetaData::fromJsonFile(packageRoot + QLatin1String("/metadata.json"));
if (!metaData.isValid()) {
layout->addWidget(new QLabel(i18nc("Required file does not exist", "%1 does not contain a valid metadata.json file", qPrintable(packageRoot))));
return;
}
const QString kconfigXTFile = packageRoot + QLatin1String("/contents/config/main.xml");
if (!QFileInfo::exists(kconfigXTFile)) {
layout->addWidget(new QLabel(i18nc("Required file does not exist", "%1 does not exist", qPrintable(kconfigXTFile))));
return;
}
const QString uiPath = packageRoot + QLatin1String("/contents/ui/config.ui");
if (!QFileInfo::exists(uiPath)) {
layout->addWidget(new QLabel(i18nc("Required file does not exist", "%1 does not exist", qPrintable(uiPath))));
return;
}
const QString localePath = packageRoot + QLatin1String("/contents/locale");
if (QFileInfo::exists(localePath)) {
KLocalizedString::addDomainLocaleDir(metaData.value("X-KWin-Config-TranslationDomain").toUtf8(), localePath);
}
QFile xmlFile(kconfigXTFile);
KConfigGroup cg = configGroup();
KConfigLoader *configLoader = new KConfigLoader(cg, &xmlFile, this);
// load the ui file
QUiLoader *loader = new QUiLoader(this);
loader->setLanguageChangeEnabled(true);
QFile uiFile(uiPath);
m_translator->setTranslationDomain(metaData.value("X-KWin-Config-TranslationDomain"));
uiFile.open(QFile::ReadOnly);
QWidget *customConfigForm = loader->load(&uiFile, widget());
m_translator->addContextToMonitor(customConfigForm->objectName());
uiFile.close();
// send a custom event to the translator to retranslate using our translator
QEvent le(QEvent::LanguageChange);
QCoreApplication::sendEvent(customConfigForm, &le);
layout->addWidget(customConfigForm);
addConfig(configLoader, customConfigForm);
}
void GenericScriptedConfig::save()
{
KCModule::save();
reload();
}
void GenericScriptedConfig::reload()
{
}
ScriptedEffectConfig::ScriptedEffectConfig(const QString &keyword, QWidget *parent, const QVariantList &args)
: GenericScriptedConfig(keyword, parent, args)
{
createUi();
}
ScriptedEffectConfig::~ScriptedEffectConfig()
{
}
QString ScriptedEffectConfig::typeName() const
{
return QStringLiteral("effects");
}
KConfigGroup ScriptedEffectConfig::configGroup()
{
return KSharedConfig::openConfig(KWIN_CONFIG)->group(QLatin1String("Effect-") + packageName());
}
void ScriptedEffectConfig::reload()
{
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
QStringLiteral("/Effects"),
QDBusConnection::sessionBus());
interface.reconfigureEffect(packageName());
}
ScriptingConfig::ScriptingConfig(const QString &keyword, QWidget *parent, const QVariantList &args)
: GenericScriptedConfig(keyword, parent, args)
{
createUi();
}
ScriptingConfig::~ScriptingConfig()
{
}
KConfigGroup ScriptingConfig::configGroup()
{
return KSharedConfig::openConfig(KWIN_CONFIG)->group(QLatin1String("Script-") + packageName());
}
QString ScriptingConfig::typeName() const
{
return QStringLiteral("scripts");
}
void ScriptingConfig::reload()
{
// TODO: what to call
}
} // namespace
#include "moc_genericscriptedconfig.cpp"
@@ -0,0 +1,85 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <KCModule>
#include <KConfigGroup>
#include <KPluginFactory>
class KLocalizedTranslator;
namespace KWin
{
class GenericScriptedConfigFactory : public KPluginFactory
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.kde.KPluginFactory" FILE "genericscriptedconfig.json")
Q_INTERFACES(KPluginFactory)
protected:
QObject *create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args) override;
};
class GenericScriptedConfig : public KCModule
{
Q_OBJECT
public:
GenericScriptedConfig(const QString &keyword, QWidget *parent, const QVariantList &args);
~GenericScriptedConfig() override;
public Q_SLOTS:
void save() override;
protected:
const QString &packageName() const;
void createUi();
virtual QString typeName() const = 0;
virtual KConfigGroup configGroup() = 0;
virtual void reload();
private:
QString m_packageName;
KLocalizedTranslator *m_translator;
};
class ScriptedEffectConfig : public GenericScriptedConfig
{
Q_OBJECT
public:
ScriptedEffectConfig(const QString &keyword, QWidget *parent, const QVariantList &args);
~ScriptedEffectConfig() override;
protected:
QString typeName() const override;
KConfigGroup configGroup() override;
void reload() override;
};
class ScriptingConfig : public GenericScriptedConfig
{
Q_OBJECT
public:
ScriptingConfig(const QString &keyword, QWidget *parent, const QVariantList &args);
~ScriptingConfig() override;
protected:
QString typeName() const override;
KConfigGroup configGroup() override;
void reload() override;
};
inline const QString &GenericScriptedConfig::packageName() const
{
return m_packageName;
}
}
@@ -0,0 +1,4 @@
{
"Type": "Service",
"X-KDE-Library": "kcm_kwin4_genericscripted"
}
@@ -0,0 +1,32 @@
#########################################################################
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwincompositing\")
################# configure checks and create the configured files #################
set(kwincompositing_SRC
main.cpp
kwincompositingdata.cpp
)
kconfig_add_kcfg_files(kwincompositing_SRC kwincompositing_setting.kcfgc GENERATE_MOC)
qt_add_dbus_interface(kwincompositing_SRC
${KWin_SOURCE_DIR}/src/org.kde.kwin.Compositing.xml kwin_compositing_interface
)
ki18n_wrap_ui(kwincompositing_SRC compositing.ui)
kcoreaddons_add_plugin(kwincompositing SOURCES ${kwincompositing_SRC} INSTALL_NAMESPACE "plasma/kcms/systemsettings_qwidgets")
kcmutils_generate_desktop_file(kwincompositing)
target_link_libraries(kwincompositing
Qt::DBus
Qt::Widgets
KF6::ConfigCore
KF6::CoreAddons
KF6::I18n
KF6::KCMUtils
KF6::WindowSystem
)
@@ -0,0 +1,3 @@
#! /usr/bin/env bash
$EXTRACTRC `find . -name \*.ui` >> rc.cpp || exit 11
$XGETTEXT *.cpp -o $podir/kcmkwincompositing.pot
@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CompositingForm</class>
<widget class="QWidget" name="CompositingForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>526</width>
<height>395</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0" colspan="2">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="KMessageWidget" name="glCrashedWarning">
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>OpenGL compositing (the default) has crashed KWin in the past.
This was most likely due to a driver bug.
If you think that you have meanwhile upgraded to a stable driver,
you can reset this protection but be aware that this might result in an immediate crash!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DialogWarning"/>
</property>
</widget>
</item>
<item>
<widget class="KMessageWidget" name="windowThumbnailWarning">
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Keeping the window thumbnail always interferes with the minimized state of windows. This can result in windows not suspending their work when minimized.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DialogWarning"/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="compositingLabel">
<property name="text">
<string>Compositing:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="kcfg_Enabled">
<property name="text">
<string>Enable on startup</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="kcfg_WindowsBlockCompositing">
<property name="toolTip">
<string>Applications can set a hint to block compositing when the window is open.
This brings performance improvements for e.g. games.
The setting can be overruled by window-specific rules.</string>
</property>
<property name="text">
<string>Allow applications to block compositing</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="animationSpeedLabel">
<property name="text">
<string>Animation speed:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QWidget" name="animationSpeedControls" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QSlider" name="animationDurationFactor">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="_3">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Very slow</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Instant</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_HiddenPreviews">
<property name="text">
<string>Keep window thumbnails:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QComboBox" name="kcfg_HiddenPreviews">
<item>
<property name="text">
<string>Never</string>
</property>
</item>
<item>
<property name="text">
<string>Only for Shown Windows</string>
</property>
</item>
<item>
<property name="text">
<string>Always</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KMessageWidget</class>
<extends>QFrame</extends>
<header>kmessagewidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,144 @@
{
"KPlugin": {
"BugReportUrl": "https://bugs.kde.org/enter_bug.cgi?product=systemsettings&component=kcm_kwincompositing",
"Description": "Compositor Settings for Desktop Effects",
"Description[ar]": "إعدادات المركب لتأثيرات سطح المكتب",
"Description[az]": "İş masası effektləri üçün düzücü ayarları",
"Description[be]": "Налады сродку кампазітынгу для эфектаў працоўнага стала",
"Description[bg]": "Настройки на композитора за ефекти на работния плот",
"Description[ca@valencia]": "Configureu el compositor per als efectes de l'escriptori",
"Description[ca]": "Arranjament del compositor per als efectes d'escriptori",
"Description[cs]": "Nastavení kompozitoru pro efekty pracovní plochy",
"Description[da]": "Kompositørrindstillinger for skrivebordseffekter",
"Description[de]": "Compositor-Einstellungen für Arbeitsflächen-Effekte",
"Description[en_GB]": "Compositor Settings for Desktop Effects",
"Description[eo]": "Komponisto-Agordoj por Labortablo-Efikoj",
"Description[es]": "Preferencias del compositor para los efectos del escritorio",
"Description[et]": "Komposiitori seadistused töölauaefektide tarbeks",
"Description[eu]": "Konposatzailearen ezarpenak mahaigaineko efektuetarako",
"Description[fi]": "Koostamisasetukset työpöytätehosteille",
"Description[fr]": "Configuration du compositeur pour les effets de bureau",
"Description[gl]": "Configuración do compositor para os efectos de escritorio.",
"Description[he]": "הגדרות מנהל חלונאי לאפקטים של שולחן העבודה",
"Description[hu]": "Kompozitorbeállítások az asztali effektusokhoz",
"Description[ia]": "Preferentias de compositor pro le effectos de scriptorio",
"Description[id]": "Pengaturan Kompositor untuk Efek Jendela",
"Description[is]": "Myndsmiðsstillingar fyrir skjáborðsbrellur",
"Description[it]": "Impostazioni del compositore per gli effetti del desktop",
"Description[ja]": "デスクトップ効果のためのコンポジタ設定",
"Description[ka]": "კომპოზიტორის მორგება სამუშაო მაგიდის ეფექტებისთვის",
"Description[ko]": "데스크톱 효과에 사용되는 컴포지터 설정",
"Description[lt]": "Kompozitoriaus nuostatos skirtos darbalaukio efektams",
"Description[lv]": "Kompozitora iestatījumi darbvirsmas efektiem",
"Description[nb]": "Sammensetterinnstillinger for skrivebordseffekter",
"Description[nl]": "Instellingen van compositor configureren voor bureaubladeffecten",
"Description[nn]": "Samansetjarinnstillingar for skrivebordseffektar",
"Description[pl]": "Ustawienia kompozytora dla efektów pulpitu",
"Description[pt]": "Configuração dos Efeitos de Ecrã do Compositor",
"Description[pt_BR]": "Definições do Compositor para os efeitos da área de trabalho",
"Description[ro]": "Configurări compozitor pentru efecte de birou",
"Description[ru]": "Настройка модуля обеспечения эффектов рабочего стола",
"Description[sa]": "डेस्कटॉप इफेक्ट्स् कृते कम्पोजिटर सेटिंग्स्",
"Description[sk]": "Nastavenia kompozítora pre efekty plochy",
"Description[sl]": "Nastavitev upravljalnika skladnje za učinke namizja",
"Description[sv]": "Sammansättningsinställningar för skrivbordseffekter",
"Description[ta]": "பணிமேடை அசைவூட்டங்களுக்கான அமைப்புகள்",
"Description[tr]": "Masaüstü Efektleri için Bileşikleştirici Ayarları",
"Description[uk]": "Параметри засобу композиції для ефектів стільниці",
"Description[vi]": "Các thiết lập trình kết hợp cho các hiệu ứng bàn làm việc",
"Description[x-test]": "xxCompositor Settings for Desktop Effectsxx",
"Description[zh_CN]": "桌面特效显示合成器设置",
"Description[zh_TW]": "合成器的桌面效果設定",
"Icon": "preferences-desktop",
"Name": "Compositor",
"Name[ar]": "المركب",
"Name[ast]": "Compositor",
"Name[az]": "Düzücü vasitəsi",
"Name[be]": "Сродак кампазітынгу",
"Name[bg]": "Композитор на визуални ефекти",
"Name[ca@valencia]": "Compositor",
"Name[ca]": "Compositor",
"Name[cs]": "Kompozitor",
"Name[da]": "Kompositør",
"Name[de]": "Compositor",
"Name[el]": "Συνθέτης",
"Name[en_GB]": "Compositor",
"Name[eo]": "Kompostisto",
"Name[es]": "Compositor",
"Name[et]": "Komposiitor",
"Name[eu]": "Konposatzailea",
"Name[fi]": "Koostin",
"Name[fr]": "Compositeur",
"Name[gl]": "Compositor",
"Name[he]": "מנהל חלונאי",
"Name[hu]": "Kompozitor",
"Name[ia]": "Compositor",
"Name[id]": "Kompositor",
"Name[is]": "Myndsmiður",
"Name[it]": "Compositore",
"Name[ja]": "コンポジタ",
"Name[ka]": "კომპოზიტორი",
"Name[ko]": "컴포지터",
"Name[lt]": "Kompozitorius",
"Name[lv]": "Kompozitors",
"Name[nb]": "Sammensetter",
"Name[nl]": "Opsteller",
"Name[nn]": "Samansetjar",
"Name[pl]": "Kompozytor",
"Name[pt]": "Compositor",
"Name[pt_BR]": "Compositor",
"Name[ro]": "Compozitor",
"Name[ru]": "Обеспечение эффектов",
"Name[sa]": "रचयिता",
"Name[sk]": "Kompozítor",
"Name[sl]": "Upravljalnik skladnje",
"Name[sv]": "Sammansättning",
"Name[ta]": "சாளரநிரல்",
"Name[tr]": "Bileşikleştirici",
"Name[uk]": "Засіб композиції",
"Name[vi]": "Trình kết hợp",
"Name[x-test]": "xxCompositorxx",
"Name[zh_CN]": "显示特效合成器",
"Name[zh_TW]": "合成器"
},
"X-DocPath": "https://userbase.kde.org/Desktop_Effects_Performance#Advanced_Desktop_Effects_Settings",
"X-KDE-Keywords": "kwin,window,manager,compositing,compositor,effect,3D effects,2D effects,video settings,graphical effects,desktop effects,graphics,latency,vsync,tearing,window thumbnails",
"X-KDE-Keywords[ar]": "كوين,نافذة,مدير,تركيب,مركب,تأثير,تأثيرات ثلاثية الأبعاد,تأثيرات ثنائية الأبعاد,إعدادات الفيديو,تأثيرات رسومية,تأثيرات سطح المكتب,رسومات,زمن الوصول,vsync,تمزيق,مصغرة للنافذة",
"X-KDE-Keywords[bg]": "kwin,прозорец,мениджър,композиране,композитор,ефект,3D ефекти,2D ефекти,видео настройки,графични ефекти,десктоп ефекти,графика,закъснение,vsync,разкъсване,миниатюри на прозорци",
"X-KDE-Keywords[ca@valencia]": "kwin,finestra,gestor,composició,compositor,efecte,efectes 3D,efectes 2D,configuració de vídeo,efectes gràfics,efectes de l'escriptori,gràfics,latència,vsync,esquinçament,miniatures de pantalla",
"X-KDE-Keywords[ca]": "kwin,finestra,gestor,composició,compositor,efecte,efectes 3D,efectes 2D,configuració de vídeo,efectes gràfics,efectes d'escriptori,gràfics,latència,vsync,esquinçament,miniatures de pantalla",
"X-KDE-Keywords[de]": "KWin,Fenster,Verwaltung,Compositing,Compositor,Effekt,3D-Effekte,2D-Effekte,Videoeinstellungen,Grafische Effekte,Arbeitsflächen-Effekte,Grafik,Wartezeit,Latenz,V-Sync,Tearing,Fenster-Vorschaubilder",
"X-KDE-Keywords[en_GB]": "kwin,window,manager,compositing,compositor,effect,3D effects,2D effects,video settings,graphical effects,desktop effects,graphics,latency,vsync,tearing,window thumbnails",
"X-KDE-Keywords[es]": "kwin,ventana,gestor,composición,compositor,efecto,efectos 3D,efectos 2D,preferencias de vídeo,preferencias de video,ajustes de vídeo,ajustes de video,efectos gráficos,efectos de escritorio,efectos del escritorio,gráficos,latencia,vsync,tearing,desgarro,miniaturas de ventanas",
"X-KDE-Keywords[eu]": "kwin,leihoa,kudeatzailea,konposatzea,konposatzailea,efektua,3D efektuak,2D efektuak,bideo ezarpenak,efektu grafikoak,mahaigaineko efektuak,grafikoak,itxarote-denbora,latentzia,sinkronizazio bertikala,vsync,urradura,leihoen koadro txikiak",
"X-KDE-Keywords[fi]": "kwin,ikkuna,hallinta,ikkunaohjelma,koostaminen,koostin,koostaja,tehoste,3D-tehosteet,2D-tehosteet,videoasetukset,graafiset tehosteet,työpöytätehosteet,grafiikka,latenssi,vsync,pirstoutuminen,ikkunan pienoiskuvat",
"X-KDE-Keywords[fr]": "kwin, fenêtre, gestionnaire, composition, compositeur, effet, effets 3D, effets 2D, paramètres vidéo, effets graphiques, effets de bureau, graphique, latence, vsync, déchirement, vignettes de fenêtres",
"X-KDE-Keywords[gl]": "kwin,window,xanela,ventá,fiestra,manager,xestor,manexador,compositing,composición,compositor,effect,efecto,3D effects,efectos 3D,2D effects,efectos 2D,video settings,configuración de vídeo,graphical effects,efectos gráficos,desktop effects,efectos de escritorio,graphics,gráficos,latency,latencia,vsync,sincronización vertical,tearing,window thumbnails,miniaturas de xanelas",
"X-KDE-Keywords[he]": "kwin,חלון,מנהל,ניהול חלונאי,ניהול חלונאות,אפקט,אפקטים תלת־ממדיים,אפקטים דו־ממדיים,הגדרות וידאו,אפקטים גרפיים,אפקטים לשולחן העבודה,גרפיקה,השהיה,המתנה,שיהוי,סנכרון אנכי,חיתוך,קריעה,תמונות ממוזערות של חלוניות,תמוניות של חלונות",
"X-KDE-Keywords[hu]": "kwin,ablak,kezelő,kompozitálás,kompozitor,effektus,3D effektusok,2D effektusok,videobeállítások,grafikai effektusok,asztali effektusok,grafika,késleltetés,vsync,képtörés,ablakelőnézetek",
"X-KDE-Keywords[ia]": "kwin,window,manager,compositing,compositor,effect,3D effects,2D effects,video settings,graphical effects,desktop effects,graphics,latency,vsync,tearing,window thumbnails",
"X-KDE-Keywords[is]": "kwin,gluggi,stjóri,myndsmíði,myndsmiður,brella,3D brellur,2D brellur,myndstillingar,grafískar brellur,skjáborðsbrellur,grafík,biðtími,vsync,rifgalli,gluggasmámyndir",
"X-KDE-Keywords[it]": "kwin,finestra,gestore,composizione,compositore,effetto,effetti 3D,effetti 2D,impostazioni video,effetti grafici,effetti desktop,grafica,latenza,vsync,tearing,anteprime delle finestre",
"X-KDE-Keywords[ka]": "kwin,window,manager,compositing,compositor,effect,3D effects,2D effects,video settings,graphical effects,desktop effects,graphics,latency,vsync,tearing,window thumbnails,ფანჯარა,მართვა,კომპოზიტორი,ეფექტები,დაყოვნება",
"X-KDE-Keywords[ko]": "창,관리자,컴포지팅,컴포지터,효과,3D 효과,2D 효과,비디오 설정,그래픽 설정,그래픽 효과,데스크톱 효과,그래픽,주사율,티어링,창 섬네일",
"X-KDE-Keywords[lv]": "kwin,logs,pārvaldnieks,kompozicionēšana,kompozitors,efekts,3D efekti,2D efekti,video iestatījumi,grafiskie efekti,darbvirsmas efekti,grafika,aizture,vsync,vertikālā sinhronizācija,plēšana,pārraušana,logu sīktēli",
"X-KDE-Keywords[nb]": "kwin,vindu,vindusbehandler,sammensetting,sammensetter,effekt,3D-effekter,2D-effekter,videoinnstillinger,bilde effekter,skrivebordseffekter,bilde,latenstid,vsync,tearing,rifter,miniatyrbilder",
"X-KDE-Keywords[nl]": "kwin,venster,beheerder,samenstellen,samensteller,effect,3D-effecten,2D-effecten,video-instellingen,grafische effecten,bureaubladeffecten,grafische elementen,vertraging,vsync,schuintrekken,vensterminiaturen",
"X-KDE-Keywords[nn]": "kwin,vindauge,vindaugshandsamar,samansetjing,samansetjar,effekt,3D-effektar,2D-effektar,videoinnstillingar,grafiske effektar,skrivebordseffektar,grafikk,latenstid,vsync,tearing,rifter,miniatyrbilete",
"X-KDE-Keywords[pl]": "kwin,okno,menadżer,komponowanie,kompozytor,efekt,efekty 3D,efekty 2D,ustawienia obrazu,ustawienia grafiki,ustawienia pulpitu,grafika,opóźnienie,vsync,cięcie,miniatury okien",
"X-KDE-Keywords[pt_BR]": "kwin,janela,gerenciador,composição,compositor,efeito,efeitos 3D,efeitos 2D,configurações de vídeo,efeitos gráficos,efeitos de área de trabalho,gráficos,latência,sincronização vertical,rasgo,miniaturas de janelas",
"X-KDE-Keywords[ru]": "kwin,window,manager,compositing,compositor,effect,3D effects,2D effects,video settings,graphical effects,desktop effects,graphics,latency,vsync,tearing,window thumbnails,окно,диспетчер,графические эффекты,эффекты,композитинг,трёхмерные эффекты,двухмерные эффекты,параметры видео,настройка видео,графика,задержка,запаздывание,разрывы,миниатюры окон",
"X-KDE-Keywords[sa]": "kwin,विंडो,प्रबंधक,रचना,रचनाकार,प्रभाव,3D प्रभाव,2D प्रभाव,वीडियो सेटिंग्स,ग्राफिकल प्रभाव,डेस्कटॉप प्रभाव,ग्राफिक्स,विलंबता,vsync,फाड़ना,विंडो लघुचित्र",
"X-KDE-Keywords[sl]": "kwin,okno,upravljalnik,sestavljanje,sestavljalni,učinek,3D učinki,2D učinki,nastavitve videa,grafični učinki,namizni učinki,grafika,zakasnitev,vsync,trganje,sličice oken",
"X-KDE-Keywords[sv]": "kwin,fönster,hanterare,sammansättning,sammansätta,effekt,tredimensionella effekter,tvådimensionella effekter,videoinställningar,grafiska effekter,skrivbordseffekter,grafik,latens,vsync,rivning,fönsterminiatyrbilder",
"X-KDE-Keywords[tr]": "kwin,pencere,yönetici,bileşikleştirme,bileşikleştirici,efekt,3b efektler,3d efektler,2d efektler,2b efektler,video ayarları,grafik efektler,masaüstü efektleri,grafikler,gecikme,vsync,yırtılma,pencere küçük görselleri,pencere küçük görseli, pencere küçük resmi,pencere küçük resimleri,küçük görsel,küçük resim",
"X-KDE-Keywords[uk]": "kwin,window,manager,compositing,effect,3D effects,2D effects,video settings,graphical effects,desktop effects,graphics,latency,vsync,tearing,window thumbnails,вікно,керування,композитне,композиція,ефект,просторовий,ефекти,плоскі,параметри відео,графічні ефекти,ефекти стільниці,графіка,латентність,синхронізація,розрив,мініатюри",
"X-KDE-Keywords[x-test]": "xxkwinxx,xxwindowxx,xxmanagerxx,xxcompositingxx,xxcompositorxx,xxeffectxx,xx3D effectsxx,xx2D effectsxx,xxvideo settingsxx,xxgraphical effectsxx,xxdesktop effectsxx,xxgraphicsxx,xxlatencyxx,xxvsyncxx,xxtearingxx,xxwindow thumbnailsxx",
"X-KDE-Keywords[zh_CN]": "kwin,window,manager,compositing,compositor,effect,3D effects,2D effects,video settings,graphical effects,desktop effects,graphics,latency,vsync,tearing,window thumbnails,chuangkou,guanliqi,xianshitexiaohunheqi,hunheqi,goutu,huncheng,xiaoguo,texiao,shixiao,dongxiao,3D texiao,2D texiao,shipinshezhi,tuxingxiaoguo,tuxingtexiao,tuxingyanchi,yanchi,chuizhitongbu,silie,chuangkousuolvetu,窗口,管理器,显示特效混合器,混合器,构图,混成,效果,特效,视效,动效,3D 特效,2D 特效,视频设置,图形效果,图形特效,图形延迟,延迟,垂直同步,撕裂,窗口缩略图",
"X-KDE-Keywords[zh_TW]": "kwin,視窗,視窗管理員,合成,合成器,效果,3D 效果,2D 效果,顯示卡,圖形,圖形效果,桌面效果,延遲,撕裂,視窗縮圖,視窗預覽",
"X-KDE-OnlyShowOnQtPlatforms": [
"xcb"
],
"X-KDE-System-Settings-Parent-Category": "display",
"X-KDE-Weight": 60
}
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 name="kwinrc"/>
<group name="KDE">
<entry name="AnimationDurationFactor" type="Double">
<default>1.0</default>
</entry>
</group>
<group name="Compositing">
<entry name="HiddenPreviews" type="Enum">
<default>Shown</default>
<choices>
<choice name="Off" value="4"/>
<choice name="Shown" value="5"/>
<choice name="Always" value="6"/>
</choices>
</entry>
<entry name="Enabled" type="Bool">
<default>true</default>
</entry>
<entry name="LastFailureTimestamp" type="Int">
<default>0</default>
</entry>
<entry name="WindowsBlockCompositing" type="Bool">
<default>true</default>
</entry>
</group>
</kcfg>
@@ -0,0 +1,5 @@
File=kwincompositing_setting.kcfg
ClassName=KWinCompositingSetting
Mutators=true
DefaultValueGetters=true
ParentInConstructor=true
@@ -0,0 +1,34 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2020 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kwincompositingdata.h"
#include "kwincompositing_setting.h"
KWinCompositingData::KWinCompositingData(QObject *parent)
: KCModuleData(parent)
, m_settings(new KWinCompositingSetting(this))
{
}
bool KWinCompositingData::isDefaults() const
{
bool defaults = true;
const KConfigSkeletonItem::List itemList = m_settings->items();
for (const auto &item : itemList) {
if (item->key() != QStringLiteral("LastFailureTimestamp")) {
defaults &= item->isDefault();
}
}
return defaults;
}
#include "moc_kwincompositingdata.cpp"
@@ -0,0 +1,29 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2020 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QObject>
#include <KCModuleData>
class KWinCompositingSetting;
class KWinCompositingData : public KCModuleData
{
Q_OBJECT
public:
explicit KWinCompositingData(QObject *parent);
bool isDefaults() const override;
private:
KWinCompositingSetting *m_settings;
};
@@ -0,0 +1,199 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2013 Antonis Tsiapaliokas <kok3rs@gmail.com>
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "ui_compositing.h"
#include <kwin_compositing_interface.h>
#include <QAction>
#include <QApplication>
#include <QLayout>
#include <KCModule>
#include <KPluginFactory>
#include <KWindowSystem>
#include <algorithm>
#include <functional>
#include "kwincompositing_setting.h"
#include "kwincompositingdata.h"
static bool isRunningPlasma()
{
return qgetenv("XDG_CURRENT_DESKTOP") == "KDE";
}
class KWinCompositingKCM : public KCModule
{
Q_OBJECT
public:
explicit KWinCompositingKCM(QObject *parent, const KPluginMetaData &data);
public Q_SLOTS:
void load() override;
void save() override;
void defaults() override;
private Q_SLOTS:
void reenableGl();
private:
void init();
void updateUnmanagedItemStatus();
bool compositingRequired() const;
Ui_CompositingForm m_form;
OrgKdeKwinCompositingInterface *m_compositingInterface;
KWinCompositingSetting *m_settings;
};
static const QList<qreal> s_animationMultipliers = {8, 4, 2, 1, 0.5, 0.25, 0.125, 0};
bool KWinCompositingKCM::compositingRequired() const
{
return m_compositingInterface->platformRequiresCompositing();
}
KWinCompositingKCM::KWinCompositingKCM(QObject *parent, const KPluginMetaData &data)
: KCModule(parent, data)
, m_compositingInterface(new OrgKdeKwinCompositingInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Compositor"), QDBusConnection::sessionBus(), this))
, m_settings(new KWinCompositingSetting(this))
{
m_form.setupUi(widget());
// AnimationDurationFactor should be written to the same place as the lnf to avoid conflicts
m_settings->findItem("AnimationDurationFactor")->setWriteFlags(KConfigBase::Global | KConfigBase::Notify);
addConfig(m_settings, widget());
QAction *reenableGlAction = new QAction(i18n("Re-enable OpenGL detection"), this);
connect(reenableGlAction, &QAction::triggered, this, &KWinCompositingKCM::reenableGl);
connect(reenableGlAction, &QAction::triggered, m_form.glCrashedWarning, &KMessageWidget::animatedHide);
m_form.glCrashedWarning->addAction(reenableGlAction);
m_form.kcfg_Enabled->setVisible(!compositingRequired());
m_form.kcfg_WindowsBlockCompositing->setVisible(!compositingRequired());
m_form.compositingLabel->setVisible(!compositingRequired());
connect(this, &KWinCompositingKCM::defaultsIndicatorsVisibleChanged, this, &KWinCompositingKCM::updateUnmanagedItemStatus);
if (KWindowSystem::isPlatformWayland()) {
m_form.kcfg_HiddenPreviews->setVisible(false);
m_form.label_HiddenPreviews->setVisible(false);
}
init();
}
void KWinCompositingKCM::reenableGl()
{
m_settings->setLastFailureTimestamp(0);
m_settings->save();
}
void KWinCompositingKCM::init()
{
auto currentIndexChangedSignal = static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged);
// animation speed
m_form.animationDurationFactor->setMaximum(s_animationMultipliers.size() - 1);
connect(m_form.animationDurationFactor, &QSlider::valueChanged, this, [this]() {
updateUnmanagedItemStatus();
m_settings->setAnimationDurationFactor(s_animationMultipliers[m_form.animationDurationFactor->value()]);
});
if (isRunningPlasma()) {
m_form.animationSpeedLabel->hide();
m_form.animationSpeedControls->hide();
}
// windowThumbnail
connect(m_form.kcfg_HiddenPreviews, currentIndexChangedSignal, this, [this](int index) {
if (index == 2) {
m_form.windowThumbnailWarning->animatedShow();
} else {
m_form.windowThumbnailWarning->animatedHide();
}
});
if (m_settings->lastFailureTimestamp() > 0) {
m_form.glCrashedWarning->animatedShow();
}
}
void KWinCompositingKCM::updateUnmanagedItemStatus()
{
const auto animationDuration = s_animationMultipliers[m_form.animationDurationFactor->value()];
const bool inPlasma = isRunningPlasma();
bool changed = false;
if (!inPlasma) {
changed |= (animationDuration != m_settings->animationDurationFactor());
}
unmanagedWidgetChangeState(changed);
bool defaulted = true;
if (!inPlasma) {
defaulted &= animationDuration == m_settings->defaultAnimationDurationFactorValue();
}
unmanagedWidgetDefaultState(defaulted);
}
void KWinCompositingKCM::load()
{
KCModule::load();
// unmanaged items
m_settings->findItem("AnimationDurationFactor")->readConfig(m_settings->config());
const double multiplier = m_settings->animationDurationFactor();
auto const it = std::lower_bound(s_animationMultipliers.begin(), s_animationMultipliers.end(), multiplier, std::greater<qreal>());
const int index = static_cast<int>(std::distance(s_animationMultipliers.begin(), it));
m_form.animationDurationFactor->setValue(index);
m_form.animationDurationFactor->setDisabled(m_settings->isAnimationDurationFactorImmutable());
}
void KWinCompositingKCM::defaults()
{
KCModule::defaults();
// unmanaged widgets
if (!isRunningPlasma()) {
// corresponds to 1.0 seconds in s_animationMultipliers
m_form.animationDurationFactor->setValue(3);
}
}
void KWinCompositingKCM::save()
{
if (!isRunningPlasma()) {
const auto animationDuration = s_animationMultipliers[m_form.animationDurationFactor->value()];
m_settings->setAnimationDurationFactor(animationDuration);
}
m_settings->save();
KCModule::save();
// This clears up old entries that are now migrated to kdeglobals
KConfig("kwinrc", KConfig::NoGlobals).group(QStringLiteral("KDE")).revertToDefault("AnimationDurationFactor");
// Send signal to all kwin instances
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/Compositor"),
QStringLiteral("org.kde.kwin.Compositing"),
QStringLiteral("reinit"));
QDBusConnection::sessionBus().send(message);
}
K_PLUGIN_FACTORY_WITH_JSON(KWinCompositingConfigFactory, "kwincompositing.json",
registerPlugin<KWinCompositingKCM>();
registerPlugin<KWinCompositingData>();)
#include "main.moc"
@@ -0,0 +1,54 @@
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_kwindecoration\")
add_subdirectory(declarative-plugin)
set(kcmkwindecoration_SRCS
declarative-plugin/buttonsmodel.cpp
decorationmodel.cpp
kcm.cpp
utils.cpp
)
kcmutils_generate_module_data(
kcmkwindecoration_SRCS
MODULE_DATA_HEADER kwindecorationdata.h
MODULE_DATA_CLASS_NAME KWinDecorationData
SETTINGS_HEADERS kwindecorationsettings.h
SETTINGS_CLASSES KWinDecorationSettings
)
kconfig_add_kcfg_files(kcmkwindecoration_SRCS kwindecorationsettings.kcfgc GENERATE_MOC)
kcmutils_add_qml_kcm(kcm_kwindecoration SOURCES ${kcmkwindecoration_SRCS})
target_link_libraries(kcm_kwindecoration PRIVATE
KDecoration3::KDecoration
KF6::I18n
KF6::KCMUtils
KF6::KCMUtilsQuick
Qt::Quick
Qt::DBus
)
set(kwin-applywindowdecoration_SRCS
kwin-applywindowdecoration.cpp
decorationmodel.cpp
utils.cpp
)
kconfig_add_kcfg_files(kwin-applywindowdecoration_SRCS kwindecorationsettings.kcfgc GENERATE_MOC)
add_executable(kwin-applywindowdecoration ${kwin-applywindowdecoration_SRCS})
target_link_libraries(kwin-applywindowdecoration
KDecoration3::KDecoration
Qt::DBus
KF6::I18n
KF6::KCMUtils
)
configure_file(window-decorations.knsrc.cmake ${CMAKE_CURRENT_BINARY_DIR}/window-decorations.knsrc)
install(FILES kwindecorationsettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/window-decorations.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR})
install(TARGETS kwin-applywindowdecoration DESTINATION ${KDE_INSTALL_LIBEXECDIR})
@@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcm_kwindecoration.pot
@@ -0,0 +1,26 @@
ecm_add_qml_module(kdecorationprivatedeclarative URI org.kde.kwin.private.kdecoration DEPENDENCIES QtCore QtQuick GENERATE_PLUGIN_SOURCE)
target_sources(kdecorationprivatedeclarative PRIVATE
previewbutton.cpp
previewbridge.cpp
previewclient.cpp
previewitem.cpp
previewsettings.cpp
buttonsmodel.cpp
../../../decorations/decorationpalette.cpp
../../../decorations/decorations_logging.cpp
types.h
)
target_link_libraries(kdecorationprivatedeclarative PRIVATE
KDecoration3::KDecoration
KDecoration3::KDecoration3Private
Qt::DBus
Qt::Quick
KF6::CoreAddons
KF6::KCMUtils
KF6::I18n
KF6::Service
)
ecm_finalize_qml_module(kdecorationprivatedeclarative)
@@ -0,0 +1,189 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "buttonsmodel.h"
#include <KLocalizedString>
#include <QFontDatabase>
namespace KDecoration3
{
namespace Preview
{
ButtonsModel::ButtonsModel(const QList<DecorationButtonType> &buttons, QObject *parent)
: QAbstractListModel(parent)
, m_buttons(buttons)
{
}
ButtonsModel::ButtonsModel(QObject *parent)
: ButtonsModel(QList<DecorationButtonType>({
DecorationButtonType::Menu,
DecorationButtonType::ApplicationMenu,
DecorationButtonType::OnAllDesktops,
DecorationButtonType::Minimize,
DecorationButtonType::Maximize,
DecorationButtonType::Close,
DecorationButtonType::ContextHelp,
DecorationButtonType::Shade,
DecorationButtonType::KeepBelow,
DecorationButtonType::KeepAbove,
DecorationButtonType::Spacer,
}),
parent)
{
}
ButtonsModel::~ButtonsModel() = default;
int ButtonsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_buttons.count();
}
static QString buttonToName(DecorationButtonType type)
{
switch (type) {
case DecorationButtonType::Menu:
return i18n("More actions for this window");
case DecorationButtonType::ApplicationMenu:
return i18n("Application menu");
case DecorationButtonType::OnAllDesktops:
return i18n("On all desktops");
case DecorationButtonType::Minimize:
return i18n("Minimize");
case DecorationButtonType::Maximize:
return i18n("Maximize");
case DecorationButtonType::Close:
return i18n("Close");
case DecorationButtonType::ContextHelp:
return i18n("Context help");
case DecorationButtonType::Shade:
return i18n("Shade");
case DecorationButtonType::KeepBelow:
return i18n("Keep below other windows");
case DecorationButtonType::KeepAbove:
return i18n("Keep above other windows");
case DecorationButtonType::Spacer:
return i18n("Spacer");
default:
return QString();
}
}
QVariant ButtonsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_buttons.count() || index.column() != 0) {
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
return buttonToName(m_buttons.at(index.row()));
case Qt::UserRole:
return QVariant::fromValue(int(m_buttons.at(index.row())));
}
return QVariant();
}
QHash<int, QByteArray> ButtonsModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(Qt::DisplayRole, QByteArrayLiteral("display"));
roles.insert(Qt::UserRole, QByteArrayLiteral("button"));
return roles;
}
void ButtonsModel::remove(int row)
{
if (row < 0 || row >= m_buttons.count()) {
return;
}
beginRemoveRows(QModelIndex(), row, row);
m_buttons.removeAt(row);
endRemoveRows();
}
void ButtonsModel::down(int index)
{
if (m_buttons.count() < 2 || index == m_buttons.count() - 1) {
return;
}
beginMoveRows(QModelIndex(), index, index, QModelIndex(), index + 2);
m_buttons.insert(index + 1, m_buttons.takeAt(index));
endMoveRows();
}
void ButtonsModel::up(int index)
{
if (m_buttons.count() < 2 || index == 0) {
return;
}
beginMoveRows(QModelIndex(), index, index, QModelIndex(), index - 1);
m_buttons.insert(index - 1, m_buttons.takeAt(index));
endMoveRows();
}
void ButtonsModel::add(DecorationButtonType type)
{
beginInsertRows(QModelIndex(), m_buttons.count(), m_buttons.count());
m_buttons.append(type);
endInsertRows();
}
void ButtonsModel::add(int index, int type)
{
beginInsertRows(QModelIndex(), index, index);
m_buttons.insert(index, KDecoration3::DecorationButtonType(type));
endInsertRows();
}
void ButtonsModel::move(int sourceIndex, int targetIndex)
{
if (sourceIndex == std::max(0, targetIndex)) {
return;
}
/* When moving an item down, the destination index needs to be incremented
by one, as explained in the documentation:
https://doc.qt.io/qt-5/qabstractitemmodel.html#beginMoveRows */
if (targetIndex > sourceIndex) {
// Row will be moved down
beginMoveRows(QModelIndex(), sourceIndex, sourceIndex, QModelIndex(), targetIndex + 1);
} else {
beginMoveRows(QModelIndex(), sourceIndex, sourceIndex, QModelIndex(), std::max(0, targetIndex));
}
m_buttons.move(sourceIndex, std::max(0, targetIndex));
endMoveRows();
}
void ButtonsModel::clear()
{
beginResetModel();
m_buttons.clear();
endResetModel();
}
void ButtonsModel::replace(const QList<DecorationButtonType> &buttons)
{
if (buttons.isEmpty()) {
return;
}
beginResetModel();
m_buttons = buttons;
endResetModel();
}
}
}
#include "moc_buttonsmodel.cpp"
@@ -0,0 +1,52 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <KDecoration3/DecorationButton>
#include <QAbstractListModel>
#include <QQmlEngine>
namespace KDecoration3
{
namespace Preview
{
class PreviewBridge;
class ButtonsModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
public:
explicit ButtonsModel(const QList<DecorationButtonType> &buttons, QObject *parent = nullptr);
explicit ButtonsModel(QObject *parent = nullptr);
~ButtonsModel() override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
QList<DecorationButtonType> buttons() const
{
return m_buttons;
}
Q_INVOKABLE void clear();
Q_INVOKABLE void remove(int index);
Q_INVOKABLE void up(int index);
Q_INVOKABLE void down(int index);
Q_INVOKABLE void move(int sourceIndex, int targetIndex);
void replace(const QList<DecorationButtonType> &buttons);
void add(DecorationButtonType type);
Q_INVOKABLE void add(int index, int type);
private:
QList<DecorationButtonType> m_buttons;
};
}
}
@@ -0,0 +1,231 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "previewbridge.h"
#include "previewclient.h"
#include "previewitem.h"
#include "previewsettings.h"
#include <KDecoration3/DecoratedWindow>
#include <KDecoration3/Decoration>
#include <KCModule>
#include <KCMultiDialog>
#include <KPluginFactory>
#include <KPluginMetaData>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDebug>
#include <QDialog>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QQuickItem>
#include <QQuickRenderControl>
#include <QQuickWindow>
#include <QVBoxLayout>
#include <QWindow>
namespace KDecoration3
{
namespace Preview
{
static const QString s_pluginName = QStringLiteral("org.kde.kdecoration3");
static const QString s_kcmName = QStringLiteral("org.kde.kdecoration3.kcm");
PreviewBridge::PreviewBridge(QObject *parent)
: DecorationBridge(parent)
, m_lastCreatedClient(nullptr)
, m_lastCreatedSettings(nullptr)
, m_valid(false)
{
connect(this, &PreviewBridge::pluginChanged, this, &PreviewBridge::createFactory);
}
PreviewBridge::~PreviewBridge() = default;
std::unique_ptr<DecoratedWindowPrivate> PreviewBridge::createClient(DecoratedWindow *client, Decoration *decoration)
{
auto ptr = std::unique_ptr<PreviewClient>(new PreviewClient(client, decoration));
m_lastCreatedClient = ptr.get();
return ptr;
}
std::unique_ptr<DecorationSettingsPrivate> PreviewBridge::settings(DecorationSettings *parent)
{
auto ptr = std::unique_ptr<PreviewSettings>(new PreviewSettings(parent));
m_lastCreatedSettings = ptr.get();
return ptr;
}
void PreviewBridge::registerPreviewItem(PreviewItem *item)
{
m_previewItems.append(item);
}
void PreviewBridge::unregisterPreviewItem(PreviewItem *item)
{
m_previewItems.removeAll(item);
}
void PreviewBridge::setPlugin(const QString &plugin)
{
if (m_plugin == plugin) {
return;
}
m_plugin = plugin;
Q_EMIT pluginChanged();
}
QString PreviewBridge::theme() const
{
return m_theme;
}
void PreviewBridge::setTheme(const QString &theme)
{
if (m_theme == theme) {
return;
}
m_theme = theme;
Q_EMIT themeChanged();
}
QString PreviewBridge::kcmoduleName() const
{
return m_kcmoduleName;
}
void PreviewBridge::setKcmoduleName(const QString &kcmoduleName)
{
if (m_kcmoduleName == kcmoduleName) {
return;
}
m_kcmoduleName = kcmoduleName;
Q_EMIT themeChanged();
}
QString PreviewBridge::plugin() const
{
return m_plugin;
}
void PreviewBridge::createFactory()
{
m_factory.clear();
if (m_plugin.isNull()) {
setValid(false);
qWarning() << "Plugin not set";
return;
}
const auto offers = KPluginMetaData::findPlugins(s_pluginName);
auto item = std::find_if(offers.constBegin(), offers.constEnd(), [this](const auto &plugin) {
return plugin.pluginId() == m_plugin;
});
if (item != offers.constEnd()) {
m_factory = KPluginFactory::loadFactory(*item).plugin;
}
setValid(!m_factory.isNull());
}
bool PreviewBridge::isValid() const
{
return m_valid;
}
void PreviewBridge::setValid(bool valid)
{
if (m_valid == valid) {
return;
}
m_valid = valid;
Q_EMIT validChanged();
}
Decoration *PreviewBridge::createDecoration(QObject *parent)
{
if (!m_valid) {
return nullptr;
}
QVariantMap args({{QStringLiteral("bridge"), QVariant::fromValue(this)}});
if (!m_theme.isNull()) {
args.insert(QStringLiteral("theme"), m_theme);
}
return m_factory->create<KDecoration3::Decoration>(parent, QVariantList({args}));
}
DecorationButton *PreviewBridge::createButton(KDecoration3::Decoration *decoration, KDecoration3::DecorationButtonType type, QObject *parent)
{
if (!m_valid) {
return nullptr;
}
return m_factory->create<KDecoration3::DecorationButton>(parent, QVariantList({QVariant::fromValue(type), QVariant::fromValue(decoration)}));
}
void PreviewBridge::configure(QQuickItem *ctx)
{
if (!m_valid) {
qWarning() << "Cannot show an invalid decoration's configuration dialog";
return;
}
KCMultiDialog *dialog = new KCMultiDialog;
dialog->setAttribute(Qt::WA_DeleteOnClose);
if (m_lastCreatedClient) {
dialog->setWindowTitle(m_lastCreatedClient->caption());
}
QVariantMap args;
if (!m_theme.isNull()) {
args.insert(QStringLiteral("theme"), m_theme);
}
Q_ASSERT(!m_kcmoduleName.isEmpty());
dialog->addModule(KPluginMetaData(s_kcmName + QLatin1Char('/') + m_kcmoduleName), {args});
connect(dialog, &KCMultiDialog::configCommitted, this, [this] {
if (m_lastCreatedSettings) {
Q_EMIT m_lastCreatedSettings->decorationSettings()->reconfigured();
}
// Send signal to all kwin instances
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
QStringLiteral("org.kde.KWin"),
QStringLiteral("reloadConfig"));
QDBusConnection::sessionBus().send(message);
});
if (ctx->window()) {
dialog->winId(); // so it creates windowHandle
dialog->windowHandle()->setTransientParent(QQuickRenderControl::renderWindowFor(ctx->window()));
dialog->setModal(true);
}
dialog->show();
}
BridgeItem::BridgeItem(QObject *parent)
: QObject(parent)
, m_bridge(new PreviewBridge())
{
connect(m_bridge, &PreviewBridge::themeChanged, this, &BridgeItem::themeChanged);
connect(m_bridge, &PreviewBridge::pluginChanged, this, &BridgeItem::pluginChanged);
connect(m_bridge, &PreviewBridge::validChanged, this, &BridgeItem::validChanged);
connect(m_bridge, &PreviewBridge::kcmoduleNameChanged, this, &BridgeItem::kcmoduleNameChanged);
}
BridgeItem::~BridgeItem()
{
m_bridge->deleteLater();
}
}
}
#include "moc_previewbridge.cpp"
@@ -0,0 +1,149 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <KDecoration3/DecorationButton>
#include <KDecoration3/Private/DecorationBridge>
#include <QList>
#include <QPointer>
#include <QQmlEngine>
class QQuickItem;
class KPluginFactory;
namespace KDecoration3
{
namespace Preview
{
class PreviewClient;
class PreviewItem;
class PreviewSettings;
class PreviewBridge : public KDecoration3::DecorationBridge
{
Q_OBJECT
QML_ANONYMOUS
Q_PROPERTY(QString plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
Q_PROPERTY(QString kcmoduleName READ kcmoduleName WRITE setKcmoduleName NOTIFY kcmoduleNameChanged)
Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
public:
explicit PreviewBridge(QObject *parent = nullptr);
~PreviewBridge() override;
std::unique_ptr<DecoratedWindowPrivate> createClient(DecoratedWindow *client, Decoration *decoration) override;
std::unique_ptr<DecorationSettingsPrivate> settings(DecorationSettings *parent) override;
PreviewClient *lastCreatedClient()
{
return m_lastCreatedClient;
}
PreviewSettings *lastCreatedSettings()
{
return m_lastCreatedSettings;
}
void registerPreviewItem(PreviewItem *item);
void unregisterPreviewItem(PreviewItem *item);
void setPlugin(const QString &plugin);
QString plugin() const;
void setKcmoduleName(const QString &name);
QString kcmoduleName() const;
void setTheme(const QString &theme);
QString theme() const;
bool isValid() const;
KDecoration3::Decoration *createDecoration(QObject *parent = nullptr);
KDecoration3::DecorationButton *createButton(KDecoration3::Decoration *decoration, KDecoration3::DecorationButtonType type, QObject *parent = nullptr);
public Q_SLOTS:
void configure(QQuickItem *ctx);
Q_SIGNALS:
void pluginChanged();
void themeChanged();
void validChanged();
void kcmoduleNameChanged();
private:
void createFactory();
void setValid(bool valid);
PreviewClient *m_lastCreatedClient;
PreviewSettings *m_lastCreatedSettings;
QList<PreviewItem *> m_previewItems;
QString m_plugin;
QString m_theme;
QString m_kcmoduleName;
QPointer<KPluginFactory> m_factory;
bool m_valid;
};
class BridgeItem : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(Bridge)
Q_PROPERTY(QString plugin READ plugin WRITE setPlugin NOTIFY pluginChanged)
Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
Q_PROPERTY(QString kcmoduleName READ kcmoduleName WRITE setKcmoduleName NOTIFY kcmoduleNameChanged)
Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
Q_PROPERTY(KDecoration3::Preview::PreviewBridge *bridge READ bridge CONSTANT)
public:
explicit BridgeItem(QObject *parent = nullptr);
~BridgeItem() override;
void setPlugin(const QString &plugin)
{
m_bridge->setPlugin(plugin);
}
QString plugin() const
{
return m_bridge->plugin();
}
void setTheme(const QString &theme)
{
m_bridge->setTheme(theme);
}
QString kcmoduleName() const
{
return m_bridge->kcmoduleName();
}
void setKcmoduleName(const QString &name)
{
m_bridge->setKcmoduleName(name);
}
QString theme() const
{
return m_bridge->theme();
}
bool isValid() const
{
return m_bridge->isValid();
}
PreviewBridge *bridge() const
{
return m_bridge;
}
Q_SIGNALS:
void pluginChanged();
void themeChanged();
void kcmoduleNameChanged();
void validChanged();
private:
PreviewBridge *m_bridge;
};
}
}
Q_DECLARE_METATYPE(KDecoration3::Preview::PreviewBridge *)
@@ -0,0 +1,146 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "previewbutton.h"
#include "previewbridge.h"
#include "previewclient.h"
#include "previewsettings.h"
#include <KDecoration3/Decoration>
#include <QPainter>
namespace KDecoration3
{
namespace Preview
{
PreviewButtonItem::PreviewButtonItem(QQuickItem *parent)
: QQuickPaintedItem(parent)
{
}
PreviewButtonItem::~PreviewButtonItem() = default;
void PreviewButtonItem::setType(int type)
{
setType(KDecoration3::DecorationButtonType(type));
}
void PreviewButtonItem::setType(KDecoration3::DecorationButtonType type)
{
if (m_type == type) {
return;
}
m_type = type;
Q_EMIT typeChanged();
}
KDecoration3::DecorationButtonType PreviewButtonItem::type() const
{
return m_type;
}
PreviewBridge *PreviewButtonItem::bridge() const
{
return m_bridge.data();
}
void PreviewButtonItem::setBridge(PreviewBridge *bridge)
{
if (m_bridge == bridge) {
return;
}
m_bridge = bridge;
Q_EMIT bridgeChanged();
}
Settings *PreviewButtonItem::settings() const
{
return m_settings.data();
}
void PreviewButtonItem::setSettings(Settings *settings)
{
if (m_settings == settings) {
return;
}
m_settings = settings;
Q_EMIT settingsChanged();
}
int PreviewButtonItem::typeAsInt() const
{
return int(m_type);
}
void PreviewButtonItem::componentComplete()
{
QQuickPaintedItem::componentComplete();
createButton();
}
void PreviewButtonItem::createButton()
{
if (m_type == KDecoration3::DecorationButtonType::Custom || m_decoration || !m_settings || !m_bridge) {
return;
}
m_decoration = m_bridge->createDecoration(this);
if (!m_decoration) {
return;
}
auto client = m_bridge->lastCreatedClient();
client->setMinimizable(true);
client->setMaximizable(true);
client->setActive(false);
client->setProvidesContextHelp(true);
m_decoration->setSettings(m_settings->settings());
m_decoration->create();
m_decoration->init();
m_decoration->apply(m_decoration->nextState()->clone());
m_button = m_bridge->createButton(m_decoration, m_type);
connect(this, &PreviewButtonItem::widthChanged, this, &PreviewButtonItem::syncGeometry);
connect(this, &PreviewButtonItem::heightChanged, this, &PreviewButtonItem::syncGeometry);
syncGeometry();
}
void PreviewButtonItem::syncGeometry()
{
if (!m_button) {
return;
}
m_button->setGeometry(QRect(0, 0, width(), height()));
}
void PreviewButtonItem::paint(QPainter *painter)
{
if (!m_button) {
return;
}
const QRect rect(0, 0, width(), height());
if (type() == KDecoration3::DecorationButtonType::Spacer) {
static const QIcon icon = QIcon::fromTheme(QStringLiteral("distribute-horizontal"));
icon.paint(painter, rect);
} else {
m_button->paint(painter, rect);
}
painter->setCompositionMode(QPainter::CompositionMode_SourceAtop);
painter->fillRect(rect, m_color);
}
void PreviewButtonItem::setColor(const QColor &color)
{
m_color = color;
m_color.setAlpha(127);
update();
}
}
}
#include "moc_previewbutton.cpp"
@@ -0,0 +1,73 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <KDecoration3/DecorationButton>
#include <QColor>
#include <QPointer>
#include <QQuickPaintedItem>
namespace KDecoration3
{
class Decoration;
namespace Preview
{
class PreviewBridge;
class Settings;
class PreviewButtonItem : public QQuickPaintedItem
{
Q_OBJECT
QML_NAMED_ELEMENT(Button)
Q_PROPERTY(KDecoration3::Preview::PreviewBridge *bridge READ bridge WRITE setBridge NOTIFY bridgeChanged)
Q_PROPERTY(KDecoration3::Preview::Settings *settings READ settings WRITE setSettings NOTIFY settingsChanged)
Q_PROPERTY(int type READ typeAsInt WRITE setType NOTIFY typeChanged)
Q_PROPERTY(QColor color READ color WRITE setColor)
public:
explicit PreviewButtonItem(QQuickItem *parent = nullptr);
~PreviewButtonItem() override;
void paint(QPainter *painter) override;
PreviewBridge *bridge() const;
void setBridge(PreviewBridge *bridge);
Settings *settings() const;
void setSettings(Settings *settings);
KDecoration3::DecorationButtonType type() const;
int typeAsInt() const;
void setType(KDecoration3::DecorationButtonType type);
void setType(int type);
const QColor &color() const
{
return m_color;
}
void setColor(const QColor &color);
Q_SIGNALS:
void bridgeChanged();
void typeChanged();
void settingsChanged();
protected:
void componentComplete() override;
private:
void createButton();
void syncGeometry();
QColor m_color;
QPointer<KDecoration3::Preview::PreviewBridge> m_bridge;
QPointer<KDecoration3::Preview::Settings> m_settings;
KDecoration3::Decoration *m_decoration = nullptr;
KDecoration3::DecorationButton *m_button = nullptr;
KDecoration3::DecorationButtonType m_type = KDecoration3::DecorationButtonType::Custom;
};
} // Preview
} // KDecoration3
@@ -0,0 +1,441 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "previewclient.h"
#include <KDecoration3/DecoratedWindow>
#include <KDecoration3/Decoration>
#include <QCoreApplication>
#include <QDebug>
#include <QEvent>
#include <QModelIndex>
namespace KDecoration3
{
namespace Preview
{
PreviewClient::PreviewClient(DecoratedWindow *c, Decoration *decoration)
: QObject(decoration)
, DecoratedWindowPrivateV2(c, decoration)
, m_icon(QIcon::fromTheme(QStringLiteral("start-here-kde")))
, m_iconName(m_icon.name())
, m_palette(QStringLiteral("kdeglobals"))
, m_active(true)
, m_closeable(true)
, m_keepBelow(false)
, m_keepAbove(false)
, m_maximizable(true)
, m_maximizedHorizontally(false)
, m_maximizedVertically(false)
, m_minimizable(true)
, m_modal(false)
, m_movable(true)
, m_resizable(true)
, m_shadeable(true)
, m_shaded(false)
, m_providesContextHelp(false)
, m_onAllDesktops(false)
, m_width(0)
, m_height(0)
, m_bordersTopEdge(false)
, m_bordersLeftEdge(false)
, m_bordersRightEdge(false)
, m_bordersBottomEdge(false)
{
connect(this, &PreviewClient::captionChanged, c, &DecoratedWindow::captionChanged);
connect(this, &PreviewClient::activeChanged, c, &DecoratedWindow::activeChanged);
connect(this, &PreviewClient::closeableChanged, c, &DecoratedWindow::closeableChanged);
connect(this, &PreviewClient::keepAboveChanged, c, &DecoratedWindow::keepAboveChanged);
connect(this, &PreviewClient::keepBelowChanged, c, &DecoratedWindow::keepBelowChanged);
connect(this, &PreviewClient::maximizableChanged, c, &DecoratedWindow::maximizeableChanged);
connect(this, &PreviewClient::maximizedChanged, c, &DecoratedWindow::maximizedChanged);
connect(this, &PreviewClient::maximizedVerticallyChanged, c, &DecoratedWindow::maximizedVerticallyChanged);
connect(this, &PreviewClient::maximizedHorizontallyChanged, c, &DecoratedWindow::maximizedHorizontallyChanged);
connect(this, &PreviewClient::minimizableChanged, c, &DecoratedWindow::minimizeableChanged);
connect(this, &PreviewClient::movableChanged, c, &DecoratedWindow::moveableChanged);
connect(this, &PreviewClient::onAllDesktopsChanged, c, &DecoratedWindow::onAllDesktopsChanged);
connect(this, &PreviewClient::resizableChanged, c, &DecoratedWindow::resizeableChanged);
connect(this, &PreviewClient::shadeableChanged, c, &DecoratedWindow::shadeableChanged);
connect(this, &PreviewClient::shadedChanged, c, &DecoratedWindow::shadedChanged);
connect(this, &PreviewClient::providesContextHelpChanged, c, &DecoratedWindow::providesContextHelpChanged);
connect(this, &PreviewClient::widthChanged, c, &DecoratedWindow::widthChanged);
connect(this, &PreviewClient::heightChanged, c, &DecoratedWindow::heightChanged);
connect(this, &PreviewClient::iconChanged, c, &DecoratedWindow::iconChanged);
connect(this, &PreviewClient::paletteChanged, c, &DecoratedWindow::paletteChanged);
connect(this, &PreviewClient::maximizedVerticallyChanged, this, [this]() {
Q_EMIT maximizedChanged(isMaximized());
});
connect(this, &PreviewClient::maximizedHorizontallyChanged, this, [this]() {
Q_EMIT maximizedChanged(isMaximized());
});
connect(this, &PreviewClient::iconNameChanged, this, [this]() {
m_icon = QIcon::fromTheme(m_iconName);
Q_EMIT iconChanged(m_icon);
});
connect(&m_palette, &KWin::Decoration::DecorationPalette::changed, this, [this]() {
Q_EMIT paletteChanged(m_palette.palette());
});
auto emitEdgesChanged = [this, c]() {
Q_EMIT c->adjacentScreenEdgesChanged(adjacentScreenEdges());
};
connect(this, &PreviewClient::bordersTopEdgeChanged, this, emitEdgesChanged);
connect(this, &PreviewClient::bordersLeftEdgeChanged, this, emitEdgesChanged);
connect(this, &PreviewClient::bordersRightEdgeChanged, this, emitEdgesChanged);
connect(this, &PreviewClient::bordersBottomEdgeChanged, this, emitEdgesChanged);
auto emitSizeChanged = [c]() {
Q_EMIT c->sizeChanged(c->size());
};
connect(this, &PreviewClient::widthChanged, this, emitSizeChanged);
connect(this, &PreviewClient::heightChanged, this, emitSizeChanged);
qApp->installEventFilter(this);
}
PreviewClient::~PreviewClient() = default;
void PreviewClient::setIcon(const QIcon &pixmap)
{
m_icon = pixmap;
Q_EMIT iconChanged(m_icon);
}
qreal PreviewClient::width() const
{
return m_width;
}
qreal PreviewClient::height() const
{
return m_height;
}
QSizeF PreviewClient::size() const
{
return QSize(m_width, m_height);
}
QString PreviewClient::caption() const
{
return m_caption;
}
QIcon PreviewClient::icon() const
{
return m_icon;
}
QString PreviewClient::iconName() const
{
return m_iconName;
}
bool PreviewClient::isActive() const
{
return m_active;
}
bool PreviewClient::isCloseable() const
{
return m_closeable;
}
bool PreviewClient::isKeepAbove() const
{
return m_keepAbove;
}
bool PreviewClient::isKeepBelow() const
{
return m_keepBelow;
}
bool PreviewClient::isMaximizeable() const
{
return m_maximizable;
}
bool PreviewClient::isMaximized() const
{
return isMaximizedHorizontally() && isMaximizedVertically();
}
bool PreviewClient::isMaximizedHorizontally() const
{
return m_maximizedHorizontally;
}
bool PreviewClient::isMaximizedVertically() const
{
return m_maximizedVertically;
}
bool PreviewClient::isMinimizeable() const
{
return m_minimizable;
}
bool PreviewClient::isModal() const
{
return m_modal;
}
bool PreviewClient::isMoveable() const
{
return m_movable;
}
bool PreviewClient::isOnAllDesktops() const
{
return m_onAllDesktops;
}
bool PreviewClient::isResizeable() const
{
return m_resizable;
}
bool PreviewClient::isShadeable() const
{
return m_shadeable;
}
bool PreviewClient::isShaded() const
{
return m_shaded;
}
bool PreviewClient::providesContextHelp() const
{
return m_providesContextHelp;
}
QPalette PreviewClient::palette() const
{
return m_palette.palette();
}
QColor PreviewClient::color(ColorGroup group, ColorRole role) const
{
return m_palette.color(group, role);
}
Qt::Edges PreviewClient::adjacentScreenEdges() const
{
Qt::Edges edges;
if (m_bordersBottomEdge) {
edges |= Qt::BottomEdge;
}
if (m_bordersLeftEdge) {
edges |= Qt::LeftEdge;
}
if (m_bordersRightEdge) {
edges |= Qt::RightEdge;
}
if (m_bordersTopEdge) {
edges |= Qt::TopEdge;
}
return edges;
}
QString PreviewClient::windowClass() const
{
return QString();
}
qreal PreviewClient::scale() const
{
return 1;
}
qreal PreviewClient::nextScale() const
{
return 1;
}
QString PreviewClient::applicationMenuServiceName() const
{
return QString();
}
QString PreviewClient::applicationMenuObjectPath() const
{
return QString();
}
bool PreviewClient::hasApplicationMenu() const
{
return true;
}
bool PreviewClient::isApplicationMenuActive() const
{
return false;
}
bool PreviewClient::bordersBottomEdge() const
{
return m_bordersBottomEdge;
}
bool PreviewClient::bordersLeftEdge() const
{
return m_bordersLeftEdge;
}
bool PreviewClient::bordersRightEdge() const
{
return m_bordersRightEdge;
}
bool PreviewClient::bordersTopEdge() const
{
return m_bordersTopEdge;
}
void PreviewClient::setBordersBottomEdge(bool enabled)
{
if (m_bordersBottomEdge == enabled) {
return;
}
m_bordersBottomEdge = enabled;
Q_EMIT bordersBottomEdgeChanged(enabled);
}
void PreviewClient::setBordersLeftEdge(bool enabled)
{
if (m_bordersLeftEdge == enabled) {
return;
}
m_bordersLeftEdge = enabled;
Q_EMIT bordersLeftEdgeChanged(enabled);
}
void PreviewClient::setBordersRightEdge(bool enabled)
{
if (m_bordersRightEdge == enabled) {
return;
}
m_bordersRightEdge = enabled;
Q_EMIT bordersRightEdgeChanged(enabled);
}
void PreviewClient::setBordersTopEdge(bool enabled)
{
if (m_bordersTopEdge == enabled) {
return;
}
m_bordersTopEdge = enabled;
Q_EMIT bordersTopEdgeChanged(enabled);
}
void PreviewClient::requestShowToolTip(const QString &text)
{
}
void PreviewClient::requestHideToolTip()
{
}
void PreviewClient::requestClose()
{
Q_EMIT closeRequested();
}
void PreviewClient::requestContextHelp()
{
}
void PreviewClient::requestToggleMaximization(Qt::MouseButtons buttons)
{
if (buttons.testFlag(Qt::LeftButton)) {
const bool set = !isMaximized();
setMaximizedHorizontally(set);
setMaximizedVertically(set);
} else if (buttons.testFlag(Qt::RightButton)) {
setMaximizedHorizontally(!isMaximizedHorizontally());
} else if (buttons.testFlag(Qt::MiddleButton)) {
setMaximizedVertically(!isMaximizedVertically());
}
}
void PreviewClient::requestMinimize()
{
Q_EMIT minimizeRequested();
}
void PreviewClient::requestToggleKeepAbove()
{
setKeepAbove(!isKeepAbove());
}
void PreviewClient::requestToggleKeepBelow()
{
setKeepBelow(!isKeepBelow());
}
void PreviewClient::requestShowWindowMenu(const QRect &rect)
{
Q_EMIT showWindowMenuRequested();
}
void PreviewClient::requestShowApplicationMenu(const QRect &rect, int actionId)
{
}
void PreviewClient::showApplicationMenu(int actionId)
{
}
void PreviewClient::requestToggleOnAllDesktops()
{
m_onAllDesktops = !m_onAllDesktops;
Q_EMIT onAllDesktopsChanged(m_onAllDesktops);
}
void PreviewClient::requestToggleShade()
{
setShaded(!isShaded());
}
#define SETTER(type, name, variable) \
void PreviewClient::name(type variable) \
{ \
if (m_##variable == variable) { \
return; \
} \
m_##variable = variable; \
Q_EMIT variable##Changed(m_##variable); \
}
#define SETTER2(name, variable) SETTER(bool, name, variable)
SETTER(const QString &, setCaption, caption)
SETTER(const QString &, setIconName, iconName)
SETTER(int, setWidth, width)
SETTER(int, setHeight, height)
SETTER2(setActive, active)
SETTER2(setCloseable, closeable)
SETTER2(setMaximizable, maximizable)
SETTER2(setKeepBelow, keepBelow)
SETTER2(setKeepAbove, keepAbove)
SETTER2(setMaximizedHorizontally, maximizedHorizontally)
SETTER2(setMaximizedVertically, maximizedVertically)
SETTER2(setMinimizable, minimizable)
SETTER2(setModal, modal)
SETTER2(setMovable, movable)
SETTER2(setResizable, resizable)
SETTER2(setShadeable, shadeable)
SETTER2(setShaded, shaded)
SETTER2(setProvidesContextHelp, providesContextHelp)
#undef SETTER2
#undef SETTER
} // namespace Preview
} // namespace KDecoration3
#include "moc_previewclient.cpp"
@@ -0,0 +1,199 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include "../../../decorations/decorationpalette.h"
#include <KDecoration3/Private/DecoratedWindowPrivate>
#include <QObject>
#include <QPalette>
#include <QQmlEngine>
class QAbstractItemModel;
namespace KDecoration3
{
namespace Preview
{
class PreviewClient : public QObject, public DecoratedWindowPrivateV2
{
Q_OBJECT
QML_ANONYMOUS
Q_PROPERTY(KDecoration3::Decoration *decoration READ decoration CONSTANT)
Q_PROPERTY(QString caption READ caption WRITE setCaption NOTIFY captionChanged)
Q_PROPERTY(QIcon icon READ icon WRITE setIcon NOTIFY iconChanged)
Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged)
Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
Q_PROPERTY(bool closeable READ isCloseable WRITE setCloseable NOTIFY closeableChanged)
Q_PROPERTY(bool keepAbove READ isKeepAbove WRITE setKeepAbove NOTIFY keepAboveChanged)
Q_PROPERTY(bool keepBelow READ isKeepBelow WRITE setKeepBelow NOTIFY keepBelowChanged)
Q_PROPERTY(bool maximizable READ isMaximizeable WRITE setMaximizable NOTIFY maximizableChanged)
Q_PROPERTY(bool maximized READ isMaximized NOTIFY maximizedChanged)
Q_PROPERTY(bool maximizedVertically READ isMaximizedVertically WRITE setMaximizedVertically NOTIFY maximizedVerticallyChanged)
Q_PROPERTY(bool maximizedHorizontally READ isMaximizedHorizontally WRITE setMaximizedHorizontally NOTIFY maximizedHorizontallyChanged)
Q_PROPERTY(bool minimizable READ isMinimizeable WRITE setMinimizable NOTIFY minimizableChanged)
Q_PROPERTY(bool modal READ isModal WRITE setModal NOTIFY modalChanged)
Q_PROPERTY(bool movable READ isMoveable WRITE setMovable NOTIFY movableChanged)
Q_PROPERTY(bool onAllDesktops READ isOnAllDesktops NOTIFY onAllDesktopsChanged)
Q_PROPERTY(bool resizable READ isResizeable WRITE setResizable NOTIFY resizableChanged)
Q_PROPERTY(bool shadeable READ isShadeable WRITE setShadeable NOTIFY shadeableChanged)
Q_PROPERTY(bool shaded READ isShaded WRITE setShaded NOTIFY shadedChanged)
Q_PROPERTY(bool providesContextHelp READ providesContextHelp WRITE setProvidesContextHelp NOTIFY providesContextHelpChanged)
Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
Q_PROPERTY(bool bordersTopEdge READ bordersTopEdge WRITE setBordersTopEdge NOTIFY bordersTopEdgeChanged)
Q_PROPERTY(bool bordersLeftEdge READ bordersLeftEdge WRITE setBordersLeftEdge NOTIFY bordersLeftEdgeChanged)
Q_PROPERTY(bool bordersRightEdge READ bordersRightEdge WRITE setBordersRightEdge NOTIFY bordersRightEdgeChanged)
Q_PROPERTY(bool bordersBottomEdge READ bordersBottomEdge WRITE setBordersBottomEdge NOTIFY bordersBottomEdgeChanged)
public:
explicit PreviewClient(DecoratedWindow *client, Decoration *decoration);
~PreviewClient() override;
QString caption() const override;
QIcon icon() const override;
bool isActive() const override;
bool isCloseable() const override;
bool isKeepAbove() const override;
bool isKeepBelow() const override;
bool isMaximizeable() const override;
bool isMaximized() const override;
bool isMaximizedVertically() const override;
bool isMaximizedHorizontally() const override;
bool isMinimizeable() const override;
bool isModal() const override;
bool isMoveable() const override;
bool isOnAllDesktops() const override;
bool isResizeable() const override;
bool isShadeable() const override;
bool isShaded() const override;
bool providesContextHelp() const override;
qreal width() const override;
qreal height() const override;
QSizeF size() const override;
QPalette palette() const override;
QColor color(ColorGroup group, ColorRole role) const override;
Qt::Edges adjacentScreenEdges() const override;
QString windowClass() const override;
qreal scale() const override;
qreal nextScale() const override;
QString applicationMenuServiceName() const override;
QString applicationMenuObjectPath() const override;
bool hasApplicationMenu() const override;
bool isApplicationMenuActive() const override;
void requestShowToolTip(const QString &text) override;
void requestHideToolTip() override;
void requestClose() override;
void requestContextHelp() override;
void requestToggleMaximization(Qt::MouseButtons buttons) override;
void requestMinimize() override;
void requestToggleKeepAbove() override;
void requestToggleKeepBelow() override;
void requestToggleShade() override;
void requestShowWindowMenu(const QRect &rect) override;
void requestShowApplicationMenu(const QRect &rect, int actionId) override;
void requestToggleOnAllDesktops() override;
void showApplicationMenu(int actionId) override;
void setCaption(const QString &caption);
void setActive(bool active);
void setCloseable(bool closeable);
void setMaximizable(bool maximizable);
void setKeepBelow(bool keepBelow);
void setKeepAbove(bool keepAbove);
void setMaximizedHorizontally(bool maximized);
void setMaximizedVertically(bool maximized);
void setMinimizable(bool minimizable);
void setModal(bool modal);
void setMovable(bool movable);
void setResizable(bool resizable);
void setShadeable(bool shadeable);
void setShaded(bool shaded);
void setProvidesContextHelp(bool contextHelp);
void setWidth(int width);
void setHeight(int height);
QString iconName() const;
void setIconName(const QString &icon);
void setIcon(const QIcon &icon);
bool bordersTopEdge() const;
bool bordersLeftEdge() const;
bool bordersRightEdge() const;
bool bordersBottomEdge() const;
void setBordersTopEdge(bool enabled);
void setBordersLeftEdge(bool enabled);
void setBordersRightEdge(bool enabled);
void setBordersBottomEdge(bool enabled);
Q_SIGNALS:
void captionChanged(const QString &);
void iconChanged(const QIcon &);
void iconNameChanged(const QString &);
void activeChanged(bool);
void closeableChanged(bool);
void keepAboveChanged(bool);
void keepBelowChanged(bool);
void maximizableChanged(bool);
void maximizedChanged(bool);
void maximizedVerticallyChanged(bool);
void maximizedHorizontallyChanged(bool);
void minimizableChanged(bool);
void modalChanged(bool);
void movableChanged(bool);
void onAllDesktopsChanged(bool);
void resizableChanged(bool);
void shadeableChanged(bool);
void shadedChanged(bool);
void providesContextHelpChanged(bool);
void widthChanged(int);
void heightChanged(int);
void paletteChanged(const QPalette &);
void bordersTopEdgeChanged(bool);
void bordersLeftEdgeChanged(bool);
void bordersRightEdgeChanged(bool);
void bordersBottomEdgeChanged(bool);
void showWindowMenuRequested();
void showApplicationMenuRequested();
void minimizeRequested();
void closeRequested();
private:
QString m_caption;
QIcon m_icon;
QString m_iconName;
KWin::Decoration::DecorationPalette m_palette;
bool m_active;
bool m_closeable;
bool m_keepBelow;
bool m_keepAbove;
bool m_maximizable;
bool m_maximizedHorizontally;
bool m_maximizedVertically;
bool m_minimizable;
bool m_modal;
bool m_movable;
bool m_resizable;
bool m_shadeable;
bool m_shaded;
bool m_providesContextHelp;
bool m_onAllDesktops;
int m_width;
int m_height;
bool m_bordersTopEdge;
bool m_bordersLeftEdge;
bool m_bordersRightEdge;
bool m_bordersBottomEdge;
};
} // namespace Preview
} // namespace KDecoration3
@@ -0,0 +1,426 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "previewitem.h"
#include "previewbridge.h"
#include "previewclient.h"
#include "previewsettings.h"
#include <KDecoration3/DecoratedWindow>
#include <KDecoration3/Decoration>
#include <KDecoration3/DecorationSettings>
#include <KDecoration3/DecorationShadow>
#include <QCoreApplication>
#include <QCursor>
#include <QPainter>
#include <QQmlContext>
#include <QQmlEngine>
#include <cmath>
#include <QDebug>
namespace KDecoration3
{
namespace Preview
{
PreviewItem::PreviewItem(QQuickItem *parent)
: QQuickPaintedItem(parent)
, m_decoration(nullptr)
, m_windowColor(QPalette().window().color())
{
setAcceptHoverEvents(true);
setAcceptedMouseButtons(Qt::AllButtons);
connect(this, &PreviewItem::widthChanged, this, &PreviewItem::syncSize);
connect(this, &PreviewItem::heightChanged, this, &PreviewItem::syncSize);
connect(this, &PreviewItem::bridgeChanged, this, &PreviewItem::createDecoration);
connect(this, &PreviewItem::settingsChanged, this, &PreviewItem::createDecoration);
}
PreviewItem::~PreviewItem()
{
if (m_decoration) {
m_decoration->deleteLater();
}
if (m_bridge) {
m_bridge->unregisterPreviewItem(this);
}
}
void PreviewItem::componentComplete()
{
QQuickPaintedItem::componentComplete();
createDecoration();
if (m_decoration) {
m_decoration->setSettings(m_settings->settings());
m_decoration->create();
m_decoration->init();
m_decoration->apply(m_decoration->nextState()->clone());
syncSize();
}
}
void PreviewItem::createDecoration()
{
if (m_bridge.isNull() || m_settings.isNull() || m_decoration) {
return;
}
Decoration *decoration = m_bridge->createDecoration(nullptr);
m_client = m_bridge->lastCreatedClient();
setDecoration(decoration);
}
Decoration *PreviewItem::decoration() const
{
return m_decoration;
}
void PreviewItem::setDecoration(Decoration *deco)
{
if (!deco || m_decoration == deco) {
return;
}
m_decoration = deco;
m_decoration->setProperty("visualParent", QVariant::fromValue(this));
connect(m_decoration, &Decoration::bordersChanged, this, &PreviewItem::syncSize);
connect(m_decoration, &Decoration::shadowChanged, this, &PreviewItem::syncSize);
connect(m_decoration, &Decoration::shadowChanged, this, &PreviewItem::shadowChanged);
connect(m_decoration, &Decoration::damaged, this, [this]() {
update();
});
Q_EMIT decorationChanged(m_decoration);
}
QColor PreviewItem::windowColor() const
{
return m_windowColor;
}
void PreviewItem::setWindowColor(const QColor &color)
{
if (m_windowColor == color) {
return;
}
m_windowColor = color;
Q_EMIT windowColorChanged(m_windowColor);
update();
}
void PreviewItem::paint(QPainter *painter)
{
if (!m_decoration) {
return;
}
int paddingLeft = 0;
int paddingTop = 0;
int paddingRight = 0;
int paddingBottom = 0;
paintShadow(painter, paddingLeft, paddingRight, paddingTop, paddingBottom);
m_decoration->paint(painter, QRect(0, 0, width(), height()));
if (m_drawBackground) {
painter->fillRect(m_decoration->borderLeft(), m_decoration->borderTop(),
width() - m_decoration->borderLeft() - m_decoration->borderRight() - paddingLeft - paddingRight,
height() - m_decoration->borderTop() - m_decoration->borderBottom() - paddingTop - paddingBottom,
m_windowColor);
}
}
void PreviewItem::paintShadow(QPainter *painter, int &paddingLeft, int &paddingRight, int &paddingTop, int &paddingBottom)
{
const auto &shadow = m_decoration->shadow();
if (!shadow) {
return;
}
paddingLeft = shadow->paddingLeft();
paddingTop = shadow->paddingTop();
paddingRight = shadow->paddingRight();
paddingBottom = shadow->paddingBottom();
const QImage shadowPixmap = shadow->shadow();
if (shadowPixmap.isNull()) {
return;
}
const QRect outerRect(-paddingLeft, -paddingTop, width(), height());
const QRect shadowRect(shadowPixmap.rect());
const QSizeF topLeftSize(shadow->topLeftGeometry().size());
QRectF topLeftTarget(
QPointF(outerRect.x(), outerRect.y()),
topLeftSize);
const QSizeF topRightSize(shadow->topRightGeometry().size());
QRectF topRightTarget(
QPointF(outerRect.x() + outerRect.width() - topRightSize.width(),
outerRect.y()),
topRightSize);
const QSizeF bottomRightSize(shadow->bottomRightGeometry().size());
QRectF bottomRightTarget(
QPointF(outerRect.x() + outerRect.width() - bottomRightSize.width(),
outerRect.y() + outerRect.height() - bottomRightSize.height()),
bottomRightSize);
const QSizeF bottomLeftSize(shadow->bottomLeftGeometry().size());
QRectF bottomLeftTarget(
QPointF(outerRect.x(),
outerRect.y() + outerRect.height() - bottomLeftSize.height()),
bottomLeftSize);
// Re-distribute the corner tiles so no one of them is overlapping with others.
// By doing this, we assume that shadow's corner tiles are symmetric
// and it is OK to not draw top/right/bottom/left tile between corners.
// For example, let's say top-left and top-right tiles are overlapping.
// In that case, the right side of the top-left tile will be shifted to left,
// the left side of the top-right tile will shifted to right, and the top
// tile won't be rendered.
bool drawTop = true;
if (topLeftTarget.x() + topLeftTarget.width() >= topRightTarget.x()) {
const float halfOverlap = std::abs(topLeftTarget.x() + topLeftTarget.width() - topRightTarget.x()) / 2.0f;
topLeftTarget.setRight(topLeftTarget.right() - std::floor(halfOverlap));
topRightTarget.setLeft(topRightTarget.left() + std::ceil(halfOverlap));
drawTop = false;
}
bool drawRight = true;
if (topRightTarget.y() + topRightTarget.height() >= bottomRightTarget.y()) {
const float halfOverlap = std::abs(topRightTarget.y() + topRightTarget.height() - bottomRightTarget.y()) / 2.0f;
topRightTarget.setBottom(topRightTarget.bottom() - std::floor(halfOverlap));
bottomRightTarget.setTop(bottomRightTarget.top() + std::ceil(halfOverlap));
drawRight = false;
}
bool drawBottom = true;
if (bottomLeftTarget.x() + bottomLeftTarget.width() >= bottomRightTarget.x()) {
const float halfOverlap = std::abs(bottomLeftTarget.x() + bottomLeftTarget.width() - bottomRightTarget.x()) / 2.0f;
bottomLeftTarget.setRight(bottomLeftTarget.right() - std::floor(halfOverlap));
bottomRightTarget.setLeft(bottomRightTarget.left() + std::ceil(halfOverlap));
drawBottom = false;
}
bool drawLeft = true;
if (topLeftTarget.y() + topLeftTarget.height() >= bottomLeftTarget.y()) {
const float halfOverlap = std::abs(topLeftTarget.y() + topLeftTarget.height() - bottomLeftTarget.y()) / 2.0f;
topLeftTarget.setBottom(topLeftTarget.bottom() - std::floor(halfOverlap));
bottomLeftTarget.setTop(bottomLeftTarget.top() + std::ceil(halfOverlap));
drawLeft = false;
}
painter->translate(paddingLeft, paddingTop);
painter->drawImage(topLeftTarget, shadowPixmap,
QRectF(QPointF(0, 0), topLeftTarget.size()));
painter->drawImage(topRightTarget, shadowPixmap,
QRectF(QPointF(shadowRect.width() - topRightTarget.width(), 0),
topRightTarget.size()));
painter->drawImage(bottomRightTarget, shadowPixmap,
QRectF(QPointF(shadowRect.width() - bottomRightTarget.width(),
shadowRect.height() - bottomRightTarget.height()),
bottomRightTarget.size()));
painter->drawImage(bottomLeftTarget, shadowPixmap,
QRectF(QPointF(0, shadowRect.height() - bottomLeftTarget.height()),
bottomLeftTarget.size()));
if (drawTop) {
QRectF topTarget(topLeftTarget.x() + topLeftTarget.width(),
topLeftTarget.y(),
topRightTarget.x() - topLeftTarget.x() - topLeftTarget.width(),
topRightTarget.height());
QRectF topSource(shadow->topGeometry());
topSource.setHeight(topTarget.height());
topSource.moveTop(shadowRect.top());
painter->drawImage(topTarget, shadowPixmap, topSource);
}
if (drawRight) {
QRectF rightTarget(topRightTarget.x(),
topRightTarget.y() + topRightTarget.height(),
topRightTarget.width(),
bottomRightTarget.y() - topRightTarget.y() - topRightTarget.height());
QRectF rightSource(shadow->rightGeometry());
rightSource.setWidth(rightTarget.width());
rightSource.moveRight(shadowRect.right());
painter->drawImage(rightTarget, shadowPixmap, rightSource);
}
if (drawBottom) {
QRectF bottomTarget(bottomLeftTarget.x() + bottomLeftTarget.width(),
bottomLeftTarget.y(),
bottomRightTarget.x() - bottomLeftTarget.x() - bottomLeftTarget.width(),
bottomRightTarget.height());
QRectF bottomSource(shadow->bottomGeometry());
bottomSource.setHeight(bottomTarget.height());
bottomSource.moveBottom(shadowRect.bottom());
painter->drawImage(bottomTarget, shadowPixmap, bottomSource);
}
if (drawLeft) {
QRectF leftTarget(topLeftTarget.x(),
topLeftTarget.y() + topLeftTarget.height(),
topLeftTarget.width(),
bottomLeftTarget.y() - topLeftTarget.y() - topLeftTarget.height());
QRectF leftSource(shadow->leftGeometry());
leftSource.setWidth(leftTarget.width());
leftSource.moveLeft(shadowRect.left());
painter->drawImage(leftTarget, shadowPixmap, leftSource);
}
}
static QMouseEvent cloneEventWithPadding(QMouseEvent *event, int paddingLeft, int paddingTop)
{
return QMouseEvent(
event->type(),
event->position() - QPointF(paddingLeft, paddingTop),
event->button(),
event->buttons(),
event->modifiers());
}
static QHoverEvent cloneEventWithPadding(QHoverEvent *event, int paddingLeft, int paddingTop)
{
return QHoverEvent(
event->type(),
event->posF() - QPointF(paddingLeft, paddingTop),
event->oldPosF() - QPointF(paddingLeft, paddingTop),
event->modifiers());
}
template<typename E>
void PreviewItem::proxyPassEvent(E *event) const
{
if (m_decoration) {
const auto &shadow = m_decoration->shadow();
if (shadow) {
E e = cloneEventWithPadding(event, shadow->paddingLeft(), shadow->paddingTop());
QCoreApplication::instance()->sendEvent(decoration(), &e);
} else {
QCoreApplication::instance()->sendEvent(decoration(), event);
}
}
// Propagate events to parent
event->ignore();
}
void PreviewItem::mouseDoubleClickEvent(QMouseEvent *event)
{
proxyPassEvent(event);
}
void PreviewItem::mousePressEvent(QMouseEvent *event)
{
proxyPassEvent(event);
}
void PreviewItem::mouseReleaseEvent(QMouseEvent *event)
{
proxyPassEvent(event);
}
void PreviewItem::mouseMoveEvent(QMouseEvent *event)
{
proxyPassEvent(event);
}
void PreviewItem::hoverEnterEvent(QHoverEvent *event)
{
proxyPassEvent(event);
}
void PreviewItem::hoverLeaveEvent(QHoverEvent *event)
{
proxyPassEvent(event);
}
void PreviewItem::hoverMoveEvent(QHoverEvent *event)
{
proxyPassEvent(event);
}
bool PreviewItem::isDrawingBackground() const
{
return m_drawBackground;
}
void PreviewItem::setDrawingBackground(bool set)
{
if (m_drawBackground == set) {
return;
}
m_drawBackground = set;
Q_EMIT drawingBackgroundChanged(set);
}
PreviewBridge *PreviewItem::bridge() const
{
return m_bridge.data();
}
void PreviewItem::setBridge(PreviewBridge *bridge)
{
if (m_bridge == bridge) {
return;
}
if (m_bridge) {
m_bridge->unregisterPreviewItem(this);
}
m_bridge = bridge;
if (m_bridge) {
m_bridge->registerPreviewItem(this);
}
Q_EMIT bridgeChanged();
}
Settings *PreviewItem::settings() const
{
return m_settings.data();
}
void PreviewItem::setSettings(Settings *settings)
{
if (m_settings == settings) {
return;
}
m_settings = settings;
Q_EMIT settingsChanged();
}
PreviewClient *PreviewItem::client()
{
return m_client.data();
}
void PreviewItem::syncSize()
{
if (!m_client) {
return;
}
int widthOffset = 0;
int heightOffset = 0;
auto shadow = m_decoration->shadow();
if (shadow) {
widthOffset = shadow->paddingLeft() + shadow->paddingRight();
heightOffset = shadow->paddingTop() + shadow->paddingBottom();
}
m_client->setWidth(width() - m_decoration->borderLeft() - m_decoration->borderRight() - widthOffset);
m_client->setHeight(height() - m_decoration->borderTop() - m_decoration->borderBottom() - heightOffset);
}
DecorationShadow *PreviewItem::shadow() const
{
if (!m_decoration) {
return nullptr;
}
return m_decoration->shadow().get();
}
}
}
#include "moc_previewitem.cpp"
@@ -0,0 +1,90 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <QPointer>
#include <QQuickPaintedItem>
namespace KDecoration3
{
class Decoration;
class DecorationShadow;
class DecorationSettings;
namespace Preview
{
class PreviewBridge;
class PreviewClient;
class Settings;
class PreviewItem : public QQuickPaintedItem
{
Q_OBJECT
QML_NAMED_ELEMENT(Decoration)
Q_PROPERTY(KDecoration3::Decoration *decoration READ decoration NOTIFY decorationChanged)
Q_PROPERTY(KDecoration3::Preview::PreviewBridge *bridge READ bridge WRITE setBridge NOTIFY bridgeChanged)
Q_PROPERTY(KDecoration3::Preview::Settings *settings READ settings WRITE setSettings NOTIFY settingsChanged)
Q_PROPERTY(KDecoration3::Preview::PreviewClient *client READ client)
Q_PROPERTY(KDecoration3::DecorationShadow *shadow READ shadow NOTIFY shadowChanged)
Q_PROPERTY(QColor windowColor READ windowColor WRITE setWindowColor NOTIFY windowColorChanged)
Q_PROPERTY(bool drawBackground READ isDrawingBackground WRITE setDrawingBackground NOTIFY drawingBackgroundChanged)
public:
PreviewItem(QQuickItem *parent = nullptr);
~PreviewItem() override;
void paint(QPainter *painter) override;
KDecoration3::Decoration *decoration() const;
void setDecoration(KDecoration3::Decoration *deco);
QColor windowColor() const;
void setWindowColor(const QColor &color);
bool isDrawingBackground() const;
void setDrawingBackground(bool set);
PreviewBridge *bridge() const;
void setBridge(PreviewBridge *bridge);
Settings *settings() const;
void setSettings(Settings *settings);
PreviewClient *client();
DecorationShadow *shadow() const;
Q_SIGNALS:
void decorationChanged(KDecoration3::Decoration *deco);
void windowColorChanged(const QColor &color);
void drawingBackgroundChanged(bool);
void bridgeChanged();
void settingsChanged();
void shadowChanged();
protected:
void mouseDoubleClickEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void hoverEnterEvent(QHoverEvent *event) override;
void hoverLeaveEvent(QHoverEvent *event) override;
void hoverMoveEvent(QHoverEvent *event) override;
void componentComplete() override;
private:
void paintShadow(QPainter *painter, int &paddingLeft, int &paddingRight, int &paddingTop, int &paddingBottom);
template <typename E>
void proxyPassEvent(E *event) const;
void syncSize();
void createDecoration();
Decoration *m_decoration;
QColor m_windowColor;
bool m_drawBackground = true;
QPointer<KDecoration3::Preview::PreviewBridge> m_bridge;
QPointer<KDecoration3::Preview::Settings> m_settings;
QPointer<KDecoration3::Preview::PreviewClient> m_client;
};
} // Preview
} // KDecoration3
@@ -0,0 +1,264 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "previewsettings.h"
#include "buttonsmodel.h"
#include "previewbridge.h"
#include <KLocalizedString>
#include <QFontDatabase>
namespace KDecoration3
{
namespace Preview
{
BorderSizesModel::BorderSizesModel(QObject *parent)
: QAbstractListModel(parent)
{
}
BorderSizesModel::~BorderSizesModel() = default;
QVariant BorderSizesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_borders.count() || index.column() != 0) {
return QVariant();
}
if (role != Qt::DisplayRole && role != Qt::UserRole) {
return QVariant();
}
return QVariant::fromValue<BorderSize>(m_borders.at(index.row()));
}
int BorderSizesModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_borders.count();
}
QHash<int, QByteArray> BorderSizesModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(Qt::DisplayRole, QByteArrayLiteral("display"));
return roles;
}
PreviewSettings::PreviewSettings(DecorationSettings *parent)
: QObject()
, DecorationSettingsPrivate(parent)
, m_alphaChannelSupported(true)
, m_onAllDesktopsAvailable(true)
, m_closeOnDoubleClick(false)
, m_leftButtons(new ButtonsModel(QList<DecorationButtonType>({DecorationButtonType::Menu,
DecorationButtonType::ApplicationMenu,
DecorationButtonType::OnAllDesktops}),
this))
, m_rightButtons(new ButtonsModel(QList<DecorationButtonType>({DecorationButtonType::ContextHelp,
DecorationButtonType::Minimize,
DecorationButtonType::Maximize,
DecorationButtonType::Close}),
this))
, m_availableButtons(new ButtonsModel(QList<DecorationButtonType>({DecorationButtonType::Menu,
DecorationButtonType::ApplicationMenu,
DecorationButtonType::OnAllDesktops,
DecorationButtonType::Minimize,
DecorationButtonType::Maximize,
DecorationButtonType::Close,
DecorationButtonType::ContextHelp,
DecorationButtonType::Shade,
DecorationButtonType::KeepBelow,
DecorationButtonType::KeepAbove}),
this))
, m_borderSizes(new BorderSizesModel(this))
, m_borderSize(int(BorderSize::Normal))
, m_font(QFontDatabase::systemFont(QFontDatabase::TitleFont))
{
connect(this, &PreviewSettings::alphaChannelSupportedChanged, parent, &DecorationSettings::alphaChannelSupportedChanged);
connect(this, &PreviewSettings::onAllDesktopsAvailableChanged, parent, &DecorationSettings::onAllDesktopsAvailableChanged);
connect(this, &PreviewSettings::closeOnDoubleClickOnMenuChanged, parent, &DecorationSettings::closeOnDoubleClickOnMenuChanged);
connect(this, &PreviewSettings::fontChanged, parent, &DecorationSettings::fontChanged);
auto updateLeft = [this, parent]() {
Q_EMIT parent->decorationButtonsLeftChanged(decorationButtonsLeft());
};
auto updateRight = [this, parent]() {
Q_EMIT parent->decorationButtonsRightChanged(decorationButtonsRight());
};
connect(m_leftButtons, &QAbstractItemModel::rowsRemoved, this, updateLeft);
connect(m_leftButtons, &QAbstractItemModel::rowsMoved, this, updateLeft);
connect(m_leftButtons, &QAbstractItemModel::rowsInserted, this, updateLeft);
connect(m_rightButtons, &QAbstractItemModel::rowsRemoved, this, updateRight);
connect(m_rightButtons, &QAbstractItemModel::rowsMoved, this, updateRight);
connect(m_rightButtons, &QAbstractItemModel::rowsInserted, this, updateRight);
}
PreviewSettings::~PreviewSettings() = default;
QAbstractItemModel *PreviewSettings::availableButtonsModel() const
{
return m_availableButtons;
}
QAbstractItemModel *PreviewSettings::leftButtonsModel() const
{
return m_leftButtons;
}
QAbstractItemModel *PreviewSettings::rightButtonsModel() const
{
return m_rightButtons;
}
bool PreviewSettings::isAlphaChannelSupported() const
{
return m_alphaChannelSupported;
}
bool PreviewSettings::isOnAllDesktopsAvailable() const
{
return m_onAllDesktopsAvailable;
}
void PreviewSettings::setAlphaChannelSupported(bool supported)
{
if (m_alphaChannelSupported == supported) {
return;
}
m_alphaChannelSupported = supported;
Q_EMIT alphaChannelSupportedChanged(m_alphaChannelSupported);
}
void PreviewSettings::setOnAllDesktopsAvailable(bool available)
{
if (m_onAllDesktopsAvailable == available) {
return;
}
m_onAllDesktopsAvailable = available;
Q_EMIT onAllDesktopsAvailableChanged(m_onAllDesktopsAvailable);
}
void PreviewSettings::setCloseOnDoubleClickOnMenu(bool enabled)
{
if (m_closeOnDoubleClick == enabled) {
return;
}
m_closeOnDoubleClick = enabled;
Q_EMIT closeOnDoubleClickOnMenuChanged(enabled);
}
QList<DecorationButtonType> PreviewSettings::decorationButtonsLeft() const
{
return m_leftButtons->buttons();
}
QList<DecorationButtonType> PreviewSettings::decorationButtonsRight() const
{
return m_rightButtons->buttons();
}
void PreviewSettings::addButtonToLeft(int row)
{
QModelIndex index = m_availableButtons->index(row);
if (!index.isValid()) {
return;
}
m_leftButtons->add(index.data(Qt::UserRole).value<DecorationButtonType>());
}
void PreviewSettings::addButtonToRight(int row)
{
QModelIndex index = m_availableButtons->index(row);
if (!index.isValid()) {
return;
}
m_rightButtons->add(index.data(Qt::UserRole).value<DecorationButtonType>());
}
void PreviewSettings::setBorderSizesIndex(int index)
{
if (m_borderSize == index) {
return;
}
m_borderSize = index;
Q_EMIT borderSizesIndexChanged(index);
Q_EMIT decorationSettings()->borderSizeChanged(borderSize());
}
BorderSize PreviewSettings::borderSize() const
{
return m_borderSizes->index(m_borderSize).data(Qt::UserRole).value<BorderSize>();
}
void PreviewSettings::setFont(const QFont &font)
{
if (m_font == font) {
return;
}
m_font = font;
Q_EMIT fontChanged(m_font);
}
Settings::Settings(QObject *parent)
: QObject(parent)
{
connect(this, &Settings::bridgeChanged, this, &Settings::createSettings);
}
Settings::~Settings() = default;
void Settings::setBridge(PreviewBridge *bridge)
{
if (m_bridge == bridge) {
return;
}
m_bridge = bridge;
Q_EMIT bridgeChanged();
}
PreviewBridge *Settings::bridge() const
{
return m_bridge.data();
}
void Settings::createSettings()
{
if (m_bridge.isNull()) {
m_settings.reset();
} else {
m_settings = std::make_shared<KDecoration3::DecorationSettings>(m_bridge.get());
m_previewSettings = m_bridge->lastCreatedSettings();
m_previewSettings->setBorderSizesIndex(m_borderSize);
connect(this, &Settings::borderSizesIndexChanged, m_previewSettings, &PreviewSettings::setBorderSizesIndex);
}
Q_EMIT settingsChanged();
}
std::shared_ptr<DecorationSettings> Settings::settings() const
{
return m_settings;
}
DecorationSettings *Settings::settingsPointer() const
{
return m_settings.get();
}
void Settings::setBorderSizesIndex(int index)
{
if (m_borderSize == index) {
return;
}
m_borderSize = index;
Q_EMIT borderSizesIndexChanged(m_borderSize);
}
}
}
#include "moc_previewsettings.cpp"
@@ -0,0 +1,153 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <KDecoration3/DecorationSettings>
#include <KDecoration3/Private/DecorationSettingsPrivate>
#include <QAbstractListModel>
#include <QObject>
#include <QPointer>
#include <QQmlEngine>
namespace KDecoration3
{
namespace Preview
{
class ButtonsModel;
class PreviewBridge;
class BorderSizesModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit BorderSizesModel(QObject *parent = nullptr);
~BorderSizesModel() override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
private:
QList<BorderSize> m_borders = QList<BorderSize>({BorderSize::None,
BorderSize::NoSides,
BorderSize::Tiny,
BorderSize::Normal,
BorderSize::Large,
BorderSize::VeryLarge,
BorderSize::Huge,
BorderSize::VeryHuge,
BorderSize::Oversized});
};
class PreviewSettings : public QObject, public DecorationSettingsPrivate
{
Q_OBJECT
Q_PROPERTY(bool onAllDesktopsAvailable READ isOnAllDesktopsAvailable WRITE setOnAllDesktopsAvailable NOTIFY onAllDesktopsAvailableChanged)
Q_PROPERTY(bool alphaChannelSupported READ isAlphaChannelSupported WRITE setAlphaChannelSupported NOTIFY alphaChannelSupportedChanged)
Q_PROPERTY(bool closeOnDoubleClickOnMenu READ isCloseOnDoubleClickOnMenu WRITE setCloseOnDoubleClickOnMenu NOTIFY closeOnDoubleClickOnMenuChanged)
Q_PROPERTY(QAbstractItemModel *leftButtonsModel READ leftButtonsModel CONSTANT)
Q_PROPERTY(QAbstractItemModel *rightButtonsModel READ rightButtonsModel CONSTANT)
Q_PROPERTY(QAbstractItemModel *availableButtonsModel READ availableButtonsModel CONSTANT)
Q_PROPERTY(QAbstractItemModel *borderSizesModel READ borderSizesModel CONSTANT)
Q_PROPERTY(int borderSizesIndex READ borderSizesIndex WRITE setBorderSizesIndex NOTIFY borderSizesIndexChanged)
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
public:
explicit PreviewSettings(DecorationSettings *parent);
~PreviewSettings() override;
bool isAlphaChannelSupported() const override;
bool isOnAllDesktopsAvailable() const override;
bool isCloseOnDoubleClickOnMenu() const override
{
return m_closeOnDoubleClick;
}
BorderSize borderSize() const override;
void setOnAllDesktopsAvailable(bool available);
void setAlphaChannelSupported(bool supported);
void setCloseOnDoubleClickOnMenu(bool enabled);
QAbstractItemModel *leftButtonsModel() const;
QAbstractItemModel *rightButtonsModel() const;
QAbstractItemModel *availableButtonsModel() const;
QAbstractItemModel *borderSizesModel() const
{
return m_borderSizes;
}
QList<DecorationButtonType> decorationButtonsLeft() const override;
QList<DecorationButtonType> decorationButtonsRight() const override;
Q_INVOKABLE void addButtonToLeft(int row);
Q_INVOKABLE void addButtonToRight(int row);
int borderSizesIndex() const
{
return m_borderSize;
}
void setBorderSizesIndex(int index);
QFont font() const override
{
return m_font;
}
void setFont(const QFont &font);
Q_SIGNALS:
void onAllDesktopsAvailableChanged(bool);
void alphaChannelSupportedChanged(bool);
void closeOnDoubleClickOnMenuChanged(bool);
void borderSizesIndexChanged(int);
void fontChanged(const QFont &);
private:
bool m_alphaChannelSupported;
bool m_onAllDesktopsAvailable;
bool m_closeOnDoubleClick;
ButtonsModel *m_leftButtons;
ButtonsModel *m_rightButtons;
ButtonsModel *m_availableButtons;
BorderSizesModel *m_borderSizes;
int m_borderSize;
QFont m_font;
};
class Settings : public QObject
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(KDecoration3::Preview::PreviewBridge *bridge READ bridge WRITE setBridge NOTIFY bridgeChanged)
Q_PROPERTY(KDecoration3::DecorationSettings *settings READ settingsPointer NOTIFY settingsChanged)
Q_PROPERTY(int borderSizesIndex READ borderSizesIndex WRITE setBorderSizesIndex NOTIFY borderSizesIndexChanged)
public:
explicit Settings(QObject *parent = nullptr);
~Settings() override;
PreviewBridge *bridge() const;
void setBridge(PreviewBridge *bridge);
std::shared_ptr<DecorationSettings> settings() const;
DecorationSettings *settingsPointer() const;
int borderSizesIndex() const
{
return m_borderSize;
}
void setBorderSizesIndex(int index);
Q_SIGNALS:
void bridgeChanged();
void settingsChanged();
void borderSizesIndexChanged(int);
private:
void createSettings();
QPointer<PreviewBridge> m_bridge;
std::shared_ptr<KDecoration3::DecorationSettings> m_settings;
PreviewSettings *m_previewSettings = nullptr;
int m_borderSize = 3;
};
}
}
@@ -0,0 +1,25 @@
/*
SPDX-FileCopyrightText: 2024 Nicolas Fella <nicolas.fella@gmx.de>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <QQmlEngine>
#include <KDecoration3/Decoration>
#include <KDecoration3/DecorationShadow>
struct DecorationForeign
{
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(KDecoration3::Decoration)
};
struct DecorationShadowForeign
{
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(KDecoration3::DecorationShadow)
};
@@ -0,0 +1,171 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "decorationmodel.h"
#include "utils.h"
// KDecoration3
#include <KDecoration3/Decoration>
#include <KDecoration3/DecorationSettings>
#include <KDecoration3/DecorationThemeProvider>
// KDE
#include <KPluginFactory>
#include <KPluginMetaData>
// Qt
#include <QDebug>
namespace KDecoration3
{
namespace Configuration
{
static const QString s_pluginName = QStringLiteral("org.kde.kdecoration3");
DecorationsModel::DecorationsModel(QObject *parent)
: QAbstractListModel(parent)
{
}
DecorationsModel::~DecorationsModel() = default;
int DecorationsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_plugins.size();
}
QVariant DecorationsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.column() != 0 || index.row() < 0 || index.row() >= int(m_plugins.size())) {
return QVariant();
}
const KDecoration3::DecorationThemeMetaData &d = m_plugins.at(index.row());
switch (role) {
case Qt::DisplayRole:
return d.visibleName();
case PluginNameRole:
return d.pluginId();
case ThemeNameRole:
return d.themeName();
case ConfigurationRole:
return !d.configurationName().isEmpty();
case KcmoduleNameRole:
return d.configurationName();
case RecommendedBorderSizeRole:
return Utils::borderSizeToString(d.borderSize());
}
return QVariant();
}
QHash<int, QByteArray> DecorationsModel::roleNames() const
{
QHash<int, QByteArray> roles({{Qt::DisplayRole, QByteArrayLiteral("display")},
{PluginNameRole, QByteArrayLiteral("plugin")},
{ThemeNameRole, QByteArrayLiteral("theme")},
{ConfigurationRole, QByteArrayLiteral("configureable")},
{KcmoduleNameRole, QByteArrayLiteral("kcmoduleName")},
{RecommendedBorderSizeRole, QByteArrayLiteral("recommendedbordersize")}});
return roles;
}
static bool isThemeEngine(const QVariantMap &decoSettingsMap)
{
auto it = decoSettingsMap.find(QStringLiteral("themes"));
if (it == decoSettingsMap.end()) {
return false;
}
return it.value().toBool();
}
static KDecoration3::BorderSize recommendedBorderSize(const QVariantMap &decoSettingsMap)
{
auto it = decoSettingsMap.find(QStringLiteral("recommendedBorderSize"));
if (it == decoSettingsMap.end()) {
return KDecoration3::BorderSize::Normal;
}
return Utils::stringToBorderSize(it.value().toString());
}
static QString themeListKeyword(const QVariantMap &decoSettingsMap)
{
auto it = decoSettingsMap.find(QStringLiteral("themeListKeyword"));
if (it == decoSettingsMap.end()) {
return QString();
}
return it.value().toString();
}
static QString findKNewStuff(const QVariantMap &decoSettingsMap)
{
auto it = decoSettingsMap.find(QStringLiteral("KNewStuff"));
if (it == decoSettingsMap.end()) {
return QString();
}
return it.value().toString();
}
void DecorationsModel::init()
{
beginResetModel();
m_plugins.clear();
const auto plugins = KPluginMetaData::findPlugins(s_pluginName);
for (const auto &info : plugins) {
std::unique_ptr<KDecoration3::DecorationThemeProvider> themeFinder(
KPluginFactory::instantiatePlugin<KDecoration3::DecorationThemeProvider>(info).plugin);
KDecoration3::DecorationThemeMetaData data;
const auto decoSettingsMap = info.rawData().value("org.kde.kdecoration3").toObject().toVariantMap();
if (themeFinder) {
const QString &kns = findKNewStuff(decoSettingsMap);
if (!kns.isEmpty() && !m_knsProviders.contains(kns)) {
m_knsProviders.append(kns);
}
if (isThemeEngine(decoSettingsMap)) {
const QString keyword = themeListKeyword(decoSettingsMap);
if (keyword.isNull()) {
// We cannot list the themes
continue;
}
const auto themesList = themeFinder->themes();
for (const KDecoration3::DecorationThemeMetaData &data : themesList) {
m_plugins.emplace_back(data);
}
// it's a theme engine, we don't want to show this entry
continue;
}
}
if (decoSettingsMap.contains(QStringLiteral("kcmodule"))) {
qWarning() << "The use of 'kcmodule' is deprecated in favor of 'kcmoduleName', please update" << info.name();
}
data.setConfigurationName(info.value("X-KDE-ConfigModule"));
data.setBorderSize(recommendedBorderSize(decoSettingsMap));
data.setVisibleName(info.name().isEmpty() ? info.pluginId() : info.name());
data.setPluginId(info.pluginId());
data.setThemeName(data.visibleName());
m_plugins.emplace_back(std::move(data));
}
endResetModel();
}
QModelIndex DecorationsModel::findDecoration(const QString &pluginName, const QString &themeName) const
{
auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [pluginName, themeName](const KDecoration3::DecorationThemeMetaData &d) {
return d.pluginId() == pluginName && d.themeName() == themeName;
});
if (it == m_plugins.cend()) {
return QModelIndex();
}
const auto distance = std::distance(m_plugins.cbegin(), it);
return createIndex(distance, 0);
}
}
}
#include "moc_decorationmodel.cpp"
@@ -0,0 +1,53 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <KDecoration3/DecorationThemeProvider>
#include <QAbstractListModel>
namespace KDecoration3
{
namespace Configuration
{
class DecorationsModel : public QAbstractListModel
{
Q_OBJECT
public:
enum DecorationRole {
PluginNameRole = Qt::UserRole + 1,
ThemeNameRole,
ConfigurationRole,
RecommendedBorderSizeRole,
KcmoduleNameRole,
};
public:
explicit DecorationsModel(QObject *parent = nullptr);
~DecorationsModel() override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
QModelIndex findDecoration(const QString &pluginName, const QString &themeName = QString()) const;
QStringList knsProviders() const
{
return m_knsProviders;
}
public Q_SLOTS:
void init();
private:
std::vector<KDecoration3::DecorationThemeMetaData> m_plugins;
QStringList m_knsProviders;
};
}
}
@@ -0,0 +1,256 @@
/*
SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
SPDX-FileCopyrightText: 2019 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: LGPL-2.0-only
*/
#include "kcm.h"
#include "config-kwin.h"
#include "declarative-plugin/buttonsmodel.h"
#include "decorationmodel.h"
#include <KConfigGroup>
#include <KLocalizedString>
#include <KPluginFactory>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDebug>
#include <QQuickItem>
#include <QQuickWindow>
#include <QSortFilterProxyModel>
#include "kwindecorationdata.h"
#include "kwindecorationsettings.h"
#include "utils.h"
K_PLUGIN_FACTORY_WITH_JSON(KCMKWinDecorationFactory, "kcm_kwindecoration.json", registerPlugin<KCMKWinDecoration>(); registerPlugin<KWinDecorationData>();)
Q_DECLARE_METATYPE(KDecoration3::BorderSize)
namespace
{
const KDecoration3::BorderSize s_defaultRecommendedBorderSize = KDecoration3::BorderSize::Normal;
}
KCMKWinDecoration::KCMKWinDecoration(QObject *parent, const KPluginMetaData &metaData)
: KQuickManagedConfigModule(parent, metaData)
, m_themesModel(new KDecoration3::Configuration::DecorationsModel(this))
, m_proxyThemesModel(new QSortFilterProxyModel(this))
, m_leftButtonsModel(new KDecoration3::Preview::ButtonsModel(DecorationButtonsList(), this))
, m_rightButtonsModel(new KDecoration3::Preview::ButtonsModel(DecorationButtonsList(), this))
, m_availableButtonsModel(new KDecoration3::Preview::ButtonsModel(this))
, m_data(new KWinDecorationData(this))
{
setButtons(Apply | Default | Help);
qmlRegisterAnonymousType<QAbstractListModel>("org.kde.kwin.KWinDecoration", 1);
qmlRegisterAnonymousType<QSortFilterProxyModel>("org.kde.kwin.KWinDecoration", 1);
qmlRegisterAnonymousType<KWinDecorationSettings>("org.kde.kwin.KWinDecoration", 1);
m_proxyThemesModel->setSourceModel(m_themesModel);
m_proxyThemesModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_proxyThemesModel->setSortCaseSensitivity(Qt::CaseInsensitive);
m_proxyThemesModel->sort(0);
connect(m_proxyThemesModel, &QSortFilterProxyModel::rowsInserted, this, &KCMKWinDecoration::themeChanged);
connect(m_proxyThemesModel, &QSortFilterProxyModel::rowsRemoved, this, &KCMKWinDecoration::themeChanged);
connect(m_proxyThemesModel, &QSortFilterProxyModel::modelReset, this, &KCMKWinDecoration::themeChanged);
connect(m_data->settings(), &KWinDecorationSettings::themeChanged, this, &KCMKWinDecoration::themeChanged);
connect(m_data->settings(), &KWinDecorationSettings::borderSizeChanged, this, &KCMKWinDecoration::borderSizeChanged);
connect(m_data->settings(), &KWinDecorationSettings::borderSizeAutoChanged, this, &KCMKWinDecoration::borderIndexChanged);
connect(this, &KCMKWinDecoration::borderSizeChanged, this, &KCMKWinDecoration::borderIndexChanged);
connect(this, &KCMKWinDecoration::themeChanged, this, &KCMKWinDecoration::borderIndexChanged);
connect(this, &KCMKWinDecoration::themeChanged, this, [this]() {
if (m_data->settings()->borderSizeAuto()) {
setBorderSize(recommendedBorderSize());
}
});
connect(m_leftButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::onLeftButtonsChanged);
connect(m_leftButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::onLeftButtonsChanged);
connect(m_leftButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::onLeftButtonsChanged);
connect(m_leftButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::onLeftButtonsChanged);
connect(m_rightButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::onRightButtonsChanged);
connect(m_rightButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::onRightButtonsChanged);
connect(m_rightButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::onRightButtonsChanged);
connect(m_rightButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::onRightButtonsChanged);
connect(this, &KCMKWinDecoration::borderSizeChanged, this, &KCMKWinDecoration::settingsChanged);
// Update the themes when the color scheme or a theme's settings change
QDBusConnection::sessionBus()
.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"),
this, SLOT(reloadKWinSettings()));
QMetaObject::invokeMethod(m_themesModel, &KDecoration3::Configuration::DecorationsModel::init, Qt::QueuedConnection);
}
KWinDecorationSettings *KCMKWinDecoration::settings() const
{
return m_data->settings();
}
void KCMKWinDecoration::reloadKWinSettings()
{
QMetaObject::invokeMethod(m_themesModel, &KDecoration3::Configuration::DecorationsModel::init, Qt::QueuedConnection);
}
void KCMKWinDecoration::load()
{
KQuickManagedConfigModule::load();
m_leftButtonsModel->replace(Utils::buttonsFromString(settings()->buttonsOnLeft()));
m_rightButtonsModel->replace(Utils::buttonsFromString(settings()->buttonsOnRight()));
setBorderSize(borderSizeIndexFromString(settings()->borderSize()));
Q_EMIT themeChanged();
}
void KCMKWinDecoration::save()
{
if (!settings()->borderSizeAuto()) {
settings()->setBorderSize(borderSizeIndexToString(m_borderSizeIndex));
} else {
settings()->setBorderSize(settings()->defaultBorderSizeValue());
}
KQuickManagedConfigModule::save();
// Send a signal to all kwin instances
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
QStringLiteral("org.kde.KWin"),
QStringLiteral("reloadConfig"));
QDBusConnection::sessionBus().send(message);
}
void KCMKWinDecoration::defaults()
{
KQuickManagedConfigModule::defaults();
setBorderSize(recommendedBorderSize());
m_leftButtonsModel->replace(Utils::buttonsFromString(settings()->buttonsOnLeft()));
m_rightButtonsModel->replace(Utils::buttonsFromString(settings()->buttonsOnRight()));
}
void KCMKWinDecoration::onLeftButtonsChanged()
{
settings()->setButtonsOnLeft(Utils::buttonsToString(m_leftButtonsModel->buttons()));
}
void KCMKWinDecoration::onRightButtonsChanged()
{
settings()->setButtonsOnRight(Utils::buttonsToString(m_rightButtonsModel->buttons()));
}
QSortFilterProxyModel *KCMKWinDecoration::themesModel() const
{
return m_proxyThemesModel;
}
QAbstractListModel *KCMKWinDecoration::leftButtonsModel()
{
return m_leftButtonsModel;
}
QAbstractListModel *KCMKWinDecoration::rightButtonsModel()
{
return m_rightButtonsModel;
}
QAbstractListModel *KCMKWinDecoration::availableButtonsModel() const
{
return m_availableButtonsModel;
}
QStringList KCMKWinDecoration::borderSizesModel() const
{
// Use index 0 for borderSizeAuto == true
// The rest of indexes get offset by 1
QStringList model = Utils::getBorderSizeNames().values();
model.insert(0, i18nc("%1 is the name of a border size", "Theme default (%1)", model.at(recommendedBorderSize())));
return model;
}
int KCMKWinDecoration::borderIndex() const
{
return settings()->borderSizeAuto() ? 0 : m_borderSizeIndex + 1;
}
void KCMKWinDecoration::setBorderIndex(int index)
{
const bool borderAuto = (index == 0);
settings()->setBorderSizeAuto(borderAuto);
setBorderSize(borderAuto ? recommendedBorderSize() : index - 1);
}
int KCMKWinDecoration::borderSize() const
{
return m_borderSizeIndex;
}
int KCMKWinDecoration::recommendedBorderSize() const
{
typedef KDecoration3::Configuration::DecorationsModel::DecorationRole DecoRole;
const QModelIndex proxyIndex = m_proxyThemesModel->index(theme(), 0);
if (proxyIndex.isValid()) {
const QModelIndex index = m_proxyThemesModel->mapToSource(proxyIndex);
if (index.isValid()) {
QVariant ret = m_themesModel->data(index, DecoRole::RecommendedBorderSizeRole);
return Utils::getBorderSizeNames().keys().indexOf(Utils::stringToBorderSize(ret.toString()));
}
}
return Utils::getBorderSizeNames().keys().indexOf(s_defaultRecommendedBorderSize);
}
int KCMKWinDecoration::theme() const
{
return m_proxyThemesModel->mapFromSource(m_themesModel->findDecoration(settings()->pluginName(), settings()->theme())).row();
}
void KCMKWinDecoration::setBorderSize(int index)
{
if (m_borderSizeIndex != index) {
m_borderSizeIndex = index;
Q_EMIT borderSizeChanged();
}
}
void KCMKWinDecoration::setBorderSize(KDecoration3::BorderSize size)
{
settings()->setBorderSize(Utils::borderSizeToString(size));
}
void KCMKWinDecoration::setTheme(int index)
{
QModelIndex dataIndex = m_proxyThemesModel->index(index, 0);
if (dataIndex.isValid()) {
settings()->setTheme(m_proxyThemesModel->data(dataIndex, KDecoration3::Configuration::DecorationsModel::ThemeNameRole).toString());
settings()->setPluginName(m_proxyThemesModel->data(dataIndex, KDecoration3::Configuration::DecorationsModel::PluginNameRole).toString());
Q_EMIT themeChanged();
}
}
bool KCMKWinDecoration::isSaveNeeded() const
{
return !settings()->borderSizeAuto() && borderSizeIndexFromString(settings()->borderSize()) != m_borderSizeIndex;
}
int KCMKWinDecoration::borderSizeIndexFromString(const QString &size) const
{
return Utils::getBorderSizeNames().keys().indexOf(Utils::stringToBorderSize(size));
}
QString KCMKWinDecoration::borderSizeIndexToString(int index) const
{
return Utils::borderSizeToString(Utils::getBorderSizeNames().keys().at(index));
}
#include "kcm.moc"
#include "moc_kcm.cpp"
@@ -0,0 +1,97 @@
/*
SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
SPDX-FileCopyrightText: 2019 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: LGPL-2.0-only
*/
#pragma once
#include <KQuickManagedConfigModule>
#include <QAbstractListModel>
class QAbstractItemModel;
class QSortFilterProxyModel;
class QQuickItem;
namespace KDecoration3
{
enum class BorderSize;
namespace Preview
{
class ButtonsModel;
}
namespace Configuration
{
class DecorationsModel;
}
}
class KWinDecorationSettings;
class KWinDecorationData;
class KCMKWinDecoration : public KQuickManagedConfigModule
{
Q_OBJECT
Q_PROPERTY(KWinDecorationSettings *settings READ settings CONSTANT)
Q_PROPERTY(QSortFilterProxyModel *themesModel READ themesModel CONSTANT)
Q_PROPERTY(QStringList borderSizesModel READ borderSizesModel NOTIFY themeChanged)
Q_PROPERTY(int borderIndex READ borderIndex WRITE setBorderIndex NOTIFY borderIndexChanged)
Q_PROPERTY(int borderSize READ borderSize NOTIFY borderSizeChanged)
Q_PROPERTY(int recommendedBorderSize READ recommendedBorderSize CONSTANT)
Q_PROPERTY(int theme READ theme WRITE setTheme NOTIFY themeChanged)
Q_PROPERTY(QAbstractListModel *leftButtonsModel READ leftButtonsModel NOTIFY buttonsChanged)
Q_PROPERTY(QAbstractListModel *rightButtonsModel READ rightButtonsModel NOTIFY buttonsChanged)
Q_PROPERTY(QAbstractListModel *availableButtonsModel READ availableButtonsModel CONSTANT)
public:
KCMKWinDecoration(QObject *parent, const KPluginMetaData &metaData);
KWinDecorationSettings *settings() const;
QSortFilterProxyModel *themesModel() const;
QAbstractListModel *leftButtonsModel();
QAbstractListModel *rightButtonsModel();
QAbstractListModel *availableButtonsModel() const;
QStringList borderSizesModel() const;
int borderIndex() const;
int borderSize() const;
int recommendedBorderSize() const;
int theme() const;
void setBorderIndex(int index);
void setBorderSize(int index);
void setBorderSize(KDecoration3::BorderSize size);
void setTheme(int index);
Q_SIGNALS:
void themeChanged();
void borderIndexChanged();
void borderSizeChanged();
public Q_SLOTS:
void load() override;
void save() override;
void defaults() override;
void reloadKWinSettings();
private Q_SLOTS:
void onLeftButtonsChanged();
void onRightButtonsChanged();
private:
bool isSaveNeeded() const override;
int borderSizeIndexFromString(const QString &size) const;
QString borderSizeIndexToString(int index) const;
KDecoration3::Configuration::DecorationsModel *m_themesModel;
QSortFilterProxyModel *m_proxyThemesModel;
KDecoration3::Preview::ButtonsModel *m_leftButtonsModel;
KDecoration3::Preview::ButtonsModel *m_rightButtonsModel;
KDecoration3::Preview::ButtonsModel *m_availableButtonsModel;
int m_borderSizeIndex = -1;
KWinDecorationData *m_data;
};
@@ -0,0 +1,144 @@
{
"Categories": "Qt;KDE;X-KDE-settings-looknfeel;",
"KPlugin": {
"BugReportUrl": "https://bugs.kde.org/enter_bug.cgi?product=systemsettings&component=kcm_kwindecoration",
"Description": "Configure window titlebars and borders",
"Description[ar]": "اضبط حدود وشريط عنوان النوافذ",
"Description[az]": "Pəncərə başlıq zolağını və çərçivələrini tənzimləyin",
"Description[be]": "Наладжванне панэляў загалоўкаў і рамкі",
"Description[bg]": "Конфигуриране на заглавни ленти и рамки на прозорци",
"Description[ca@valencia]": "Configura les barres de títols i les vores de les finestres",
"Description[ca]": "Configura les barres de títols i les vores de les finestres",
"Description[cs]": "Nastavit popisky a okraje okna",
"Description[da]": "Konfigurér vinduers titellinjer og -kanter",
"Description[de]": "Titelleiste und Ränder von Fenstern einrichten",
"Description[en_GB]": "Configure window title-bars and borders",
"Description[eo]": "Agordi fenestrajn titolbretojn kaj randojn",
"Description[es]": "Configurar las barras de título y los bordes de las ventanas",
"Description[et]": "Akende tiitliriba ja raami seadistamine",
"Description[eu]": "Konfiguratu leihoen titulu-barrak eta ertzak",
"Description[fi]": "Ikkunoiden otsikkopalkkien ja reunojen asetukset",
"Description[fr]": "Configurer les barres de titre et les bordures des fenêtres",
"Description[gl]": "Configurar as barras de título e os bordos das xanelas.",
"Description[he]": "הגדרת שורות כותרות ומסגרות של חלונות",
"Description[hu]": "Az ablakok címsorainak és szegélyeinek beállítása",
"Description[ia]": "Configura barras de titulo e margines",
"Description[id]": "Konfigurasikan bingkai dan bilah judul jendela",
"Description[is]": "Grunnstilla titilstikur og ramma á gluggum",
"Description[it]": "Configura la barra del titolo e i bordi delle finestre",
"Description[ja]": "ウィンドウのタイトルバーと枠を設定",
"Description[ka]": "ფანჯრის სათაურის ზოლისა და საზღვრების მორგება",
"Description[ko]": "창 제목 표시줄과 경계선 설정",
"Description[lt]": "Konfigūruoti langų antraštės juostas ir rėmelius",
"Description[lv]": "Konfigurēt loga virsrakstjoslas un apmales",
"Description[nb]": "Sett opp tittellinjer og vindusrammer",
"Description[nl]": "Titelbalken en randen van venster configureren",
"Description[nn]": "Set opp tittellinjer og vindaugsrammer",
"Description[pl]": "Ustawienia pasków tytułów i obramowań okien",
"Description[pt]": "Configurar as barras de título e contornos das janelas",
"Description[pt_BR]": "Configure as barras de títulos e bordas da janela",
"Description[ro]": "Configurează barele de titlu și contururile ferestrelor",
"Description[ru]": "Настройка заголовка и границ окон",
"Description[sa]": "विण्डो शीर्षकपट्टिकाः सीमाः च विन्यस्यताम्",
"Description[sk]": "Nastaviť záhlavia a okraje okna",
"Description[sl]": "Prilagodite naslovne vrstice in obrobe oken",
"Description[sv]": "Anpassa namnlister och kanter för fönster",
"Description[ta]": "சாளர விளிம்புகளையும் தலைப்புப்பட்டைகளையும் அமையுங்கள்",
"Description[tr]": "Masaüstü pencere başlık çubukları ve kenarlıklarını yapılandır",
"Description[uk]": "Налаштовування смужок заголовків та рамок вікон",
"Description[vi]": "Cấu hình thanh tiêu đề và viền của cửa sổ",
"Description[x-test]": "xxConfigure window titlebars and bordersxx",
"Description[zh_CN]": "配置窗口标题栏和边框",
"Description[zh_TW]": "設定視窗標題列和邊框",
"FormFactors": [
"desktop",
"tablet"
],
"Icon": "preferences-desktop-theme-windowdecorations",
"Name": "Window Decorations",
"Name[ar]": "زخارف النوافذ",
"Name[az]": "Pəncərə haşiyələri",
"Name[be]": "Аздабленне акон",
"Name[bg]": "Декорации на прозорци",
"Name[ca@valencia]": "Decoració de les finestres",
"Name[ca]": "Decoració de les finestres",
"Name[cs]": "Dekorace oken",
"Name[da]": "Vinduedekorationer",
"Name[de]": "Fensterdekoration",
"Name[en_GB]": "Window Decorations",
"Name[eo]": "Fenestraj Dekoracioj",
"Name[es]": "Decoraciones de las ventanas",
"Name[et]": "Akna dekoratsioonid",
"Name[eu]": "Leiho-apaindurak",
"Name[fi]": "Ikkunakoristelu",
"Name[fr]": "Décorations de fenêtres",
"Name[gl]": "Decoración de xanelas",
"Name[he]": "עיטורי חלונות",
"Name[hu]": "Ablakdekorációk",
"Name[ia]": "Decorationes de fenestra",
"Name[id]": "Dekorasi Jendela",
"Name[is]": "Gluggaskreytingar",
"Name[it]": "Decorazioni delle finestre",
"Name[ja]": "ウィンドウの装飾",
"Name[ka]": "ფანჯრის დეკორაციები",
"Name[ko]": "창 장식",
"Name[lt]": "Langų dekoracijos",
"Name[lv]": "Logu noformējums",
"Name[nb]": "Vindusdekorasjon",
"Name[nl]": "Vensterdecoraties",
"Name[nn]": "Vindaugspynt",
"Name[pl]": "Wygląd okien",
"Name[pt]": "Decorações das Janelas",
"Name[pt_BR]": "Decorações da janela",
"Name[ro]": "Decorații fereastră",
"Name[ru]": "Оформление окон",
"Name[sa]": "खिडकी सजावट",
"Name[sk]": "Dekorácie okien",
"Name[sl]": "Okrasitev oken",
"Name[sv]": "Fönsterdekorationer",
"Name[ta]": "சாளர விளிம்புகள்",
"Name[tr]": "Pencere Dekorasyonları",
"Name[uk]": "Обрамлення вікон",
"Name[vi]": "Trang trí cửa sổ",
"Name[x-test]": "xxWindow Decorationsxx",
"Name[zh_CN]": "窗口装饰元素",
"Name[zh_TW]": "視窗裝飾"
},
"X-DocPath": "kcontrol/kwindecoration/index.html",
"X-KDE-Keywords": "kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,window decorations,titlebar,window buttons,window border,skin,shadow",
"X-KDE-Keywords[ar]": "كوين,نافذة,مدير,حدود,نمط,موضوع,نظرة,إحساس,تخطيط,زر,مقبض,حافة,KWM,ديكور,زخارف النوافذ,شريط العنوان,أزرار النافذة,حدود النافذة,الجلد,الظل",
"X-KDE-Keywords[bg]": "kwin,прозорец,мениджър,граница,стил,тема,изглед,усещане,оформление,бутон,ръкохватка,ръб,kwm,декорация,декорации на прозорци,заглавна лента,бутони на прозорци,рамка на прозореца,кожа,сянка",
"X-KDE-Keywords[ca@valencia]": "kwin,finestra,gestor,vora,estil,tema,aspecte,comportament,disposició,botó,ansa,vora,kwm,decoració,decoracions de finestra,barra de títol,botons de finestra,vora de finestra,aparença,ombra",
"X-KDE-Keywords[ca]": "kwin,finestra,gestor,vora,estil,tema,aspecte,comportament,disposició,botó,nansa,vora,kwm,decoració,decoracions de finestra,barra de títol,botons de finestra,vora de finestra,aparença,ombra",
"X-KDE-Keywords[cs]": "kwin,okno,správce,okraj,styl,motiv,vzhled,pocit,rozvržení,tlačítko,madlo,okraj,kwm,dekorace,dekorace oken,pruh titulku,tlačítka okna,okraj okna, stín",
"X-KDE-Keywords[en_GB]": "kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,window decorations,titlebar,window buttons,window border,skin,shadow",
"X-KDE-Keywords[es]": "kwin,ventana,gestor,borde,estilo,tema,aspecto,apariencia,organización,disposición,esquema,botón,asa,tirador,borde,kwm,decoración,decoraciones de las ventanas,barra de título,botones de la ventana,borde de la ventana,piel,sombra,sombreado",
"X-KDE-Keywords[eu]": "kwin,leihoa,kudeatzailea,ertza,bazterra,muga,estiloa,gaia,itxura,izaera,antolaera,botoia,heldulekua,kirtena,kwm,apainketa,apaindura,apaingarria,leihoen apaingarriak,titulu-barra,leihoaren botoiak,leihoaren ertzak,azala,itzala",
"X-KDE-Keywords[fi]": "kwin,ikkuna,hallinta,ikkunaohjelma,reuna,reunaviiva,tyyli,teema,ulkoasu,tuntuma,asettelu,painike,nappin,kahva,reuna,laita,kwin,koristelu,koristus,ikkunakoristeet,otsikkorivi,otsikkopalkki,ikkunan reunan,varjo,varjostus",
"X-KDE-Keywords[fr]": "kwin, fenêtre, gestionnaire, bordure, style, thème, apparence, toucher, mise en page, bouton, poignée, bord, kwm, décoration, décorations de fenêtre, barre de titre, boutons de fenêtre, bordure de fenêtre, habillage, ombre",
"X-KDE-Keywords[gl]": "kwin,window,xanela,ventá,fiestra,manager,xestor,manexador,border,bordo,esquina,extremo,style,estilo,theme,tema,look,aparencia,feel,comportamento,layout,disposición,button,botón,handle,asa,edge,kwm,decoration,decoración,window decorations,decoracións de xanelas,decoracións de ventás,decoracións de fiestras,titlebar,barra de título,window buttons,botóns de xanelas,botóns de ventás,botóns de fiestras,window border,bordo de xanela,bordo de ventá,bordo de fiestra,skin,shadow,sombra",
"X-KDE-Keywords[he]": "kwin,מראה,מנהל,גבול,מסגרת,סגנון,ערכת עיצוב,ערכת נושא,תחושה,פריסה,כפתור,ידית,קצה,שול,kwm,עיטור,עיטורי חלון,שורת כותרת,כפתורי חלון,גבול חלון,מסגרת חלון,מעטפת,עור,סקין,צל,הצללה,צללית",
"X-KDE-Keywords[hu]": "kwin,ablak,kezelő,szegély,stílus,téma,megjelenés,kinézet,elrendezés,gomb,kezelő,szél,kwm,dekoráció,ablakdekorációk,címsor,ablakgombok,ablakszegéy,felület,árnyék",
"X-KDE-Keywords[ia]": "kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,window decorations,titlebar,window buttons,window border,skin,shadow",
"X-KDE-Keywords[is]": "kwin,gluggi,stjóri,jaðar,stílsnið,þema,útlit,tilfinning,framsetning,hnappur,grip,brún,kwm,skreyting,gluggaskreytingar,titilstika,gluggahnappar,gluggabrún,yfirlag,skuggi",
"X-KDE-Keywords[it]": "kwin,finestra,gestore,bordo,stile,tema,aspetto,impressione,disposizione,pulsante,maniglia,bordo,kwm,decorazione,decorazioni finestra,barra del titolo,pulsanti finestra,bordo finestra,tema,ombra",
"X-KDE-Keywords[ka]": "kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,window decorations,titlebar,window buttons,window border,skin,shadow,ჩრდილი,სკინი,ფანჯრის საზღვარი,ფანჯრის ღილაკები,ფანჯრის დეკორაცია,დეკორაცია,განლაგება,გარეგნობა,თემა,საზღვარი",
"X-KDE-Keywords[ko]": "창,관리자,경계선,테두리,스타일,테마,레이아웃,단추,핸들,경계선,장식,창 장식,제목 표시줄,창 단추,창 경계선,창 테두리,그림자",
"X-KDE-Keywords[lv]": "kwin,logs,pārvaldnieks,apmale, rāmis,stils,motīvs,izskats,uzvedība,izkārtojums,poga,turis,mala,kwm,dekorācija,logu dekorācijas,virsrakstjosla,loga pogas,loga apmale,āda,ēna",
"X-KDE-Keywords[nb]": "kwin,vindu,behandler,ramme,kantlinje,stil,tema,lås,utforming,knapp,håndtak,kant,kwm,dekorasjon,pynt,vindusdekorasjon,vinduspynt,tittellinje,vindusknapper,vinduskant,vindusramme,tema,drakt,utseende,skygge",
"X-KDE-Keywords[nl]": "kwin,venster,beheerder,rand,stijl,thema,uiterlijk,gevoel,indeling,knop,hendel,rand,kwm,decoratie,vensterdecoraties,titelbalk,vensterknoppen, vensterrand,skin,schaduw",
"X-KDE-Keywords[nn]": "kwin,vindauge,handsamar,ramme,kantlinje,stil,tema,lås,utforming,knapp,handtak,kant,kwm,dekorasjon,pynt,vindaugsdekorasjon,vindaugspynt,tittellinje,vindaugsknappar,vindaugskant,vindaugsramme,tema,drakt,utsjånad,skugge",
"X-KDE-Keywords[pl]": "kwin,okno,menadżer,obramowanie,styl,motyw,wygląd,odczucie,układ,przycisk, uchwyt,krawędź,kwm,ozdoba,ozdoby okien,pasek tytułu,przyciski okna,obramowanie okna,skóra,cień",
"X-KDE-Keywords[pt_BR]": "kwin,janela,gerenciador,borda,estilo,tema,aparência,comportamento,layout,botão,borda,kwm,decoração,decorações de janela,barra de título,botões de janela,borda de janela,skin,sombra",
"X-KDE-Keywords[ru]": "kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,window decorations,titlebar,window buttons,window border,skin,shadow,окно,диспетчер,граница,стиль,тема,внешний вид,удобство,компоновка,кнопка,маркер,край,оформление окон,строка заголовка,заголовок,кнопки окна,граница окна,тень",
"X-KDE-Keywords[sa]": "kwin,खिड़की,प्रबंधक,सीमा,शैली,थीम,देखें,अनुभूति,लेआउट,बटन,हैंडल,धार,kwm,सजावट,खिड़की सजावट,शीर्षकपट्टी,खिड़की बटन,खिड़की सीमा,चमड़ी,छाया",
"X-KDE-Keywords[sl]": "kwin,okno,upravljalnik,meja,slog,tema,videz,občutek,postaviten,gumb,ročka,rob,kwm,dekoracija,okenske dekoracije,naslovna vrstica,okenski gumbi,meje oken,preobleka,senca",
"X-KDE-Keywords[sv]": "kwin,fönster,hanterare,kant,stil,tema,utseende,känsla,layout,knapp,grepp,kant,kwm,dekoration,fönsterdekorationer,namnlist,fönsterknappar,fönsterkant,skal,skugga",
"X-KDE-Keywords[tr]": "kwin,pencere,yönetici,kenarlık,biçem,stil,tema,görünüş,his,yerleşim,düzen,düğme,tutaç,tutamak,kenar,kwm,dekorasyon,pencere dekorasyonu,başlık çubuğu,pencere düğmeleri,pencere kenarlığı,tema,gölge",
"X-KDE-Keywords[uk]": "kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,window decorations,titlebar,window buttons,window border,skin,shadow,вікно,вікна,керування,менеджер,рамка,межа,стиль,тема,вигляд,поведінка,компонування,кнопка,елемент,край,декорації,обрамлення,смужка заголовка,кнопки,рамка,оформлення,тінь",
"X-KDE-Keywords[x-test]": "xxkwinxx,xxwindowxx,xxmanagerxx,xxborderxx,xxstylexx,xxthemexx,xxlookxx,xxfeelxx,xxlayoutxx,xxbuttonxx,xxhandlexx,xxedgexx,xxkwmxx,xxdecorationxx,xxwindow decorationsxx,xxtitlebarxx,xxwindow buttonsxx,xxwindow borderxx,xxskinxx,xxshadowxx",
"X-KDE-Keywords[zh_CN]": "kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,window decorations,titlebar,window buttons,window border,skin,shadow,chuangkou,guanliqi,chuangkouguanliqi,biankuang,fengge,yangshi,zhuti,jiemianwaiguan,waiguan,guangan,shijuexiaoguo,shixiao,buju,anniu,tuobing,shoubing,bianyuan,zhuangshi,chuangkouzhuangshi,biaotilan,chuangkouanniu,chuangkoubiankuang,chuangkouwaikuang,pifu,touying,yinying,窗口,管理器,窗口管理器,边框,风格,样式,主题,界面外观,外观,观感,视觉效果,视效,布局,按钮,拖柄,手柄,边缘,装饰,窗口装饰,标题栏,窗口按钮,窗口边框,窗口外框,皮肤,投影,阴影",
"X-KDE-Keywords[zh_TW]": "kwin,視窗,視窗管理員,邊框,風格,樣式,主題,佈局,配置,按鈕,邊緣,視窗裝飾,裝飾,標題列,標題欄,標題按鈕,視窗按鈕,陰影",
"X-KDE-System-Settings-Parent-Category": "themes",
"X-KDE-Weight": 60
}
@@ -0,0 +1,130 @@
/*
SPDX-FileCopyrightText: 2021 Dan Leinir Turthra Jensen <admin@leinir.dk>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "kwindecorationsettings.h"
#include "decorationmodel.h"
#include <KLocalizedString>
#include <QCommandLineParser>
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDebug>
#include <QFileInfo>
#include <QTimer>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
int exitCode{0};
QCoreApplication::setApplicationName(QStringLiteral("kwin-applywindowdecoration"));
QCoreApplication::setApplicationVersion(QStringLiteral("1.0"));
QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
KLocalizedString::setApplicationDomain(QByteArrayLiteral("kwin-applywindowdecoration"));
QCommandLineParser *parser = new QCommandLineParser;
parser->addHelpOption();
parser->setApplicationDescription(i18n("This tool allows you to set the window decoration theme for the currently active session, without accidentally setting it to one that is either not available, or which is already set."));
parser->addPositionalArgument(QStringLiteral("theme"), i18n("The name of the window decoration theme you wish to set for KWin. Passing a full path will attempt to find a theme in that directory, and then apply that if one can be deduced."));
parser->addOption(QCommandLineOption(QStringLiteral("list-themes"), i18n("Show all the themes available on the system (and which is the current theme)")));
parser->process(app);
KDecoration3::Configuration::DecorationsModel *model = new KDecoration3::Configuration::DecorationsModel(&app);
model->init();
KWinDecorationSettings *settings = new KWinDecorationSettings(&app);
QTextStream ts(stdout);
if (!parser->positionalArguments().isEmpty()) {
QString requestedTheme{parser->positionalArguments().constFirst()};
if (requestedTheme.endsWith(QStringLiteral("/*"))) {
// Themes installed through KNewStuff will commonly be given an installed files entry
// which has the main directory name and an asterix to say the cursors are all in that directory,
// and since one of the main purposes of this tool is to allow adopting things from a kns dialog,
// we handle that little weirdness here.
requestedTheme.remove(requestedTheme.length() - 2, 2);
}
bool themeResolved{true};
if (requestedTheme.contains(QStringLiteral("/"))) {
themeResolved = false;
if (QFileInfo::exists(requestedTheme) && QFileInfo(requestedTheme).isDir()) {
// Since this is the name of a directory, let's do a bit of checking to see
// if we know enough about it to deduce that this is, in fact, a theme.
QStringList splitTheme = requestedTheme.split(QStringLiteral("/"), Qt::SkipEmptyParts);
if (splitTheme.count() > 3 && splitTheme[splitTheme.count() - 3] == QLatin1StringView("aurorae") && splitTheme[splitTheme.count() - 2] == QLatin1StringView("themes")) {
// We think this is an aurorae theme, but let's just make a little more certain...
QString file(QStringLiteral("aurorae/themes/%1/metadata.desktop").arg(splitTheme.last()));
QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, file);
if (!path.isEmpty() && path == QStringLiteral("%1/metadata.desktop").arg(requestedTheme)) {
requestedTheme = QString("__aurorae__svg__").append(splitTheme.last());
themeResolved = true;
ts << i18n("Resolved %1 to the KWin Aurorae theme \"%2\", and will attempt to set that as your current theme.")
.arg(parser->positionalArguments().first(), requestedTheme)
<< Qt::endl;
}
}
} else {
ts << i18n("You attempted to pass a file path, but this could not be resolved to a theme, and we will have to abort, due to having no theme to set") << Qt::endl;
exitCode = -1;
}
}
if (settings->theme() == requestedTheme) {
ts << i18n("The requested theme \"%1\" is already set as the window decoration theme.", requestedTheme) << Qt::endl;
// not an error condition, just nothing happens
} else if (themeResolved) {
int index{-1};
QStringList availableThemes;
for (int i = 0; i < model->rowCount(); ++i) {
const QString themeName = model->data(model->index(i), KDecoration3::Configuration::DecorationsModel::ThemeNameRole).toString();
if (requestedTheme == themeName) {
index = i;
break;
}
availableThemes << themeName;
}
if (index > -1) {
settings->setTheme(model->data(model->index(index), KDecoration3::Configuration::DecorationsModel::ThemeNameRole).toString());
settings->setPluginName(model->data(model->index(index), KDecoration3::Configuration::DecorationsModel::PluginNameRole).toString());
if (settings->save()) {
// Send a signal to all kwin instances
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
QStringLiteral("org.kde.KWin"),
QStringLiteral("reloadConfig"));
QDBusConnection::sessionBus().send(message);
ts << i18n("Successfully applied the cursor theme %1 to your current Plasma session",
model->data(model->index(index), KDecoration3::Configuration::DecorationsModel::ThemeNameRole).toString())
<< Qt::endl;
} else {
ts << i18n("Failed to save your theme settings - the reason is unknown, but this is an unrecoverable error. You may find that simply trying again will work.");
exitCode = -1;
}
} else {
ts << i18n("Could not find theme \"%1\". The theme should be one of the following options: %2", requestedTheme, availableThemes.join(QStringLiteral(", "))) << Qt::endl;
exitCode = -1;
}
}
} else if (parser->isSet(QStringLiteral("list-themes"))) {
ts << i18n("You have the following KWin window decoration themes on your system:") << Qt::endl;
for (int i = 0; i < model->rowCount(); ++i) {
const QString displayName = model->data(model->index(i), Qt::DisplayRole).toString();
const QString themeName = model->data(model->index(i), KDecoration3::Configuration::DecorationsModel::ThemeNameRole).toString();
if (settings->theme() == themeName) {
ts << QStringLiteral(" * %1 (theme name: %2 - current theme for this Plasma session)").arg(displayName, themeName) << Qt::endl;
} else {
ts << QStringLiteral(" * %1 (theme name: %2)").arg(displayName, themeName) << Qt::endl;
}
}
} else {
parser->showHelp();
}
QTimer::singleShot(0, &app, [&app, &exitCode]() {
app.exit(exitCode);
});
return app.exec();
}
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<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" >
<include>config-kwin.h</include>
<kcfgfile name="kwinrc" />
<group name="org.kde.kdecoration2">
<entry name="pluginName" key="library" type="String">
<label>Plugin name</label>
<code>#if HAVE_BREEZE_DECO
const QString s_defaultPlugin { BREEZE_KDECORATION_PLUGIN_ID };
#else
const QString s_defaultPlugin { QStringLiteral("org.kde.kwin.aurorae") };
#endif
</code>
<default code="true">s_defaultPlugin</default>
</entry>
<entry name="theme" key="theme" type="String">
<label>Theme name</label>
<code>#if HAVE_BREEZE_DECO
const QString s_defaultTheme { QStringLiteral("Breeze") };
#else
const QString s_defaultTheme { QStringLiteral("kwin4_decoration_qml_plastik") };
#endif
</code>
<default code="true">s_defaultTheme</default>
</entry>
<entry name="borderSize" key="BorderSize" type="String">
<label>Window border size</label>
<default>Normal</default>
</entry>
<entry name="borderSizeAuto" key="BorderSizeAuto" type="Bool">
<label>Use theme's default window border size</label>
<default>true</default>
</entry>
<entry name="closeOnDoubleClickOnMenu" key="CloseOnDoubleClickOnMenu" type="Bool">
<label>Close windows by double clicking the menu button</label>
<default>false</default>
</entry>
<entry name="showToolTips" key="ShowToolTips" type="Bool">
<label>Show titlebar button tooltips</label>
<default>true</default>
</entry>
<entry name="buttonsOnLeft" key="ButtonsOnLeft" type="String">
<label>Titlebar left buttons</label>
<default>MS</default>
</entry>
<entry name="buttonsOnRight" key="ButtonsOnRight" type="String">
<label>Titlebar right buttons</label>
<default>HIAX</default>
</entry>
</group>
</kcfg>
@@ -0,0 +1,7 @@
File=kwindecorationsettings.kcfg
ClassName=KWinDecorationSettings
Mutators=true
DefaultValueGetters=true
GenerateProperties=true
ParentInConstructor=true
Notifiers=buttonsOnLeft,buttonsOnRight,theme
@@ -0,0 +1,65 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kwin.private.kdecoration as KDecoration
ListView {
id: view
property string key
property bool dragActive: false
property int iconSize: Kirigami.Units.iconSizes.small
orientation: ListView.Horizontal
interactive: false
spacing: Kirigami.Units.smallSpacing
implicitHeight: iconSize
implicitWidth: count * (iconSize + Kirigami.Units.smallSpacing) - Math.min(1, count) * Kirigami.Units.smallSpacing
delegate: Item {
width: view.iconSize
height: view.iconSize
KDecoration.Button {
id: button
property int itemIndex: index
property var buttonsModel: parent.ListView.view.model
bridge: bridgeItem.bridge
settings: settingsItem
type: model["button"]
width: view.iconSize
height: view.iconSize
anchors.fill: Drag.active ? undefined : parent
Drag.keys: [ "decoButtonRemove", view.key ]
Drag.active: dragArea.drag.active
Drag.onActiveChanged: view.dragActive = Drag.active
color: palette.windowText
opacity: parent.enabled ? 1.0 : 0.3
}
MouseArea {
id: dragArea
cursorShape: drag.target.Drag.active ? Qt.ClosedHandCursor : Qt.OpenHandCursor
anchors.fill: parent
drag.target: button
onReleased: {
if (drag.target.Drag.target) {
drag.target.Drag.drop();
} else {
drag.target.Drag.cancel();
}
}
}
}
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: Kirigami.Units.longDuration/2 }
NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: Kirigami.Units.longDuration/2 }
}
move: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: Kirigami.Units.longDuration/2 }
NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: Kirigami.Units.longDuration/2 }
}
displaced: Transition {
NumberAnimation { properties: "x,y"; duration: Kirigami.Units.longDuration; easing.type: Easing.OutBounce }
}
}
@@ -0,0 +1,264 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import org.kde.kcmutils as KCM
import org.kde.kirigami as Kirigami
import org.kde.kwin.private.kdecoration as KDecoration
// Fake Window
Rectangle {
id: baseLayout
readonly property int buttonIconSize: Kirigami.Units.iconSizes.medium
readonly property int titleBarSpacing: Kirigami.Units.largeSpacing
readonly property bool draggingTitlebarButtons: leftButtonsView.dragActive || rightButtonsView.dragActive
readonly property bool hideDragHint: draggingTitlebarButtons || availableButtonsGrid.dragActive
color: palette.base
radius: Kirigami.Units.cornerRadius
KDecoration.Bridge {
id: bridgeItem
plugin: "org.kde.breeze"
}
KDecoration.Settings {
id: settingsItem
bridge: bridgeItem.bridge
}
ColumnLayout {
anchors.fill: parent
// Fake titlebar
Rectangle {
Layout.fillWidth: true
implicitHeight: buttonPreviewRow.implicitHeight + 2 * baseLayout.titleBarSpacing
radius: Kirigami.Units.cornerRadius
gradient: Gradient {
GradientStop { position: 0.0; color: palette.midlight }
GradientStop { position: 1.0; color: palette.window }
}
RowLayout {
id: buttonPreviewRow
anchors {
margins: baseLayout.titleBarSpacing
left: parent.left
right: parent.right
top: parent.top
}
ButtonGroup {
id: leftButtonsView
iconSize: baseLayout.buttonIconSize
model: kcm.leftButtonsModel
key: "decoButtonLeft"
Rectangle {
visible: stateBindingButtonLeft.nonDefaultHighlightVisible
anchors.fill: parent
Layout.margins: Kirigami.Units.smallSpacing
color: "transparent"
border.color: Kirigami.Theme.neutralTextColor
border.width: 1
radius: Kirigami.Units.cornerRadius
}
KCM.SettingStateBinding {
id: stateBindingButtonLeft
configObject: kcm.settings
settingName: "buttonsOnLeft"
}
}
QQC2.Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
font.bold: true
text: i18n("Titlebar")
}
ButtonGroup {
id: rightButtonsView
iconSize: baseLayout.buttonIconSize
model: kcm.rightButtonsModel
key: "decoButtonRight"
Rectangle {
visible: stateBindingButtonRight.nonDefaultHighlightVisible
anchors.fill: parent
Layout.margins: Kirigami.Units.smallSpacing
color: "transparent"
border.color: Kirigami.Theme.neutralTextColor
border.width: 1
radius: Kirigami.Units.cornerRadius
}
KCM.SettingStateBinding {
id: stateBindingButtonRight
configObject: kcm.settings
settingName: "buttonsOnRight"
}
}
}
DropArea {
id: titleBarDropArea
anchors {
fill: parent
margins: -baseLayout.titleBarSpacing
}
keys: [ "decoButtonAdd", "decoButtonRight", "decoButtonLeft" ]
onEntered: {
drag.accept();
}
onDropped: {
var view = undefined;
var left = drag.x - (leftButtonsView.x + leftButtonsView.width);
var right = drag.x - rightButtonsView.x;
if (Math.abs(left) <= Math.abs(right)) {
if (leftButtonsView.enabled) {
view = leftButtonsView;
}
} else {
if (rightButtonsView.enabled) {
view = rightButtonsView;
}
}
if (!view) {
return;
}
var point = mapToItem(view, drag.x, drag.y);
var index = 0
for(var childIndex = 0 ; childIndex < (view.count - 1) ; childIndex++) {
var child = view.contentItem.children[childIndex]
if (child.x > point.x) {
break
}
index = childIndex + 1
}
if (drop.keys.indexOf("decoButtonAdd") !== -1) {
view.model.add(index, drag.source.type);
} else if (drop.keys.indexOf("decoButtonLeft") !== -1) {
if (view === leftButtonsView) {
// move in same view
if (index !== drag.source.itemIndex) {
drag.source.buttonsModel.move(drag.source.itemIndex, index);
}
} else {
// move to right view
view.model.add(index, drag.source.type);
drag.source.buttonsModel.remove(drag.source.itemIndex);
}
} else if (drop.keys.indexOf("decoButtonRight") !== -1) {
if (view === rightButtonsView) {
// move in same view
if (index !== drag.source.itemIndex) {
drag.source.buttonsModel.move(drag.source.itemIndex, index);
}
} else {
// move to left view
view.model.add(index, drag.source.type);
drag.source.buttonsModel.remove(drag.source.itemIndex);
}
}
}
}
}
GridView {
id: availableButtonsGrid
property bool dragActive: false
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: availableButtonsGrid.cellHeight * 2
Layout.margins: Kirigami.Units.largeSpacing
cellWidth: Kirigami.Units.gridUnit * 6
cellHeight: Kirigami.Units.gridUnit * 6
model: kcm.availableButtonsModel
interactive: false
delegate: ColumnLayout {
width: availableButtonsGrid.cellWidth - Kirigami.Units.largeSpacing
height: availableButtonsGrid.cellHeight - Kirigami.Units.largeSpacing
opacity: baseLayout.draggingTitlebarButtons ? 0.15 : 1.0
Rectangle {
Layout.alignment: Qt.AlignHCenter
color: palette.window
radius: Kirigami.Units.cornerRadius
implicitWidth: baseLayout.buttonIconSize + Kirigami.Units.largeSpacing
implicitHeight: baseLayout.buttonIconSize + Kirigami.Units.largeSpacing
KDecoration.Button {
id: availableButton
anchors.centerIn: Drag.active ? undefined : parent
bridge: bridgeItem.bridge
settings: settingsItem
type: model["button"]
width: baseLayout.buttonIconSize
height: baseLayout.buttonIconSize
Drag.keys: [ "decoButtonAdd" ]
Drag.active: dragArea.drag.active
Drag.onActiveChanged: availableButtonsGrid.dragActive = Drag.active
color: palette.windowText
}
MouseArea {
id: dragArea
anchors.fill: availableButton
drag.target: availableButton
cursorShape: availableButton.Drag.active ? Qt.ClosedHandCursor : Qt.OpenHandCursor
onReleased: {
if (availableButton.Drag.target) {
availableButton.Drag.drop();
} else {
availableButton.Drag.cancel();
}
}
}
}
QQC2.Label {
id: iconLabel
text: model["display"]
Layout.fillWidth: true
Layout.fillHeight: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
elide: Text.ElideRight
wrapMode: Text.Wrap
}
}
DropArea {
anchors.fill: parent
keys: [ "decoButtonRemove" ]
onEntered: {
drag.accept();
}
onDropped: {
drag.source.buttonsModel.remove(drag.source.itemIndex);
}
Kirigami.Heading {
text: i18n("Drop button here to remove it")
font.weight: Font.Bold
level: 2
anchors.centerIn: parent
opacity: baseLayout.draggingTitlebarButtons ? 1.0 : 0.0
}
}
}
Text {
id: dragHint
readonly property real dragHintOpacitiy: enabled ? 1.0 : 0.3
color: palette.windowText
opacity: baseLayout.hideDragHint ? 0.0 : dragHintOpacitiy
Layout.fillWidth: true
Layout.margins: Kirigami.Units.gridUnit * 3
horizontalAlignment: Text.AlignHCenter
text: i18n("Drag buttons between here and the titlebar")
}
}
}
@@ -0,0 +1,69 @@
/*
SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
SPDX-License-Identifier: LGPL-2.0-only
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import org.kde.kcmutils as KCM
import org.kde.kirigami 2.20 as Kirigami
KCM.AbstractKCM {
title: i18n("Titlebar Buttons")
framedView: false
Rectangle {
anchors.fill: parent
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
color: Kirigami.Theme.backgroundColor
Buttons {
anchors.fill: parent
anchors.margins: Kirigami.Units.largeSpacing
}
}
footer: ColumnLayout {
QQC2.CheckBox {
id: closeOnDoubleClickOnMenuCheckBox
text: i18nc("checkbox label", "Close windows by double clicking the menu button")
checked: kcm.settings.closeOnDoubleClickOnMenu
onToggled: {
kcm.settings.closeOnDoubleClickOnMenu = checked;
infoLabel.visible = checked;
}
KCM.SettingStateBinding {
configObject: kcm.settings
settingName: "closeOnDoubleClickOnMenu"
}
}
Kirigami.InlineMessage {
Layout.fillWidth: true
id: infoLabel
type: Kirigami.MessageType.Information
text: i18nc("popup tip", "Click and hold on the menu button to show the menu.")
showCloseButton: true
visible: false
}
QQC2.CheckBox {
id: showToolTipsCheckBox
text: i18nc("checkbox label", "Show titlebar button tooltips")
checked: kcm.settings.showToolTips
onToggled: kcm.settings.showToolTips = checked
KCM.SettingStateBinding {
configObject: kcm.settings
settingName: "showToolTips"
}
}
}
}
@@ -0,0 +1,117 @@
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick
import org.kde.kcmutils as KCM
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kwin.private.kdecoration as KDecoration
KCM.GridView {
function updateDecoration(item, marginTopLeft, marginBottomRight) {
const mainMargin = Kirigami.Units.largeSpacing;
const shd = item.shadow;
item.anchors.leftMargin = mainMargin + marginTopLeft - (shd ? shd.paddingLeft : 0);
item.anchors.rightMargin = mainMargin + marginBottomRight - (shd ? shd.paddingRight : 0);
item.anchors.topMargin = mainMargin + marginTopLeft - (shd ? shd.paddingTop : 0);
item.anchors.bottomMargin = mainMargin + marginBottomRight - (shd ? shd.paddingBottom : 0);
}
view.model: kcm.themesModel
view.currentIndex: kcm.theme
view.onContentHeightChanged: view.positionViewAtIndex(view.currentIndex, GridView.Visible)
view.implicitCellWidth: Kirigami.Units.gridUnit * 18
framedView: false
view.delegate: KCM.GridDelegate {
id: delegate
text: model.display
thumbnailAvailable: true
thumbnail: Rectangle {
anchors.fill: parent
color: palette.base
clip: true
KDecoration.Bridge {
id: bridgeItem
plugin: model.plugin
theme: model.theme
kcmoduleName: model.kcmoduleName
}
KDecoration.Settings {
id: settingsItem
bridge: bridgeItem.bridge
Component.onCompleted: {
settingsItem.borderSizesIndex = kcm.borderSize;
}
}
KDecoration.Decoration {
id: inactivePreview
bridge: bridgeItem.bridge
settings: settingsItem
anchors.fill: parent
onShadowChanged: updateDecoration(inactivePreview, 0, client.decoration.titleBar.height)
Component.onCompleted: {
client.active = false;
client.caption = model.display;
updateDecoration(inactivePreview, 0, client.decoration.titleBar.height);
}
}
KDecoration.Decoration {
id: activePreview
bridge: bridgeItem.bridge
settings: settingsItem
anchors.fill: parent
onShadowChanged: updateDecoration(activePreview, client.decoration.titleBar.height, 0)
Component.onCompleted: {
client.active = true;
client.caption = model.display;
updateDecoration(activePreview, client.decoration.titleBar.height, 0);
}
}
MouseArea {
anchors.fill: parent
onClicked: delegate.clicked()
onDoubleClicked: delegate.doubleClicked()
}
Connections {
target: kcm
function onBorderSizeChanged() {
settingsItem.borderSizesIndex = kcm.borderSize;
}
}
}
actions: [
Kirigami.Action {
icon.name: "edit-entry"
tooltip: i18n("Edit %1 Theme…", model.display)
enabled: model.configureable
onTriggered: {
kcm.theme = index;
view.currentIndex = index;
bridgeItem.bridge.configure(delegate);
}
}
]
onClicked: {
kcm.theme = index;
view.currentIndex = index;
}
onDoubleClicked: {
kcm.save();
}
}
Connections {
target: kcm
function onThemeChanged() {
view.currentIndex = kcm.theme;
}
}
}
@@ -0,0 +1,76 @@
/*
SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
SPDX-License-Identifier: LGPL-2.0-only
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import org.kde.kcmutils as KCM
import org.kde.kirigami 2.20 as Kirigami
import org.kde.newstuff as NewStuff
KCM.AbstractKCM {
id: root
title: kcm.name
framedView: false
implicitWidth: Kirigami.Units.gridUnit * 48
implicitHeight: Kirigami.Units.gridUnit * 33
actions: [
Kirigami.Action {
id: borderSizeComboBox
text: i18nc("Selector label", "Window border size:")
displayComponent: RowLayout {
QQC2.ComboBox {
id: borderSizeComboBox
currentIndex: kcm.borderIndex
flat: true
model: kcm.borderSizesModel
onActivated: kcm.borderIndex = currentIndex
KCM.SettingHighlighter {
highlight: kcm.borderIndex !== 0
}
}
}
},
Kirigami.Action {
icon.name: "configure"
text: i18nc("button text", "Configure Titlebar Buttons…")
onTriggered: kcm.push("ConfigureTitlebar.qml")
},
NewStuff.Action {
configFile: "window-decorations.knsrc"
text: i18nc("@action:button as in, \"Get New Window Decorations\"", "Get New…")
onEntryEvent: (entry, event) => {
if (event === NewStuff.Engine.StatusChangedEvent) {
kcm.reloadKWinSettings();
} else if (event === NewStuff.Engine.EntryAdoptedEvent) {
kcm.load();
}
}
}
]
Themes {
id: themes
anchors.fill: parent
KCM.SettingStateBinding {
configObject: kcm.settings
settingName: "pluginName"
target: themes
}
}
}
@@ -0,0 +1,107 @@
/*
SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
SPDX-License-Identifier: LGPL-2.0-only
*/
#include "utils.h"
#include <KConfigGroup>
#include <KLocalizedString>
namespace
{
const QMap<QString, KDecoration3::BorderSize> s_borderSizes{
{QStringLiteral("None"), KDecoration3::BorderSize::None},
{QStringLiteral("NoSides"), KDecoration3::BorderSize::NoSides},
{QStringLiteral("Tiny"), KDecoration3::BorderSize::Tiny},
{QStringLiteral("Normal"), KDecoration3::BorderSize::Normal},
{QStringLiteral("Large"), KDecoration3::BorderSize::Large},
{QStringLiteral("VeryLarge"), KDecoration3::BorderSize::VeryLarge},
{QStringLiteral("Huge"), KDecoration3::BorderSize::Huge},
{QStringLiteral("VeryHuge"), KDecoration3::BorderSize::VeryHuge},
{QStringLiteral("Oversized"), KDecoration3::BorderSize::Oversized}};
const QMap<KDecoration3::BorderSize, QString> s_borderSizeNames{
{KDecoration3::BorderSize::None, i18n("No window borders")},
{KDecoration3::BorderSize::NoSides, i18n("No side window borders")},
{KDecoration3::BorderSize::Tiny, i18n("Tiny window borders")},
{KDecoration3::BorderSize::Normal, i18n("Normal window borders")},
{KDecoration3::BorderSize::Large, i18n("Large window borders")},
{KDecoration3::BorderSize::VeryLarge, i18n("Very large window borders")},
{KDecoration3::BorderSize::Huge, i18n("Huge window borders")},
{KDecoration3::BorderSize::VeryHuge, i18n("Very huge window borders")},
{KDecoration3::BorderSize::Oversized, i18n("Oversized window borders")}};
const QHash<KDecoration3::DecorationButtonType, QChar> s_buttonNames{
{KDecoration3::DecorationButtonType::Menu, QChar('M')},
{KDecoration3::DecorationButtonType::ApplicationMenu, QChar('N')},
{KDecoration3::DecorationButtonType::OnAllDesktops, QChar('S')},
{KDecoration3::DecorationButtonType::ContextHelp, QChar('H')},
{KDecoration3::DecorationButtonType::Minimize, QChar('I')},
{KDecoration3::DecorationButtonType::Maximize, QChar('A')},
{KDecoration3::DecorationButtonType::Close, QChar('X')},
{KDecoration3::DecorationButtonType::KeepAbove, QChar('F')},
{KDecoration3::DecorationButtonType::KeepBelow, QChar('B')},
{KDecoration3::DecorationButtonType::Shade, QChar('L')},
{KDecoration3::DecorationButtonType::Spacer, QChar('_')},
};
}
namespace Utils
{
QString buttonsToString(const DecorationButtonsList &buttons)
{
auto buttonToString = [](KDecoration3::DecorationButtonType button) -> QChar {
const auto it = s_buttonNames.constFind(button);
if (it != s_buttonNames.constEnd()) {
return it.value();
}
return QChar();
};
QString ret;
for (auto button : buttons) {
ret.append(buttonToString(button));
}
return ret;
}
DecorationButtonsList buttonsFromString(const QString &buttons)
{
DecorationButtonsList ret;
for (auto it = buttons.begin(); it != buttons.end(); ++it) {
for (auto it2 = s_buttonNames.constBegin(); it2 != s_buttonNames.constEnd(); ++it2) {
if (it2.value() == (*it)) {
ret << it2.key();
}
}
}
return ret;
}
DecorationButtonsList readDecorationButtons(const KConfigGroup &config, const QString &key, const DecorationButtonsList &defaultValue)
{
return buttonsFromString(config.readEntry(key, buttonsToString(defaultValue)));
}
KDecoration3::BorderSize stringToBorderSize(const QString &name)
{
auto it = s_borderSizes.constFind(name);
if (it == s_borderSizes.constEnd()) {
// non sense values are interpreted just like normal
return KDecoration3::BorderSize::Normal;
}
return it.value();
}
QString borderSizeToString(KDecoration3::BorderSize size)
{
return s_borderSizes.key(size);
}
const QMap<KDecoration3::BorderSize, QString> &getBorderSizeNames()
{
return s_borderSizeNames;
}
} // namespace Utils
@@ -0,0 +1,27 @@
/*
SPDX-FileCopyrightText: 2019 Valerio Pilo <vpilo@coldshock.net>
SPDX-License-Identifier: LGPL-2.0-only
*/
#pragma once
#include <KDecoration3/DecorationButton>
#include <KSharedConfig>
#include <QList>
using DecorationButtonsList = QList<KDecoration3::DecorationButtonType>;
namespace Utils
{
QString buttonsToString(const DecorationButtonsList &buttons);
DecorationButtonsList buttonsFromString(const QString &buttons);
DecorationButtonsList readDecorationButtons(const KConfigGroup &config, const QString &key, const DecorationButtonsList &defaultValue);
KDecoration3::BorderSize stringToBorderSize(const QString &name);
QString borderSizeToString(KDecoration3::BorderSize size);
const QMap<KDecoration3::BorderSize, QString> &getBorderSizeNames();
}
@@ -0,0 +1,69 @@
[KNewStuff3]
Name=Window Decorations
Name[ar]=زخارف النوافذ
Name[az]=Pəncərə dekorasiyası
Name[bg]=Декорации на прозорците
Name[bs]=Dekoracije prozora
Name[ca]=Decoració de les finestres
Name[ca@valencia]=Decoració de les finestres
Name[cs]=Dekorace oken
Name[da]=Vinduesdekorationer
Name[de]=Fensterdekoration
Name[el]=Διακοσμήσεις παραθύρου
Name[en_GB]=Window Decorations
Name[es]=Decoraciones de las ventanas
Name[et]=Akna dekoratsioonid
Name[eu]=Leiho-apaindurak
Name[fi]=Ikkunakehykset
Name[fr]=Décorations de fenêtres
Name[ga]=Maisiúcháin Fhuinneog
Name[gl]=Decoración da xanela
Name[he]=מסגרת חלון
Name[hi]=ि
Name[hr]=Ukrasi prozora
Name[hu]=Ablakdekorációk
Name[ia]=Decorationes de fenestra
Name[id]=Dekorasi Window
Name[is]=Gluggaskreytingar
Name[it]=Decorazioni delle finestre
Name[ja]=
Name[kk]=Терезенің безендірулері
Name[km]=
Name[kn]=ಿ
Name[ko]=
Name[lt]=Langų dekoracijos
Name[lv]=Logu dekorācijas
Name[mr]=
Name[nb]=Vinduspynt
Name[nds]=Finstern opfladusen
Name[nl]=Vensterdecoraties
Name[nn]=Vindaugspynt
Name[pa]=ਿ
Name[pl]=Wygląd okien
Name[pt]=Decorações das Janelas
Name[pt_BR]=Decorações da janela
Name[ro]=Decorații fereastră
Name[ru]=Оформление окон
Name[si]=
Name[sk]=Dekorácie okien
Name[sl]=Okraski oken
Name[sr]=Декорације прозора
Name[sr@ijekavian]=Декорације прозора
Name[sr@ijekavianlatin]=Dekoracije prozora
Name[sr@latin]=Dekoracije prozora
Name[sv]=Fönsterdekorationer
Name[th]=
Name[tr]=Pencere Dekorasyonları
Name[ug]=كۆزنەك بېزەكلىرى
Name[uk]=Обрамлення вікон
Name[wa]=Gåyotaedjes des fniesses
Name[x-test]=xxWindow Decorationsxx
Name[zh_CN]=
Name[zh_TW]=
ProvidersUrl=https://autoconfig.kde.org/ocs/providers.xml
ContentWarning=Executables
Categories=Plasma 6 Window Decorations
TargetDir=aurorae/themes
Uncompress=archive
AdoptionCommand=@KDE_INSTALL_FULL_LIBEXECDIR@/kwin-applywindowdecoration %f
@@ -0,0 +1,29 @@
# KI18N Translation Domain for this library.
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_kwin_virtualdesktops\")
########### next target ###############
set(kcm_kwin_virtualdesktops_PART_SRCS
../../virtualdesktopsdbustypes.cpp
animationsmodel.cpp
desktopsmodel.cpp
virtualdesktops.cpp
virtualdesktopsdata.cpp
)
kconfig_add_kcfg_files(kcm_kwin_virtualdesktops_PART_SRCS virtualdesktopssettings.kcfgc GENERATE_MOC)
kcmutils_add_qml_kcm(kcm_kwin_virtualdesktops SOURCES ${kcm_kwin_virtualdesktops_PART_SRCS})
target_link_libraries(kcm_kwin_virtualdesktops PRIVATE
Qt::DBus
KF6::I18n
KF6::KCMUtils
KF6::KCMUtilsQuick
KF6::XmlGui
kcmkwincommon
)
install(FILES virtualdesktopssettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
@@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT `find . -name \*.cpp -o -name \*.qml` -o $podir/kcm_kwin_virtualdesktops.pot
@@ -0,0 +1,178 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "animationsmodel.h"
#include <KConfigGroup>
namespace KWin
{
AnimationsModel::AnimationsModel(QObject *parent)
: EffectsModel(parent)
{
connect(this, &EffectsModel::loaded, this, [this]() {
setAnimationEnabled(modelAnimationEnabled());
setAnimationIndex(modelAnimationIndex());
loadDefaults();
});
connect(this, &AnimationsModel::animationIndexChanged, this, [this]() {
const QModelIndex index_ = index(m_animationIndex, 0);
if (!index_.isValid()) {
return;
}
const bool configurable = index_.data(ConfigurableRole).toBool();
if (configurable != m_currentConfigurable) {
m_currentConfigurable = configurable;
Q_EMIT currentConfigurableChanged();
}
});
}
bool AnimationsModel::animationEnabled() const
{
return m_animationEnabled;
}
void AnimationsModel::setAnimationEnabled(bool enabled)
{
if (m_animationEnabled != enabled) {
m_animationEnabled = enabled;
Q_EMIT animationEnabledChanged();
}
}
int AnimationsModel::animationIndex() const
{
return m_animationIndex;
}
void AnimationsModel::setAnimationIndex(int index)
{
if (m_animationIndex != index) {
m_animationIndex = index;
Q_EMIT animationIndexChanged();
}
}
bool AnimationsModel::currentConfigurable() const
{
return m_currentConfigurable;
}
bool AnimationsModel::defaultAnimationEnabled() const
{
return m_defaultAnimationEnabled;
}
int AnimationsModel::defaultAnimationIndex() const
{
return m_defaultAnimationIndex;
}
bool AnimationsModel::shouldStore(const EffectData &data) const
{
return data.untranslatedCategory.contains(
QStringLiteral("Virtual Desktop Switching Animation"), Qt::CaseInsensitive);
}
EffectsModel::Status AnimationsModel::status(int row) const
{
return Status(data(index(row, 0), static_cast<int>(StatusRole)).toInt());
}
void AnimationsModel::loadDefaults()
{
for (int i = 0; i < rowCount(); ++i) {
const QModelIndex rowIndex = index(i, 0);
if (rowIndex.data(EnabledByDefaultRole).toBool()) {
m_defaultAnimationEnabled = true;
m_defaultAnimationIndex = i;
Q_EMIT defaultAnimationEnabledChanged();
Q_EMIT defaultAnimationIndexChanged();
break;
}
}
}
bool AnimationsModel::modelAnimationEnabled() const
{
for (int i = 0; i < rowCount(); ++i) {
if (status(i) != Status::Disabled) {
return true;
}
}
return false;
}
int AnimationsModel::modelAnimationIndex() const
{
for (int i = 0; i < rowCount(); ++i) {
if (status(i) != Status::Disabled) {
return i;
}
}
return 0;
}
void AnimationsModel::load()
{
EffectsModel::load();
}
void AnimationsModel::save()
{
for (int i = 0; i < rowCount(); ++i) {
const auto status = (m_animationEnabled && i == m_animationIndex)
? EffectsModel::Status::Enabled
: EffectsModel::Status::Disabled;
updateEffectStatus(index(i, 0), status);
}
EffectsModel::save();
}
void AnimationsModel::defaults()
{
EffectsModel::defaults();
setAnimationEnabled(modelAnimationEnabled());
setAnimationIndex(modelAnimationIndex());
}
bool AnimationsModel::isDefaults() const
{
// effect at m_animationIndex index may not be the current saved selected effect
const bool enabledByDefault = index(m_animationIndex, 0).data(EnabledByDefaultRole).toBool();
return enabledByDefault;
}
bool AnimationsModel::needsSave() const
{
KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), QStringLiteral("Plugins"));
for (int i = 0; i < rowCount(); ++i) {
const QModelIndex index_ = index(i, 0);
const bool enabledConfig = kwinConfig.readEntry(
index_.data(ServiceNameRole).toString() + QLatin1String("Enabled"),
index_.data(EnabledByDefaultRole).toBool());
const bool enabled = (m_animationEnabled && i == m_animationIndex);
if (enabled != enabledConfig) {
return true;
}
}
return false;
}
}
#include "moc_animationsmodel.cpp"
@@ -0,0 +1,71 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "effectsmodel.h"
namespace KWin
{
class AnimationsModel : public EffectsModel
{
Q_OBJECT
Q_PROPERTY(bool animationEnabled READ animationEnabled WRITE setAnimationEnabled NOTIFY animationEnabledChanged)
Q_PROPERTY(int animationIndex READ animationIndex WRITE setAnimationIndex NOTIFY animationIndexChanged)
Q_PROPERTY(bool currentConfigurable READ currentConfigurable NOTIFY currentConfigurableChanged)
Q_PROPERTY(bool defaultAnimationEnabled READ defaultAnimationEnabled NOTIFY defaultAnimationEnabledChanged)
Q_PROPERTY(int defaultAnimationIndex READ defaultAnimationIndex NOTIFY defaultAnimationIndexChanged)
public:
explicit AnimationsModel(QObject *parent = nullptr);
bool animationEnabled() const;
void setAnimationEnabled(bool enabled);
int animationIndex() const;
void setAnimationIndex(int index);
bool currentConfigurable() const;
bool defaultAnimationEnabled() const;
int defaultAnimationIndex() const;
void load();
void save();
void defaults();
bool isDefaults() const;
bool needsSave() const;
Q_SIGNALS:
void animationEnabledChanged();
void animationIndexChanged();
void currentConfigurableChanged();
void defaultAnimationEnabledChanged();
void defaultAnimationIndexChanged();
protected:
bool shouldStore(const EffectData &data) const override;
private:
Status status(int row) const;
void loadDefaults();
bool modelAnimationEnabled() const;
int modelAnimationIndex() const;
bool m_animationEnabled = false;
bool m_defaultAnimationEnabled = false;
int m_animationIndex = -1;
int m_defaultAnimationIndex = -1;
bool m_currentConfigurable = false;
Q_DISABLE_COPY(AnimationsModel)
};
}
@@ -0,0 +1,688 @@
/*
SPDX-FileCopyrightText: 2018 Eike Hein <hein@kde.org>
SPDX-FileCopyrightText: 2018 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "desktopsmodel.h"
#include <cmath>
#include <KLocalizedString>
#include <QDBusArgument>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusMetaType>
#include <QDBusPendingCall>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
#include <QDBusServiceWatcher>
#include <QDBusVariant>
#include <QMetaEnum>
#include <QRegularExpression>
#include <QUuid>
namespace KWin
{
static const QString s_serviceName(QStringLiteral("org.kde.KWin"));
static const QString s_virtualDesktopsInterface(QStringLiteral("org.kde.KWin.VirtualDesktopManager"));
static const QString s_virtDesktopsPath(QStringLiteral("/VirtualDesktopManager"));
static const QString s_fdoPropertiesInterface(QStringLiteral("org.freedesktop.DBus.Properties"));
DesktopsModel::DesktopsModel(QObject *parent)
: QAbstractListModel(parent)
, m_userModified(false)
, m_serverModified(false)
, m_serverSideRows(-1)
, m_rows(-1)
{
qDBusRegisterMetaType<KWin::DBusDesktopDataStruct>();
qDBusRegisterMetaType<KWin::DBusDesktopDataVector>();
m_serviceWatcher = new QDBusServiceWatcher(s_serviceName,
QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange);
QObject::connect(m_serviceWatcher, &QDBusServiceWatcher::serviceRegistered,
this, [this]() {
reset();
});
QObject::connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered,
this, [this]() {
QDBusConnection::sessionBus().disconnect(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("desktopCreated"),
this,
SLOT(desktopCreated(QString, KWin::DBusDesktopDataStruct)));
QDBusConnection::sessionBus().disconnect(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("desktopRemoved"),
this,
SLOT(desktopRemoved(QString)));
QDBusConnection::sessionBus().disconnect(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("desktopDataChanged"),
this,
SLOT(desktopDataChanged(QString, KWin::DBusDesktopDataStruct)));
QDBusConnection::sessionBus().disconnect(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("rowsChanged"),
this,
SLOT(desktopRowsChanged(uint)));
});
reset();
}
DesktopsModel::~DesktopsModel()
{
}
QHash<int, QByteArray> DesktopsModel::roleNames() const
{
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles"));
for (int i = 0; i < e.keyCount(); ++i) {
roles.insert(e.value(i), e.key(i));
}
return roles;
}
QVariant DesktopsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() > (m_desktops.count() - 1)) {
return QVariant();
}
if (role == Qt::DisplayRole) {
return m_names.value(m_desktops.at(index.row()));
} else if (role == Id) {
return m_desktops.at(index.row());
} else if (role == DesktopRow) {
const int rows = std::max(m_rows, 1);
const int perRow = std::ceil((qreal)m_desktops.count() / (qreal)rows);
return (index.row() / perRow) + 1;
} else if (role == IsDefault) {
// According to defaults(), first desktop is default
return index.row() == 0;
}
return QVariant();
}
int DesktopsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_desktops.count();
}
bool DesktopsModel::ready() const
{
return !m_desktops.isEmpty();
}
QString DesktopsModel::error() const
{
return m_error;
}
bool DesktopsModel::userModified() const
{
return m_userModified;
}
bool DesktopsModel::serverModified() const
{
return m_serverModified;
}
int DesktopsModel::rows() const
{
return m_rows;
}
void DesktopsModel::setRows(int rows)
{
if (!ready()) {
return;
}
if (m_rows != rows) {
m_rows = rows;
Q_EMIT rowsChanged();
Q_EMIT dataChanged(index(0, 0), index(m_desktops.count() - 1, 0), QList<int>{DesktopRow});
updateModifiedState();
}
}
int DesktopsModel::desktopCount() const
{
return rowCount();
}
QString DesktopsModel::createDesktopName() const
{
const QStringList nameValues = m_names.values();
for (int index = 1;; ++index) {
const QString desktopName = i18ncp("A numbered name for virtual desktops", "Desktop %1", "Desktop %1", index);
if (!nameValues.contains(desktopName)) {
return desktopName;
}
}
}
void DesktopsModel::createDesktop()
{
if (!ready()) {
return;
}
beginInsertRows(QModelIndex(), m_desktops.count(), m_desktops.count());
const QString &dummyId = QUuid::createUuid().toString(QUuid::WithoutBraces);
m_desktops.append(dummyId);
m_names[dummyId] = createDesktopName();
endInsertRows();
Q_EMIT desktopCountChanged();
updateModifiedState();
}
void DesktopsModel::removeDesktop(const QString &id)
{
if (!ready() || !m_desktops.contains(id)) {
return;
}
const int desktopIndex = m_desktops.indexOf(id);
beginRemoveRows(QModelIndex(), desktopIndex, desktopIndex);
m_desktops.removeAt(desktopIndex);
m_names.remove(id);
endRemoveRows();
Q_EMIT desktopCountChanged();
updateModifiedState();
}
void DesktopsModel::setDesktopName(const QString &id, const QString &name)
{
if (!ready() || !m_desktops.contains(id)) {
return;
}
m_names[id] = name;
const QModelIndex &idx = index(m_desktops.indexOf(id), 0);
Q_EMIT dataChanged(idx, idx, QList<int>{Qt::DisplayRole});
updateModifiedState();
}
void DesktopsModel::syncWithServer()
{
auto callFinished = [this](QDBusPendingCallWatcher *call) {
QDBusPendingReply<void> reply = *call;
if (reply.isError()) {
handleCallError();
}
--m_pendingCalls;
call->deleteLater();
};
if (m_desktops.count() > m_serverSideDesktops.count()) {
auto call = QDBusMessage::createMethodCall(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("createDesktop"));
const int newIndex = m_serverSideDesktops.count();
call.setArguments({(uint)newIndex, m_names.value(m_desktops.at(newIndex))});
++m_pendingCalls;
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call);
const auto *watcher = new QDBusPendingCallWatcher(pending, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished);
return; // The change-handling slot will call syncWithServer() again,
// until everything is in sync.
}
if (m_desktops.count() < m_serverSideDesktops.count()) {
QStringListIterator i(m_serverSideDesktops);
i.toBack();
while (i.hasPrevious()) {
const QString &previous = i.previous();
if (!m_desktops.contains(previous)) {
auto call = QDBusMessage::createMethodCall(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("removeDesktop"));
call.setArguments({previous});
++m_pendingCalls;
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call);
const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished);
return; // The change-handling slot will call syncWithServer() again,
// until everything is in sync.
}
}
}
// Sync ids. Replace dummy ids in the process.
for (int i = 0; i < m_serverSideDesktops.count(); ++i) {
const QString oldId = m_desktops.at(i);
const QString &newId = m_serverSideDesktops.at(i);
m_desktops[i] = newId;
m_names[newId] = m_names.take(oldId);
}
Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), QList<int>{Qt::DisplayRole});
// Sync names.
if (m_names != m_serverSideNames) {
QHashIterator<QString, QString> i(m_names);
while (i.hasNext()) {
i.next();
if (i.value() != m_serverSideNames.value(i.key())) {
auto call = QDBusMessage::createMethodCall(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("setDesktopName"));
call.setArguments({i.key(), i.value()});
++m_pendingCalls;
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call);
const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished);
break;
}
}
return; // The change-handling slot will call syncWithServer() again,
// until everything is in sync..
}
// Sync rows.
if (m_rows != m_serverSideRows) {
auto call = QDBusMessage::createMethodCall(
s_serviceName,
s_virtDesktopsPath,
s_fdoPropertiesInterface,
QStringLiteral("Set"));
call.setArguments({s_virtualDesktopsInterface,
QStringLiteral("rows"), QVariant::fromValue(QDBusVariant(QVariant((uint)m_rows)))});
++m_pendingCalls;
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call);
const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished);
}
}
void DesktopsModel::reset()
{
auto getAllAndConnectCall = QDBusMessage::createMethodCall(
s_serviceName,
s_virtDesktopsPath,
s_fdoPropertiesInterface,
QStringLiteral("GetAll"));
getAllAndConnectCall.setArguments({s_virtualDesktopsInterface});
QDBusConnection::sessionBus().callWithCallback(
getAllAndConnectCall,
this,
SLOT(getAllAndConnect(QDBusMessage)),
SLOT(handleCallError()));
}
bool DesktopsModel::needsSave() const
{
return m_userModified;
}
bool DesktopsModel::isDefaults() const
{
return m_rows == 2 && m_desktops.count() == 1;
}
void DesktopsModel::defaults()
{
beginResetModel();
// default is 1 desktop with 2 rows
// see kwin/virtualdesktops.cpp VirtualDesktopGrid::VirtualDesktopGrid
while (m_desktops.count() > 1) {
const auto desktop = m_desktops.takeLast();
m_names.remove(desktop);
}
setRows(2);
endResetModel();
m_userModified = true;
updateModifiedState();
}
void DesktopsModel::load()
{
beginResetModel();
m_desktops = m_serverSideDesktops;
m_names = m_serverSideNames;
setRows(m_serverSideRows);
endResetModel();
m_userModified = true;
updateModifiedState();
}
void DesktopsModel::getAllAndConnect(const QDBusMessage &msg)
{
const QVariantMap &data = qdbus_cast<QVariantMap>(msg.arguments().at(0).value<QDBusArgument>());
const KWin::DBusDesktopDataVector &desktops = qdbus_cast<KWin::DBusDesktopDataVector>(
data.value(QStringLiteral("desktops")).value<QDBusArgument>());
const int newServerSideRows = data.value(QStringLiteral("rows")).toUInt();
QStringList newServerSideDesktops;
QHash<QString, QString> newServerSideNames;
for (const KWin::DBusDesktopDataStruct &d : desktops) {
newServerSideDesktops.append(d.id);
newServerSideNames[d.id] = d.name;
}
// If the server-side state changed during a KWin restart, and the
// user had made notifications, the model should notify about the
// change.
if (m_serverSideDesktops != newServerSideDesktops
|| m_serverSideNames != newServerSideNames
|| m_serverSideRows != newServerSideRows) {
if (!m_serverSideDesktops.isEmpty() || m_userModified) {
m_serverModified = true;
Q_EMIT serverModifiedChanged();
}
m_serverSideDesktops = newServerSideDesktops;
m_serverSideNames = newServerSideNames;
m_serverSideRows = newServerSideRows;
}
// For the case KWin restarts while the KCM was open: If the user had
// made no modifications, just reset to the server data. E.g. perhaps
// the user intentionally nuked the KWin config while it was down, so
// we should follow.
if (!m_userModified || m_desktops.empty()) {
beginResetModel();
m_desktops = m_serverSideDesktops;
m_names = m_serverSideNames;
m_rows = m_serverSideRows;
endResetModel();
Q_EMIT rowsChanged();
}
Q_EMIT readyChanged();
auto handleConnectionError = [this]() {
m_error = i18n("There was an error connecting to the compositor.");
Q_EMIT errorChanged();
};
bool connected = QDBusConnection::sessionBus().connect(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("desktopCreated"),
this,
SLOT(desktopCreated(QString, KWin::DBusDesktopDataStruct)));
if (!connected) {
handleConnectionError();
return;
}
connected = QDBusConnection::sessionBus().connect(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("desktopRemoved"),
this,
SLOT(desktopRemoved(QString)));
if (!connected) {
handleConnectionError();
return;
}
connected = QDBusConnection::sessionBus().connect(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("desktopDataChanged"),
this,
SLOT(desktopDataChanged(QString, KWin::DBusDesktopDataStruct)));
if (!connected) {
handleConnectionError();
return;
}
connected = QDBusConnection::sessionBus().connect(
s_serviceName,
s_virtDesktopsPath,
s_virtualDesktopsInterface,
QStringLiteral("rowsChanged"),
this,
SLOT(desktopRowsChanged(uint)));
if (!connected) {
handleConnectionError();
return;
}
}
void DesktopsModel::desktopCreated(const QString &id, const KWin::DBusDesktopDataStruct &data)
{
m_serverSideDesktops.insert(data.position, id);
m_serverSideNames[data.id] = data.name;
// If the user didn't make any changes, we can just stay in sync.
if (!m_userModified) {
beginInsertRows(QModelIndex(), data.position, data.position);
m_desktops = m_serverSideDesktops;
m_names = m_serverSideNames;
endInsertRows();
} else {
// Remove dummy data.
const QString dummyId = m_desktops.at(data.position);
m_desktops[data.position] = id;
m_names.remove(dummyId);
m_names[id] = data.name;
const QModelIndex &idx = index(data.position, 0);
Q_EMIT dataChanged(idx, idx, QList<int>{Id});
updateModifiedState(/* server */ true);
}
}
void DesktopsModel::desktopRemoved(const QString &id)
{
const int desktopIndex = m_serverSideDesktops.indexOf(id);
m_serverSideDesktops.removeAt(desktopIndex);
m_serverSideNames.remove(id);
// If the user didn't make any changes, we can just stay in sync.
if (!m_userModified) {
beginRemoveRows(QModelIndex(), desktopIndex, desktopIndex);
m_desktops = m_serverSideDesktops;
m_names = m_serverSideNames;
endRemoveRows();
} else {
updateModifiedState(/* server */ true);
}
}
void DesktopsModel::desktopDataChanged(const QString &id, const KWin::DBusDesktopDataStruct &data)
{
const int desktopIndex = m_serverSideDesktops.indexOf(id);
m_serverSideDesktops[desktopIndex] = id;
m_serverSideNames[id] = data.name;
// If the user didn't make any changes, we can just stay in sync.
if (!m_userModified) {
m_desktops = m_serverSideDesktops;
m_names = m_serverSideNames;
const QModelIndex &idx = index(desktopIndex, 0);
Q_EMIT dataChanged(idx, idx, QList<int>{Qt::DisplayRole});
} else {
updateModifiedState(/* server */ true);
}
}
void DesktopsModel::desktopRowsChanged(uint rows)
{
// Unfortunately we sometimes get this signal from the server with an unchanged value.
if ((int)rows == m_serverSideRows) {
return;
}
m_serverSideRows = rows;
// If the user didn't make any changes, we can just stay in sync.
if (!m_userModified) {
m_rows = m_serverSideRows;
Q_EMIT rowsChanged();
Q_EMIT dataChanged(index(0, 0), index(m_desktops.count() - 1, 0), QList<int>{DesktopRow});
} else {
updateModifiedState(/* server */ true);
}
}
void DesktopsModel::updateModifiedState(bool server)
{
// Count is the same but contents are not: The user may have
// removed and created new desktops in the UI, but there were
// no changes to send to the server because number and names
// have remained the same. In that case we can just clean
// that up here.
if (m_desktops.count() == m_serverSideDesktops.count()
&& m_desktops != m_serverSideDesktops) {
for (int i = 0; i < m_serverSideDesktops.count(); ++i) {
const QString oldId = m_desktops.at(i);
const QString &newId = m_serverSideDesktops.at(i);
m_desktops[i] = newId;
m_names[newId] = m_names.take(oldId);
}
Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), QList<int>{Qt::DisplayRole});
}
if (m_desktops == m_serverSideDesktops
&& m_names == m_serverSideNames
&& m_rows == m_serverSideRows) {
m_userModified = false;
Q_EMIT userModifiedChanged();
m_serverModified = false;
Q_EMIT serverModifiedChanged();
} else {
if (m_pendingCalls > 0) {
m_serverModified = false;
Q_EMIT serverModifiedChanged();
syncWithServer();
} else if (server) {
m_serverModified = true;
Q_EMIT serverModifiedChanged();
} else {
m_userModified = true;
Q_EMIT userModifiedChanged();
}
}
}
void DesktopsModel::handleCallError()
{
if (m_pendingCalls > 0) {
m_serverModified = false;
Q_EMIT serverModifiedChanged();
m_error = i18n("There was an error saving the settings to the compositor.");
Q_EMIT errorChanged();
} else {
m_error = i18n("There was an error requesting information from the compositor.");
Q_EMIT errorChanged();
}
}
}
#include "moc_desktopsmodel.cpp"
@@ -0,0 +1,125 @@
/*
SPDX-FileCopyrightText: 2018 Eike Hein <hein@kde.org>
SPDX-FileCopyrightText: 2018 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QAbstractListModel>
#include "virtualdesktopsdbustypes.h"
class QDBusArgument;
class QDBusMessage;
class QDBusServiceWatcher;
namespace KWin
{
/**
* @short An item model around KWin's D-Bus API for virtual desktops.
*
* The model initially gets the state from KWin and populates.
*
* As long as the user makes no changes, KWin-side changes are directly
* exposed in the model.
*
* If the user makes changes (see the `userModified` property), it stops
* exposing KWin-side changes live, but it keeps track of the KWin-side
* changes, so it can figure out and apply the delta when `syncWithServer`
* is called.
*
* When KWin-side changes happen while the model is user-modified, the
* model signals this via the `serverModified` property. A call to
* `syncWithServer` will overwrite the KWin-side changes.
*
* After synchronization, the model tracks Kwin-side changes again,
* until the user makes further changes.
*
* @author Eike Hein <hein@kde.org>
*/
class DesktopsModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(bool ready READ ready NOTIFY readyChanged)
Q_PROPERTY(QString error READ error NOTIFY errorChanged)
Q_PROPERTY(bool userModified READ userModified NOTIFY userModifiedChanged)
Q_PROPERTY(bool serverModified READ serverModified NOTIFY serverModifiedChanged)
Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
Q_PROPERTY(int desktopCount READ desktopCount NOTIFY desktopCountChanged)
public:
enum AdditionalRoles {
Id = Qt::UserRole + 1,
DesktopRow,
IsDefault,
};
Q_ENUM(AdditionalRoles)
explicit DesktopsModel(QObject *parent = nullptr);
~DesktopsModel() override;
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = {}) const override;
bool ready() const;
QString error() const;
bool userModified() const;
bool serverModified() const;
int rows() const;
void setRows(int rows);
int desktopCount() const;
QString createDesktopName() const;
Q_INVOKABLE void createDesktop();
Q_INVOKABLE void removeDesktop(const QString &id);
Q_INVOKABLE void setDesktopName(const QString &id, const QString &name);
Q_INVOKABLE void syncWithServer();
bool needsSave() const;
void load();
void defaults();
bool isDefaults() const;
Q_SIGNALS:
void readyChanged() const;
void errorChanged() const;
void userModifiedChanged() const;
void serverModifiedChanged() const;
void rowsChanged() const;
void desktopCountChanged();
protected Q_SLOTS:
void reset();
void getAllAndConnect(const QDBusMessage &msg);
void desktopCreated(const QString &id, const KWin::DBusDesktopDataStruct &data);
void desktopRemoved(const QString &id);
void desktopDataChanged(const QString &id, const KWin::DBusDesktopDataStruct &data);
void desktopRowsChanged(uint rows);
void updateModifiedState(bool server = false);
void handleCallError();
private:
QDBusServiceWatcher *m_serviceWatcher;
QString m_error;
bool m_userModified;
bool m_serverModified;
QStringList m_serverSideDesktops;
QHash<QString, QString> m_serverSideNames;
int m_serverSideRows;
QStringList m_desktops;
QHash<QString, QString> m_names;
int m_rows;
int m_pendingCalls = 0;
};
}
@@ -0,0 +1,143 @@
{
"Categories": "Qt;KDE;X-KDE-settings-translations;",
"KPlugin": {
"BugReportUrl": "https://bugs.kde.org/enter_bug.cgi?product=systemsettings&component=kcm_kwinvirtualdesktops",
"Description": "Configure navigation, number and layout of virtual desktops",
"Description[ar]": "اضبط عدد وتخطيط أسطح المكتب الافتراضية وكيفية التنقل بينها",
"Description[az]": "Virtual iş masalarının istiqamətini, sayını və maketini tənzimləyin",
"Description[be]": "Наладжванне навігацыі, колькасці і макета кампанавання віртуальных працоўных сталоў",
"Description[bg]": "Конфигуриране на навигация, брой и подредба на виртуални работни плотове",
"Description[ca@valencia]": "Configura la navegació, el nombre i la disposició dels escriptoris virtuals",
"Description[ca]": "Configura la navegació, el nombre i la disposició dels escriptoris virtuals",
"Description[cs]": "Nastavit ovládání, počet a rozvržení virtuálních pracovních ploch",
"Description[da]": "Konfigurér navigation, antal og layout af virtuelel skrivebord",
"Description[de]": "Navigation, Anzahl und Layout virtueller Arbeitsflächen einrichten",
"Description[en_GB]": "Configure navigation, number and layout of virtual desktops",
"Description[eo]": "Agordu navigadon, nombron kaj aranĝon de virtualaj labortabloj",
"Description[es]": "Configurar la navegación, el número y la disposición de los escritorios virtuales",
"Description[et]": "Virtuaalsete töölaudade vahel liikumise, nende arvu ja paigutuse seadistamine",
"Description[eu]": "Konfiguratu nabigatzea, alegiazko mahaigainen kopurua eta antolamendua",
"Description[fi]": "Virtuaalityöpöytien määrä-, asettelu- ja liikkumisasetukset",
"Description[fr]": "Configurer la navigation, le nombre et la disposition des bureaux virtuels",
"Description[gl]": "Configurar a navegación, cantidade e disposición dos escritorios virtuais.",
"Description[he]": "הגדרת ניווט, מספר ופריסת שולחנות עבודה וירטואליים",
"Description[hu]": "A virtuális asztalok számának, elrendezésének, és a köztük történő navigációnak a beállítása",
"Description[ia]": "Configura navigation, numero e disposition de scriptorios virtual",
"Description[id]": "Konfigurasikan navigasi, nomor dan tataletak desktop virtual",
"Description[is]": "Grunnstilla flettingu, fjölda og framsetningu sýndarskjáborða",
"Description[it]": "Configura navigazione, numero e disposizione dei desktop virtuali",
"Description[ja]": "仮想デスクトップの数、レイアウト、仮想デスクトップ間の移動を設定",
"Description[ka]": "ვირტუალური სამუშაო მაგიდებს რიცხვის, ნავიგაციისა და განლაგების მორგება",
"Description[ko]": "가상 바탕 화면 탐색, 개수, 레이아웃 설정",
"Description[lt]": "Konfigūruoti virtualių darbalaukių naršymą, skaičių ir išdėstymą",
"Description[lv]": "Konfigurēt virtuālo darbvirsmu navigāciju, skaitu un izvietojumu",
"Description[nb]": "Sett opp navigering, nummer og visning av virtuelle skrivebord",
"Description[nl]": "Navigatie, aantal en indeling van virtuele bureaubladen configureren",
"Description[nn]": "Set opp navigering, nummer og vising av virtuelle skrivebord",
"Description[pl]": "Ustawienia poruszania się, liczby oraz układu wirtualnych klawiatur",
"Description[pt]": "Configurar a navegação, o número e a disposição dos ecrãs virtuais",
"Description[pt_BR]": "Configura a navegação, quantidade e layout das áreas de trabalho virtuais",
"Description[ro]": "Configurează navigarea, numărul și aranjamentul birourilor virtuale",
"Description[ru]": "Число, расположение и способ переключения рабочих столов",
"Description[sa]": "वर्चुअल् डेस्कटॉप् इत्यस्य नेविगेशनं, संख्यां, लेआउट् च विन्यस्यताम्",
"Description[sk]": "Nastaviť navigáciu, počet a rozloženie virtuálnych plôch",
"Description[sl]": "Prilagodite krmarjenje, število in postavitev navideznih namizij",
"Description[sv]": "Anpassa navigering, antal och layout av virtuella skrivbord",
"Description[ta]": "பணிமேடைகளின் எண்ணிக்கை, தளவமைப்பு, மற்றும் அவற்றுக்கிடையேயான உலாவலை அமைக்கும்",
"Description[tr]": "Dolaşımı, sanal masaüstlerinin sayısını ve yerleşimini yapılandır",
"Description[uk]": "Налаштовування навігації, кількості та компонування віртуальних стільниць",
"Description[vi]": "Cấu hình điều hướng, số lượng và bố cục của các bàn làm việc ảo",
"Description[x-test]": "xxConfigure navigation, number and layout of virtual desktopsxx",
"Description[zh_CN]": "配置虚拟桌面的数量、排列方式和切换方式",
"Description[zh_TW]": "設定虛擬桌面的導覽、數量與佈局",
"FormFactors": [
"desktop"
],
"Icon": "preferences-desktop-virtual",
"Name": "Virtual Desktops",
"Name[ar]": "أسطح المكتب الافتراضية",
"Name[ast]": "Escritorios virtuales",
"Name[az]": "Virtual iş masaları",
"Name[be]": "Віртуальныя працоўныя сталы",
"Name[bg]": "Виртуални работни плотове",
"Name[ca@valencia]": "Escriptoris virtuals",
"Name[ca]": "Escriptoris virtuals",
"Name[cs]": "Virtuální plochy",
"Name[da]": "Virtuelle skriveborde",
"Name[de]": "Virtuelle Arbeitsflächen",
"Name[en_GB]": "Virtual Desktops",
"Name[eo]": "Virtualaj Labortabloj",
"Name[es]": "Escritorios virtuales",
"Name[et]": "Virtuaalsed töölauad",
"Name[eu]": "Alegiazko mahaigaina",
"Name[fi]": "Virtuaalityöpöydät",
"Name[fr]": "Bureaux virtuels",
"Name[gl]": "Escritorios virtuais",
"Name[he]": "שולחנות עבודה וירטואליים",
"Name[hu]": "Virtuális asztalok",
"Name[ia]": "Scriptorios virtual",
"Name[id]": "Desktop Virtual",
"Name[is]": "Sýndarskjáborð",
"Name[it]": "Desktop virtuali",
"Name[ja]": "仮想デスクトップ",
"Name[ka]": "ვირტუალური სამუშაო მაგიდები",
"Name[ko]": "가상 바탕 화면",
"Name[lt]": "Virtualūs darbalaukiai",
"Name[lv]": "Virtuālās darbvirsmas",
"Name[nb]": "Virtuelle skrivebord",
"Name[nl]": "Virtuele bureaubladen",
"Name[nn]": "Virtuelle skrivebord",
"Name[pl]": "Pulpity wirtualne",
"Name[pt]": "Ecrãs Virtuais",
"Name[pt_BR]": "Áreas de trabalho virtuais",
"Name[ro]": "Birouri virtuale",
"Name[ru]": "Виртуальные рабочие столы",
"Name[sa]": "आभासी डेस्कटॉप्स",
"Name[sk]": "Virtuálne pracovné plochy",
"Name[sl]": "Navidezna namizja",
"Name[sv]": "Virtuella skrivbord",
"Name[ta]": "மெய்நிகர் பணிமேடைகள்",
"Name[tr]": "Sanal Masaüstleri",
"Name[uk]": "Віртуальні стільниці",
"Name[vi]": "Bàn làm việc ảo",
"Name[x-test]": "xxVirtual Desktopsxx",
"Name[zh_CN]": "虚拟桌面",
"Name[zh_TW]": "虛擬桌面"
},
"X-DocPath": "kcontrol/desktop/index.html",
"X-KDE-Keywords": "desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,indicator,navigation,cube,slide,workspaces",
"X-KDE-Keywords[ar]": "سطح المكتب,أسطح المكتب,رقم,سطح المكتب الافتراضي,أسطح مكتب متعددة,جهاز استدعاء,أداة جهاز استدعاء,أداة صغيرة لجهاز استدعاء,إعدادات جهاز استدعاء,مؤشر,التنقل,مكعب,شريحة,مساحات عمل",
"X-KDE-Keywords[bg]": "работен плот,настолни компютри,номер,виртуален работен плот,множество настолни компютри,пейджър,уиджет за пейджър,аплет за пейджър,настройки на пейджър,индикатор,навигация,куб,слайд,работни пространства",
"X-KDE-Keywords[ca@valencia]": "escriptori,escriptoris,número,escriptori virtual,escriptoris múltiples,paginador,giny paginador,miniaplicació de paginador,configuració del paginador,indicador,navegació,cub,diapositiva,espais de treball",
"X-KDE-Keywords[ca]": "escriptori,escriptoris,número,escriptori virtual,escriptoris múltiples,paginador,giny paginador,miniaplicació de paginador,configuració del paginador,indicador,navegació,cub,diapositiva,espais de treball",
"X-KDE-Keywords[en_GB]": "desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,indicator,navigation,cube,slide,workspaces",
"X-KDE-Keywords[es]": "escritorio,escritorios,número,escritorio virtual,múltiples escritorios,paginador,widget del paginador,elemento gráfico del paginador,miniaplicación del paginador,preferencias del paginador,ajustes del paginador,indicador,navegación,cubo,deslizar,espacios de trabajo",
"X-KDE-Keywords[eu]": "mahaigaina,mahaigainak,zenbakia,alegiazko mahaigaina,mahaigain birtuala,mahaigain anizkoitzak,orrialdekatzailea,trepeta orrialdekatzailea,aplikaziotxo aldekatzailea,orrialdekatzailearen ezarpenak,adierazlea,nabigazioa,nabigatzea,kuboa,irristatu,labaindu,languneak",
"X-KDE-Keywords[fi]": "työpöytä,työpöydät,määrä,virtuaalityöpöytä,monta työpöytää,sivutin,sivutinsovelma,sivutus,sivutusasetukset,osoitin,navigointi,liikkuminen,kuutio,liuku,työtilat",
"X-KDE-Keywords[fr]": "bureau, bureaux, numéro, bureau virtuel, bureaux multiples,téléavertisseur, composant graphique de téléavertisseur, applet de téléavertisseur, paramètres de téléavertisseur,indicateur,navigation,cube,diapositive,espaces de travail",
"X-KDE-Keywords[gl]": "escritorio,escritorios,número,escritorio virtual,escritorios múltiplos,paxinador, trebello paxinador, miniaplicativo paxinador,configuración do paxinador,indicator,indicador,navigation,navegación,cube,cubo,slide,diapositiva,workspaces,espazos de traballo",
"X-KDE-Keywords[he]": "שולחן עבודה,שולחנות עבודה,דסקטופ,דסקטופים,שולחן עבודה וירטואלי,ריבוי שולחנות עבודה,דפדפן,וידג׳ט דפדפן,יישומון דפדוף,יישומונית דפדוף,הגדרות דפדפן,מחוון,ניווט,קובייה,שקופית,מרחבי עבודה",
"X-KDE-Keywords[hu]": "asztal,asztalok,szám,virtuális asztal,több asztal,lapozó,lapozó elem,lapozó kisalkalmazás,lapozóbeállítások,jelző,navigáció,kocka,csúszás,munkaterületek",
"X-KDE-Keywords[ia]": "scriptorio,scriptorios,numero,scriptorio virtual,scriptorio multiple,pager, widget de pager, applet de pager, preferentias de pager, indicator, navigation, cubo, glissamento, spatios de labor",
"X-KDE-Keywords[is]": "skjáborð,fjöldi,sýndarskjábroð,mörg skjáborð,flettir,flettigræja,flettismáforrit,stillinger flettis,vísir,flakk,teningur,renna,vinnusvæði",
"X-KDE-Keywords[it]": "desktop,desktop,numero,desktop virtuale,desktop multipli,selettore dei desktop,oggetto del selettore dei desktop,applet selettore dei desktop,impostazioni selettore dei desktop,indicatore,navigazione,cubo,diapositiva,aree di lavoro",
"X-KDE-Keywords[ka]": "desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,indicator,navigation,cube,slide,workspaces,სამუშაო მაგიდა,ვიჯეტები,ვირტუალური სამუშაო მაგიდა,რიცხვი,აპლეტები",
"X-KDE-Keywords[ko]": "데스크톱,바탕 화면,가상 바탕 화면,가상 데스크톱,호출기,호출기 위젯,호출기 애플릿,호출기 설정,표시기,탐색,큐브,슬라이드,작업 공간",
"X-KDE-Keywords[lv]": "darbvirsma,darbvirsmas,skaits,virtuālā darbvirsma,vairākas darbvirsmas,lapotājs,lapotāja logdaļa,lapotāja sīklietotne,lapotāja iestatījumi,indikators,navigācija,kubs,slīdnis,darbvietas",
"X-KDE-Keywords[nb]": "skrivebord,mengde,tall,virtuelt skrivebord,flere skrivebord,bytter,bytteelement,bytteinnstillinger,bytteoppsett,indikator,navigering,navigasjon,kube,gliding,arbeidsområde",
"X-KDE-Keywords[nl]": "bureaublad,bureaubladen,aantal,virtueel bureaublad,meerdere bureaubladen,pager,pager-widget,pager-applet,pager-instellingen,indicator,navigatie,kubus,dia,werkruimten",
"X-KDE-Keywords[nn]": "skrivebord,mengd,tal,virtuelt skrivebord,fleire skrivebord,vekslar,vekslarelement,vekslarelement,vekslerinnstillinger,vekslaroppsett,indikator,navigering,navigasjon,kube,gliding,arbeidsområde",
"X-KDE-Keywords[pl]": "pulpit,pulpity,liczba,pulpity wirtualne,wiele pulpitów,pager,element pagera,aplet pagera,ustawienia pagera,wskaźnik,poruszanie się,kostka,slajd,przestrzenie pracy",
"X-KDE-Keywords[pt_BR]": "área de trabalho,áreas de trabalho,número,área de trabalho virtual,múltiplas áreas de trabalho,paginador,widget de paginador,applet de paginador,configurações de paginador,indicador,navegação,cubo,deslizar,espaços de trabalho",
"X-KDE-Keywords[ru]": "desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,indicator,navigation,cube,slide,workspaces,рабочий стол,рабочие столы,число,виртуальный рабочий стол,несколько рабочих столов,переключатель рабочих столов,виджет переключателя рабочих столов,апплет переключателя рабочих столов,параметры переключения,настройка переключения,индикатор,навигация,куб,прокрутка,скольжение,рабочие пространства",
"X-KDE-Keywords[sa]": "डेस्कटॉप,डेस्कटॉप, संख्या, आभासी डेस्कटॉप,बहु डेस्कटॉप, पेजर, पेजर विजेट, पेजर एप्लेट, पेजर सेटिंग्स, सूचक, नेविगेशन, घन, स्लाइड, कार्यक्षेत्र",
"X-KDE-Keywords[sl]": "namizje,namizja,število,navidezno namizje,več namizij,pozivnik,pripomoček pozivnika,aplet pozivnika,nastavitve pozivnika,indikator,krmarjenje,kocka,diapozitiv,delovni prostori",
"X-KDE-Keywords[sv]": "skrivbord,nummer,virtuellt skrivbord,flera skrivbord,skrivbordsväljare,skrivbordsväljarkomponent, skrivbordsväljarminiprogram, skrivbordsväljarinställningar,indikator,navigering,kub,bild,arbetsytor",
"X-KDE-Keywords[tr]": "masaüstü,masaüstleri,sayı,numara,sanal masaüstü,çoklu masaüstleri,sayfalayıcı,araç takımı,uygulamacık,ayarlar,gösterge,dolaşım,gezinti,küp,kaydır,çalışma alanları",
"X-KDE-Keywords[uk]": "desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,indicator,navigation,cube,slide,workspaces,стільниця,стільниці,кількість,віртуальна стільниця,перемикач,пейджер,віджет перемикача,віджет пейджера,аплет перемикання,аплет перемикача,параметри перемикання,параметри перемикача,індикатор,навігація,куб,ковзання,слайд,простори",
"X-KDE-Keywords[x-test]": "xxdesktopxx,xxdesktopsxx,xxnumberxx,xxvirtual desktopxx,xxmultiple desktopsxx,xxpagerxx,xxpager widgetxx,xxpager appletxx,xxpager settingsxx,xxindicatorxx,xxnavigationxx,xxcubexx,xxslidexx,xxworkspacesxx",
"X-KDE-Keywords[zh_CN]": "desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,zhuomian,xunizhuomian,duozhuomian,qiehuan,xunizhuomianqiehuanqi,qiehuanqi,qiehuanqizujian,qiehuanqishezhi,zhishiqi,zhishise,tishiqi,tishise,daohang,fangkuai,zhengfangti,huadong,gongzuoqu,gongzuokongjian,桌面,虚拟桌面,多桌面,切换,虚拟桌面切换器,切换器,切换器组件,切换器设置,指示器,指示色,提示器,提示色,导航,方块,正方体,滑动,工作区,工作空间",
"X-KDE-Keywords[zh_TW]": "桌面,虛擬桌面,桌面管理器,虛擬桌面管理器,指示器,瀏覽,工作空間",
"X-KDE-System-Settings-Parent-Category": "windowmanagement",
"X-KDE-Weight": 60
}
@@ -0,0 +1,335 @@
/*
SPDX-FileCopyrightText: 2018 Eike Hein <hein@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kcmutils as KCM
import org.kde.kirigami 2.20 as Kirigami
KCM.ScrollViewKCM {
id: root
implicitWidth: Kirigami.Units.gridUnit * 35
implicitHeight: Kirigami.Units.gridUnit * 30
actions: [
Kirigami.Action {
displayComponent: RowLayout {
spacing: Kirigami.Units.smallSpacing
QQC2.Label {
text: i18nc("@text:label Number of rows, label associated to a number input field", "Rows:")
}
QQC2.SpinBox {
id: rowsSpinBox
from: 1
to: 20
editable: true
value: kcm.desktopsModel.rows
onValueModified: kcm.desktopsModel.rows = value
KCM.SettingHighlighter {
highlight: kcm.desktopsModel.rows !== 2
}
Connections {
target: kcm.desktopsModel
function onReadyChanged() {
rowsSpinBox.value = kcm.desktopsModel.rows;
}
function onRowsChanged() {
rowsSpinBox.value = kcm.desktopsModel.rows;
}
}
}
}
},
Kirigami.Action {
text: i18nc("@action:button", "Add Desktop")
icon.name: "list-add"
displayHint: Kirigami.DisplayHint.KeepVisible
onTriggered: kcm.desktopsModel.createDesktop()
}
]
Component {
id: desktopsListItemComponent
QQC2.ItemDelegate {
width: ListView.view.width
down: false // Disable press effect
hoverEnabled: false
// use alternating background colors to visually connect list items'
// left and right side content elements
Kirigami.Theme.useAlternateBackgroundColor: true
contentItem: RowLayout {
QQC2.TextField {
id: nameField
background: null
leftPadding: Kirigami.Units.largeSpacing
topPadding: 0
bottomPadding: 0
Layout.fillWidth: true
Layout.fillHeight: true
text: model ? model.display : ""
verticalAlignment: Text.AlignVCenter
readOnly: true
onTextEdited: {
Qt.callLater(kcm.desktopsModel.setDesktopName, model.Id, text);
}
onEditingFinished: {
readOnly = true;
}
MouseArea {
anchors.fill: parent
enabled: nameField.readOnly
onDoubleClicked: {
renameAction.clicked();
}
}
}
Rectangle {
id: defaultIndicator
radius: width * 0.5
implicitWidth: Kirigami.Units.largeSpacing
implicitHeight: Kirigami.Units.largeSpacing
visible: kcm.defaultsIndicatorsVisible
opacity: model ? !model.IsDefault : 0.0
color: Kirigami.Theme.neutralTextColor
}
DelegateButton {
id: renameAction
enabled: model && !model.IsMissing
visible: !applyAction.visible
icon.name: "edit-rename"
text: i18nc("@info:tooltip", "Rename")
onClicked: {
nameField.readOnly = false;
nameField.selectAll();
nameField.forceActiveFocus();
}
}
DelegateButton {
id: applyAction
visible: !nameField.readOnly
icon.name: "dialog-ok-apply"
text: i18nc("@info:tooltip", "Confirm new name")
onClicked: {
nameField.readOnly = true;
}
}
DelegateButton {
enabled: model && !model.IsMissing && desktopsList.count !== 1
icon.name: "edit-delete-remove-symbolic"
text: i18nc("@info:tooltip", "Remove")
onClicked: kcm.desktopsModel.removeDesktop(model.Id)
}
}
}
}
component DelegateButton: QQC2.ToolButton {
display: QQC2.AbstractButton.IconOnly
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
}
header: ColumnLayout {
id: messagesLayout
spacing: Kirigami.Units.largeSpacing
Kirigami.InlineMessage {
Layout.fillWidth: true
type: Kirigami.MessageType.Error
text: kcm.desktopsModel.error
visible: kcm.desktopsModel.error !== ""
}
Kirigami.InlineMessage {
Layout.fillWidth: true
type: Kirigami.MessageType.Information
text: i18n("Virtual desktops have been changed outside this settings application. Saving now will overwrite the changes.")
visible: kcm.desktopsModel.serverModified
}
}
view: ListView {
id: desktopsList
clip: true
model: kcm.desktopsModel.ready ? kcm.desktopsModel : null
section.property: "DesktopRow"
section.delegate: Kirigami.ListSectionHeader {
width: desktopsList.width
label: i18n("Row %1", section)
}
delegate: desktopsListItemComponent
reuseItems: true
}
extraFooterTopPadding: true // re-add separator line
footer: ColumnLayout {
Kirigami.FormLayout {
QQC2.CheckBox {
id: navWraps
Kirigami.FormData.label: i18n("Options:")
text: i18n("Navigation wraps around")
enabled: !kcm.virtualDesktopsSettings.isImmutable("rollOverDesktops")
checked: kcm.virtualDesktopsSettings.rollOverDesktops
onToggled: kcm.virtualDesktopsSettings.rollOverDesktops = checked
KCM.SettingStateBinding {
configObject: kcm.virtualDesktopsSettings
settingName: "rollOverDesktops"
}
}
RowLayout {
Layout.fillWidth: true
QQC2.CheckBox {
id: animationEnabled
Layout.fillWidth: true
text: i18n("Show animation when switching:")
checked: kcm.animationsModel.animationEnabled
onToggled: kcm.animationsModel.animationEnabled = checked
KCM.SettingHighlighter {
highlight: kcm.animationsModel.animationEnabled !== kcm.animationsModel.defaultAnimationEnabled
}
}
QQC2.ComboBox {
enabled: animationEnabled.checked
model: kcm.animationsModel
textRole: "NameRole"
currentIndex: kcm.animationsModel.animationIndex
onActivated: kcm.animationsModel.animationIndex = currentIndex
KCM.SettingHighlighter {
highlight: kcm.animationsModel.animationIndex !== kcm.animationsModel.defaultAnimationIndex
}
}
QQC2.Button {
enabled: animationEnabled.checked && kcm.animationsModel.currentConfigurable
icon.name: "configure"
onClicked: kcm.configureAnimation()
}
QQC2.Button {
enabled: animationEnabled.checked
icon.name: "dialog-information"
onClicked: kcm.showAboutAnimation()
}
Item {
Layout.fillWidth: true
}
}
RowLayout {
Layout.fillWidth: true
QQC2.CheckBox {
id: osdEnabled
text: i18n("Show on-screen display when switching:")
checked: kcm.virtualDesktopsSettings.desktopChangeOsdEnabled
onToggled: kcm.virtualDesktopsSettings.desktopChangeOsdEnabled = checked
KCM.SettingStateBinding {
configObject: kcm.virtualDesktopsSettings
settingName: "desktopChangeOsdEnabled"
}
}
QQC2.SpinBox {
id: osdDuration
from: 0
to: 10000
stepSize: 100
textFromValue: (value, locale) => i18n("%1 ms", value)
valueFromText: (text, locale) => Number.fromLocaleString(locale, text.split(" ")[0])
value: kcm.virtualDesktopsSettings.popupHideDelay
onValueModified: kcm.virtualDesktopsSettings.popupHideDelay = value
KCM.SettingStateBinding {
configObject: kcm.virtualDesktopsSettings
settingName: "popupHideDelay"
extraEnabledConditions: osdEnabled.checked
}
}
}
RowLayout {
Layout.fillWidth: true
Item {
Layout.preferredWidth: Kirigami.Units.gridUnit
}
QQC2.CheckBox {
id: osdTextOnly
text: i18n("Show desktop layout indicators")
checked: !kcm.virtualDesktopsSettings.textOnly
onToggled: kcm.virtualDesktopsSettings.textOnly = !checked
KCM.SettingStateBinding {
configObject: kcm.virtualDesktopsSettings
settingName: "textOnly"
extraEnabledConditions: osdEnabled.checked
}
}
}
}
}
}
@@ -0,0 +1,165 @@
/*
SPDX-FileCopyrightText: 2018 Eike Hein <hein@kde.org>
SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "virtualdesktops.h"
#include "animationsmodel.h"
#include "desktopsmodel.h"
#include "virtualdesktopsdata.h"
#include "virtualdesktopssettings.h"
#include <KAboutApplicationDialog>
#include <KAboutData>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KPluginFactory>
#include <QDBusConnection>
#include <QDBusMessage>
K_PLUGIN_FACTORY_WITH_JSON(VirtualDesktopsFactory,
"kcm_kwin_virtualdesktops.json",
registerPlugin<KWin::VirtualDesktops>();
registerPlugin<KWin::VirtualDesktopsData>();)
namespace KWin
{
VirtualDesktops::VirtualDesktops(QObject *parent, const KPluginMetaData &metaData)
: KQuickManagedConfigModule(parent, metaData)
, m_data(new VirtualDesktopsData(this))
{
qmlRegisterAnonymousType<VirtualDesktopsSettings>("org.kde.kwin.kcm.desktop", 0);
setButtons(Apply | Default | Help);
QObject::connect(m_data->desktopsModel(), &KWin::DesktopsModel::userModifiedChanged,
this, &VirtualDesktops::settingsChanged);
connect(m_data->animationsModel(), &AnimationsModel::animationEnabledChanged,
this, &VirtualDesktops::settingsChanged);
connect(m_data->animationsModel(), &AnimationsModel::animationIndexChanged,
this, &VirtualDesktops::settingsChanged);
}
VirtualDesktops::~VirtualDesktops()
{
}
QAbstractItemModel *VirtualDesktops::desktopsModel() const
{
return m_data->desktopsModel();
}
QAbstractItemModel *VirtualDesktops::animationsModel() const
{
return m_data->animationsModel();
}
VirtualDesktopsSettings *VirtualDesktops::virtualDesktopsSettings() const
{
return m_data->settings();
}
void VirtualDesktops::load()
{
KQuickManagedConfigModule::load();
m_data->desktopsModel()->load();
m_data->animationsModel()->load();
}
void VirtualDesktops::save()
{
KQuickManagedConfigModule::save();
m_data->desktopsModel()->syncWithServer();
m_data->animationsModel()->save();
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"));
QDBusConnection::sessionBus().send(message);
}
void VirtualDesktops::defaults()
{
KQuickManagedConfigModule::defaults();
m_data->desktopsModel()->defaults();
m_data->animationsModel()->defaults();
}
bool VirtualDesktops::isDefaults() const
{
return m_data->isDefaults();
}
void VirtualDesktops::configureAnimation()
{
const QModelIndex index = m_data->animationsModel()->index(m_data->animationsModel()->animationIndex(), 0);
if (!index.isValid()) {
return;
}
m_data->animationsModel()->requestConfigure(index, nullptr);
}
void VirtualDesktops::showAboutAnimation()
{
const QModelIndex index = m_data->animationsModel()->index(m_data->animationsModel()->animationIndex(), 0);
if (!index.isValid()) {
return;
}
const QString name = index.data(AnimationsModel::NameRole).toString();
const QString comment = index.data(AnimationsModel::DescriptionRole).toString();
const QString author = index.data(AnimationsModel::AuthorNameRole).toString();
const QString email = index.data(AnimationsModel::AuthorEmailRole).toString();
const QString website = index.data(AnimationsModel::WebsiteRole).toString();
const QString version = index.data(AnimationsModel::VersionRole).toString();
const QString license = index.data(AnimationsModel::LicenseRole).toString();
const QString icon = index.data(AnimationsModel::IconNameRole).toString();
const KAboutLicense::LicenseKey licenseType = KAboutLicense::byKeyword(license).key();
KAboutData aboutData(
name, // Plugin name
name, // Display name
version, // Version
comment, // Short description
licenseType, // License
QString(), // Copyright statement
QString(), // Other text
website.toLatin1() // Home page
);
aboutData.setProgramLogo(icon);
const QStringList authors = author.split(',');
const QStringList emails = email.split(',');
if (authors.count() == emails.count()) {
int i = 0;
for (const QString &author : authors) {
if (!author.isEmpty()) {
aboutData.addAuthor(i18n(author.toUtf8()), QString(), emails[i]);
}
i++;
}
}
QPointer<KAboutApplicationDialog> aboutPlugin = new KAboutApplicationDialog(aboutData);
aboutPlugin->exec();
delete aboutPlugin;
}
bool VirtualDesktops::isSaveNeeded() const
{
return m_data->animationsModel()->needsSave() || m_data->desktopsModel()->needsSave();
}
}
#include "moc_virtualdesktops.cpp"
#include "virtualdesktops.moc"
@@ -0,0 +1,55 @@
/*
SPDX-FileCopyrightText: 2018 Eike Hein <hein@kde.org>
SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <KQuickManagedConfigModule>
#include <KSharedConfig>
#include <QAbstractItemModel>
class VirtualDesktopsSettings;
namespace KWin
{
class VirtualDesktopsData;
class AnimationsModel;
class DesktopsModel;
class VirtualDesktops : public KQuickManagedConfigModule
{
Q_OBJECT
Q_PROPERTY(QAbstractItemModel *desktopsModel READ desktopsModel CONSTANT)
Q_PROPERTY(QAbstractItemModel *animationsModel READ animationsModel CONSTANT)
Q_PROPERTY(VirtualDesktopsSettings *virtualDesktopsSettings READ virtualDesktopsSettings CONSTANT)
public:
explicit VirtualDesktops(QObject *parent, const KPluginMetaData &metaData);
~VirtualDesktops() override;
QAbstractItemModel *desktopsModel() const;
QAbstractItemModel *animationsModel() const;
VirtualDesktopsSettings *virtualDesktopsSettings() const;
bool isDefaults() const override;
bool isSaveNeeded() const override;
public Q_SLOTS:
void load() override;
void save() override;
void defaults() override;
void configureAnimation();
void showAboutAnimation();
private:
VirtualDesktopsData *m_data;
};
}
@@ -0,0 +1,54 @@
/*
SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "virtualdesktopsdata.h"
#include "animationsmodel.h"
#include "desktopsmodel.h"
#include "virtualdesktopssettings.h"
namespace KWin
{
VirtualDesktopsData::VirtualDesktopsData(QObject *parent)
: KCModuleData(parent)
, m_settings(new VirtualDesktopsSettings(this))
, m_desktopsModel(new DesktopsModel(this))
, m_animationsModel(new AnimationsModel(this))
{
// Default behavior of KCModuleData is to emit loaded signal after being initialized.
// To handle asynchronous load of EffectsModel we disable default behavior and
// emit loaded signal when EffectsModel is actually loaded.
disconnect(this, &KCModuleData::aboutToLoad, nullptr, nullptr);
connect(m_animationsModel, &EffectsModel::loaded, this, &KCModuleData::loaded);
m_desktopsModel->load();
m_animationsModel->load();
}
bool VirtualDesktopsData::isDefaults() const
{
return m_animationsModel->isDefaults() && m_desktopsModel->isDefaults() && m_settings->isDefaults();
}
VirtualDesktopsSettings *VirtualDesktopsData::settings() const
{
return m_settings;
}
DesktopsModel *VirtualDesktopsData::desktopsModel() const
{
return m_desktopsModel;
}
AnimationsModel *VirtualDesktopsData::animationsModel() const
{
return m_animationsModel;
}
}
#include "moc_virtualdesktopsdata.cpp"
@@ -0,0 +1,40 @@
/*
SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QObject>
#include <KCModuleData>
class VirtualDesktopsSettings;
namespace KWin
{
class AnimationsModel;
class DesktopsModel;
class VirtualDesktopsData : public KCModuleData
{
Q_OBJECT
public:
explicit VirtualDesktopsData(QObject *parent);
bool isDefaults() const override;
VirtualDesktopsSettings *settings() const;
DesktopsModel *desktopsModel() const;
AnimationsModel *animationsModel() const;
private:
VirtualDesktopsSettings *m_settings;
DesktopsModel *m_desktopsModel;
AnimationsModel *m_animationsModel;
};
}
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 name="kwinrc"/>
<group name="Windows">
<entry name="rollOverDesktops" key="RollOverDesktops" type="bool">
<label>Whether or not, we circle through the virtual desktop when moving from one to the next</label>
<default>false</default>
</entry>
</group>
<group name="Plugins">
<entry name="desktopChangeOsdEnabled" key="desktopchangeosdEnabled" type="bool">
<label>Display in an OSD the virtual desktop name when switching between virtual desktops</label>
<default>false</default>
</entry>
</group>
<group name="Script-desktopchangeosd">
<entry name="popupHideDelay" key="PopupHideDelay" type="int">
<label>Duraton of the OSD</label>
<default>1000</default>
</entry>
<entry name="textOnly" key="TextOnly" type="bool">
<label>Whether or not to display desktop layout in the OSD</label>
<default>false</default>
</entry>
</group>
</kcfg>
@@ -0,0 +1,6 @@
File=virtualdesktopssettings.kcfg
ClassName=VirtualDesktopsSettings
Mutators=true
DefaultValueGetters=true
GenerateProperties=true
ParentInConstructor=true
@@ -0,0 +1,27 @@
# KI18N Translation Domain for this library.
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_kwin_effects\")
########### next target ###############
set(kcm_kwin_effects_PART_SRCS
kcm.cpp
effectsfilterproxymodel.cpp
desktopeffectsdata.cpp
)
kcmutils_add_qml_kcm(kcm_kwin_effects SOURCES ${kcm_kwin_effects_PART_SRCS})
target_link_libraries(kcm_kwin_effects PRIVATE
Qt::DBus
Qt::Quick
KF6::KCMUtils
KF6::I18n
KF6::KCMUtils
KF6::KCMUtilsQuick
KF6::XmlGui
kcmkwincommon
)
install(FILES kwineffect.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR})
@@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT `find . -name \*.cpp -o -name \*.qml` -o $podir/kcm_kwin_effects.pot
@@ -0,0 +1,35 @@
/*
SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "desktopeffectsdata.h"
#include "effectsmodel.h"
namespace KWin
{
DesktopEffectsData::DesktopEffectsData(QObject *parent)
: KCModuleData(parent)
, m_model(new EffectsModel(this))
{
disconnect(this, &KCModuleData::aboutToLoad, nullptr, nullptr);
connect(m_model, &EffectsModel::loaded, this, &KCModuleData::loaded);
m_model->load();
}
DesktopEffectsData::~DesktopEffectsData()
{
}
bool DesktopEffectsData::isDefaults() const
{
return m_model->isDefaults();
}
}
#include "moc_desktopeffectsdata.cpp"
@@ -0,0 +1,31 @@
/*
SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QObject>
#include <KCModuleData>
namespace KWin
{
class EffectsModel;
class DesktopEffectsData : public KCModuleData
{
Q_OBJECT
public:
explicit DesktopEffectsData(QObject *parent);
~DesktopEffectsData() override;
bool isDefaults() const override;
private:
EffectsModel *m_model;
};
}
@@ -0,0 +1,73 @@
/*
SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "effectsfilterproxymodel.h"
#include "effectsmodel.h"
namespace KWin
{
EffectsFilterProxyModel::EffectsFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}
EffectsFilterProxyModel::~EffectsFilterProxyModel()
{
}
QString EffectsFilterProxyModel::query() const
{
return m_query;
}
void EffectsFilterProxyModel::setQuery(const QString &query)
{
if (m_query != query) {
m_query = query;
Q_EMIT queryChanged();
invalidateFilter();
}
}
bool EffectsFilterProxyModel::excludeUnsupported() const
{
return m_excludeUnsupported;
}
void EffectsFilterProxyModel::setExcludeUnsupported(bool exclude)
{
if (m_excludeUnsupported != exclude) {
m_excludeUnsupported = exclude;
Q_EMIT excludeUnsupportedChanged();
invalidateFilter();
}
}
bool EffectsFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
const QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent);
if (!m_query.isEmpty()) {
const bool matches = idx.data(EffectsModel::NameRole).toString().contains(m_query, Qt::CaseInsensitive) || idx.data(EffectsModel::DescriptionRole).toString().contains(m_query, Qt::CaseInsensitive) || idx.data(EffectsModel::CategoryRole).toString().contains(m_query, Qt::CaseInsensitive);
if (!matches) {
return false;
}
}
if (m_excludeUnsupported) {
if (!idx.data(EffectsModel::SupportedRole).toBool()) {
return false;
}
}
return true;
}
} // namespace KWin
#include "moc_effectsfilterproxymodel.cpp"
@@ -0,0 +1,45 @@
/*
SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QSortFilterProxyModel>
namespace KWin
{
class EffectsFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(QAbstractItemModel *sourceModel READ sourceModel WRITE setSourceModel)
Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
Q_PROPERTY(bool excludeUnsupported READ excludeUnsupported WRITE setExcludeUnsupported NOTIFY excludeUnsupportedChanged)
public:
explicit EffectsFilterProxyModel(QObject *parent = nullptr);
~EffectsFilterProxyModel() override;
QString query() const;
void setQuery(const QString &query);
bool excludeUnsupported() const;
void setExcludeUnsupported(bool exclude);
Q_SIGNALS:
void queryChanged();
void excludeUnsupportedChanged();
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
private:
QString m_query;
bool m_excludeUnsupported = true;
Q_DISABLE_COPY(EffectsFilterProxyModel)
};
} // namespace KWin
@@ -0,0 +1,92 @@
/*
SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kcm.h"
#include "desktopeffectsdata.h"
#include "effectsfilterproxymodel.h"
#include "effectsmodel.h"
#include <KLocalizedString>
#include <KPluginFactory>
#include <QQuickWindow>
#include <QWindow>
K_PLUGIN_FACTORY_WITH_JSON(DesktopEffectsKCMFactory,
"kcm_kwin_effects.json",
registerPlugin<KWin::DesktopEffectsKCM>();
registerPlugin<KWin::DesktopEffectsData>();)
namespace KWin
{
DesktopEffectsKCM::DesktopEffectsKCM(QObject *parent, const KPluginMetaData &metaData)
: KQuickConfigModule(parent, metaData)
, m_model(new EffectsModel(this))
{
qmlRegisterType<EffectsFilterProxyModel>("org.kde.private.kcms.kwin.effects", 1, 0, "EffectsFilterProxyModel");
setButtons(Apply | Default | Help);
connect(m_model, &EffectsModel::dataChanged, this, &DesktopEffectsKCM::updateNeedsSave);
connect(m_model, &EffectsModel::loaded, this, &DesktopEffectsKCM::updateNeedsSave);
}
DesktopEffectsKCM::~DesktopEffectsKCM()
{
}
QAbstractItemModel *DesktopEffectsKCM::effectsModel() const
{
return m_model;
}
void DesktopEffectsKCM::load()
{
m_model->load();
setNeedsSave(false);
}
void DesktopEffectsKCM::save()
{
m_model->save();
setNeedsSave(false);
}
void DesktopEffectsKCM::defaults()
{
m_model->defaults();
updateNeedsSave();
}
void DesktopEffectsKCM::onGHNSEntriesChanged()
{
m_model->load(EffectsModel::LoadOptions::KeepDirty);
}
void DesktopEffectsKCM::configure(const QString &pluginId, QQuickItem *context)
{
const QModelIndex index = m_model->findByPluginId(pluginId);
QWindow *transientParent = nullptr;
if (context && context->window()) {
transientParent = context->window();
}
m_model->requestConfigure(index, transientParent);
}
void DesktopEffectsKCM::updateNeedsSave()
{
setNeedsSave(m_model->needsSave());
setRepresentsDefaults(m_model->isDefaults());
}
} // namespace KWin
#include "kcm.moc"
#include "moc_kcm.cpp"
@@ -0,0 +1,47 @@
/*
SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <KQuickConfigModule>
#include <QAbstractItemModel>
#include <QQuickItem>
namespace KWin
{
class EffectsModel;
class DesktopEffectsKCM : public KQuickConfigModule
{
Q_OBJECT
Q_PROPERTY(QAbstractItemModel *effectsModel READ effectsModel CONSTANT)
public:
explicit DesktopEffectsKCM(QObject *parent, const KPluginMetaData &metaData);
~DesktopEffectsKCM() override;
QAbstractItemModel *effectsModel() const;
public Q_SLOTS:
void load() override;
void save() override;
void defaults() override;
void onGHNSEntriesChanged();
void configure(const QString &pluginId, QQuickItem *context);
private Q_SLOTS:
void updateNeedsSave();
private:
EffectsModel *m_model;
Q_DISABLE_COPY(DesktopEffectsKCM)
};
} // namespace KWin
@@ -0,0 +1,135 @@
{
"KPlugin": {
"BugReportUrl": "https://bugs.kde.org/enter_bug.cgi?product=systemsettings&component=kcm_kwineffects",
"Description": "Configure compositor settings for desktop effects",
"Description[ar]": "اضبط إعدادات المركب لتأثيرات سطح المكتب",
"Description[az]": "İş masası effektləri üçün düzücünün ayarlarını tənzimləyin",
"Description[be]": "Наладжванне сродку кампазітынгу для эфектаў працоўнага стала",
"Description[bg]": "Конфигуриране на настройките на композитора за ефекти на работния плот",
"Description[ca@valencia]": "Configura la configuració del compositor per als efectes de l'escriptori",
"Description[ca]": "Configura l'arranjament del compositor per als efectes d'escriptori",
"Description[cs]": "Nastavení kompozitoru pro efekty pracovní plochy",
"Description[da]": "Konfigurér kompositørindstillinger for skrivebordseffekter",
"Description[de]": "Compositor-Einstellungen für Arbeitsflächen-Effekte einrichten",
"Description[en_GB]": "Configure compositor settings for desktop effects",
"Description[eo]": "Agordi kompostajn agordojn por labortablaj efikoj",
"Description[es]": "Configurar las preferencias del compositor para los efectos del escritorio",
"Description[et]": "Komposiitori seadistamine töölauaefektide tarbeks",
"Description[eu]": "Konfiguratu konposatzailearen ezarpenak mahaigaineko efektuetarako",
"Description[fi]": "Koostamisasetukset työpöytätehosteille",
"Description[fr]": "Configurer les paramètres du compositeur pour les effets de bureau",
"Description[gl]": "Configurar o compositor para os efectos de escritorio.",
"Description[he]": "הגדרת אפקטים של שולחן עבודה בהגדרות המנהל החלונאי",
"Description[hu]": "A kompozitor beállításainak konfigurálása az asztali effektusokhoz",
"Description[ia]": "Configura preferentias de compositor pro le effectos de scriptorio",
"Description[id]": "Konfigurasikan pengaturan kompositor untuk efek desktop",
"Description[is]": "Grunnstilla myndsmiðsstillingar fyrir skjáborðsbrellur",
"Description[it]": "Configura impostazioni del compositore per gli effetti del desktop",
"Description[ja]": "デスクトップ効果のためのコンポジタ設定",
"Description[ka]": "კომპოზიტორის მორგება სამუშაო მაგიდის ეფექტებისთვის",
"Description[ko]": "데스크톱 효과에 사용되는 컴포지터 설정",
"Description[lt]": "Konfigūruoti darbalaukio efektams skirtas kompozitoriaus nuostatas",
"Description[lv]": "Konfigurēt kompozitora iestatījumus darbvirsmas efektiem",
"Description[nb]": "Sett opp sammensetterinnstillinger for skrivebordseffekter",
"Description[nl]": "Instellingen van compositor configureren voor bureaubladeffecten",
"Description[nn]": "Samansetjarinnstillingar for skrivebordseffektar",
"Description[pl]": "Ustawienia kompozytora dla efektów pulpitu",
"Description[pt]": "Configurar as definições dos efeitos do ecrã do compositor",
"Description[pt_BR]": "Defina as configurações do compositor para os efeitos da área de trabalho",
"Description[ro]": "Configurează opțiunile compozitorului pentru efecte de birou",
"Description[ru]": "Настройка модуля обеспечения эффектов рабочего стола",
"Description[sa]": "डेस्कटॉप् इफेक्ट्स् कृते कम्पोजिटर सेटिंग्स् विन्यस्यताम्",
"Description[sk]": "Nastavenia kompozítora pre efekty plochy",
"Description[sl]": "Prilagodite nastavitve skladanja za učinke namizja",
"Description[sv]": "Anpassa sammansättningsinställningar för skrivbordseffekter",
"Description[ta]": "பணிமேடை அசைவூட்டங்களுக்கான சாளரநிரல் அமைப்புகளை மாற்றுங்கள்",
"Description[tr]": "Masaüstü efektleri için bileşikleştirici ayarlarını yapılandır",
"Description[uk]": "Налаштовування параметрів засобу композиції для ефектів стільниці",
"Description[vi]": "Cấu hình các thiết lập trình kết hợp cho các hiệu ứng bàn làm việc",
"Description[x-test]": "xxConfigure compositor settings for desktop effectsxx",
"Description[zh_CN]": "配置桌面的显示特效合成器设置",
"Description[zh_TW]": "設定合成器的桌面效果選項",
"FormFactors": [
"desktop",
"tablet"
],
"Icon": "preferences-desktop-effects",
"Name": "Desktop Effects",
"Name[ar]": "تأثيرات سطح المكتب",
"Name[az]": "İş masası effektləri",
"Name[be]": "Эфекты працоўнага стала",
"Name[bg]": "Ефекти на работния плот",
"Name[ca@valencia]": "Efectes de l'escriptori",
"Name[ca]": "Efectes d'escriptori",
"Name[cs]": "Efekty na ploše",
"Name[da]": "Skrivebordseffekter",
"Name[de]": "Arbeitsflächen-Effekte",
"Name[en_GB]": "Desktop Effects",
"Name[eo]": "Labortablo-Efikoj",
"Name[es]": "Efectos del escritorio",
"Name[et]": "Töölauaefektid",
"Name[eu]": "Mahaigaineko efektuak",
"Name[fi]": "Työpöytätehosteet",
"Name[fr]": "Effets de bureau",
"Name[gl]": "Efectos de escritorio",
"Name[he]": "אפקטים של שולחן עבודה",
"Name[hu]": "Asztali effektusok",
"Name[ia]": "Effectos de scriptorio",
"Name[id]": "Efek Desktop",
"Name[is]": "Skjáborðsbrellur",
"Name[it]": "Effetti del desktop",
"Name[ja]": "デスクトップ効果",
"Name[ka]": "სამუშაო მაგიდის ეფექტები",
"Name[ko]": "데스크톱 효과",
"Name[lt]": "Darbalaukio efektai",
"Name[lv]": "Darbvirsmu efekti",
"Name[nb]": "Skrivebordseffekter",
"Name[nl]": "Bureaubladeffecten",
"Name[nn]": "Skrivebords­effektar",
"Name[pl]": "Efekty pulpitu",
"Name[pt]": "Efeitos do Ecrã",
"Name[pt_BR]": "Efeitos da área de trabalho",
"Name[ro]": "Efecte de birou",
"Name[ru]": "Эффекты рабочего стола",
"Name[sa]": "डेस्कटॉप प्रभाव",
"Name[sk]": "Efekty plochy",
"Name[sl]": "Namizni učinki",
"Name[sv]": "Skrivbordseffekter",
"Name[ta]": "பணிமேடை அசைவூட்டங்கள்",
"Name[tr]": "Masaüstü Efektleri",
"Name[uk]": "Ефекти стільниці",
"Name[vi]": "Hiệu ứng bàn làm việc",
"Name[x-test]": "xxDesktop Effectsxx",
"Name[zh_CN]": "桌面特效",
"Name[zh_TW]": "桌面效果"
},
"X-DocPath": "kcontrol/kwineffects/index.html",
"X-KDE-Keywords": "kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,background contrast effect,bling,fading,movement,motion,overview windows effect,accessibility,cursor,pointer,mouse,hide cursor,hide cursor effect,hide pointer,hide pointer effect,hide mouse,hide mouse effect",
"X-KDE-Keywords[ar]": "كوين،نافذة،مدير،تأثير،تأثيرات ثلاثية الأبعاد،تأثيرات ثنائية الأبعاد،تأثيرات رسومية،تأثيرات سطح المكتب،رسوم متحركة،رسوم متحركة مختلفة،تأثيرات إدارة النوافذ،تأثير تبديل النوافذ،تأثير تبديل سطح المكتب،رسوم متحركة،رسوم متحركة لسطح المكتب،برامج تشغيل،إعدادات برنامج التشغيل،عرض،عرض ,تأثير عكسي,تأثير الزجاج,تأثير المكبر,تأثير مساعد المفاجئة,تأثير الفأرة المسار,تأثير التكبير/التصغير,تأثير التمويه,تأثير التلاشي,تأثير تلاشي سطح المكتب,تأثير الانهيار,تأثير الانزلاق,تأثير النافذة المميزة,تأثير تسجيل الدخول,تأثير تسجيل الخروج,سحر تأثير المصباح,تقليل تأثير الحركة,تأثير علامة الفأرة,تأثير المقياس,تأثير لقطة الشاشة,تأثير الورقة,تأثير الشريحة,تأثير النوافذ المنبثقة المنزلقة,تأثير الصورة المصغرة جانبًا,الشفافية,تأثير الشفافية,الشفافية,تأثير هندسة النافذة,تأثير النوافذ المتذبذبة,تأثير ردود الفعل عند بدء التشغيل,تأثير الحوار الأصلي,تأثير خافت غير نشط,تأثير الشاشة الخافت,تأثير الشريحة الخلفية,العين حلوى,حلوى,إظهار تأثير FPS,إظهار تأثير الطلاء,تأثير تبديل الغطاء,تأثير مكعب سطح المكتب,تأثير رسوم متحركة لمكعب سطح المكتب,تأثير شبكة سطح المكتب,تأثير تبديل,تأثير تباين الخلفية,بريق,بهتان,حركة,حركة,تأثير نظرة عامة على النوافذ,إمكانية الوصول,مؤشر,مؤشر,فأر,إخفاء المؤشر,إخفاء تأثير المؤشر,إخفاء المؤشر,إخفاء تأثير المؤشر,إخفاء الفأرة,إخفاء تأثير الفأرة",
"X-KDE-Keywords[bg]": "kwin,прозорец,мениджър,ефект,3D ефекти,2D ефекти,графични ефекти,ефекти на работния плот,анимации,различни анимации,ефекти за управление на прозорци,ефект на превключване на прозорци,ефект на превключване на работния плот,анимации,анимации на работния плот,драйвери,настройки на драйвери,рендъриране,рендър ,ефект на обръщане,ефект на огледало,ефект на лупа,ефект помощник при щракване,ефект на проследяване на мишката,ефект на увеличение,ефект на замъгляване,ефект на избледняване,ефект на избледняване на работния плот,ефект на разпадане,ефект на плъзгане,ефект на подчертаване на прозореца,ефект на влизане,ефект на излизане,магия ефект на лампа,ефект на минимизиране на анимация,ефект на маркировка на мишката,ефект на мащаб,ефект на екранна снимка,ефект на лист,ефект на слайд,ефект на плъзгащи се изскачащи прозорци,ефект на миниизображение встрани,полупрозрачност,ефект на полупрозрачност,прозрачност,ефект на геометрията на прозореца,ефект на колебливи прозорци,ефект на обратна връзка при стартиране,диалогов родителски ефект,затъмнен неактивен ефект,затъмнен екранен ефект,плъзгащ се назад ефект,бонбони за очи,бонбони,покажи FPS ефект,покажи ефект на рисуване,ефект на превключвател на капака,ефект на куб на работния плот,ефект на анимация на куб на работния плот,ефект на решетка на работния плот,ефект на превключвател с превключване,настоящ прозоречен ефект,преоразмеряване на прозоречен ефект,фонов контрастен ефект,блясък,избледняване,движение,движение,ефект на прозорци за общ преглед,достъпност,плочка,ефект на редактор на мозайки,курсор,показалец,мишка,скриване на курсора,скриване на ефект на курсора,скриване на показалеца,скриване на показалеца ефект,скриване на мишката,скриване на ефекта на мишката",
"X-KDE-Keywords[ca@valencia]": "kwin,finestra,gestor,efecte,efectes 3D,efectes 2D,efectes gràfics,efectes de l'escriptori,animacions,animacions diverses,efectes de gestió de finestres,efecte de commutació de finestres,efecte de commutació d'escriptori,animacions,animacions d'escriptori,controladors,configuració de controladors,efecte d'inversió,efecte «looking glass»,efecte de lupa,efecte d'ajuda d'ajust,efecte de seguiment de ratolí,efecte de zoom,efecte de difuminat,efecte d'esvaïment,efecte d'esvaïment d'escriptori,efecte de trencament,efecte de lliscament,efecte de ressaltat de finestra,efecte d'inici de sessió,efecte d'eixida de sessió,efecte de làmpada màgica,efecte d'animació de minimització,efecte de marca de ratolí,efecte d'escala,efecte de captura de pantalla,efecte de full,efecte de missatges emergents desplaçant-se,efecte de miniatures al costat,translucidesa,efecte de translucidesa,transparència,efecte de geometria de les finestres,efecte de finestres sacsades,efecte de retroacció en iniciar,efecte de diàleg principal,efecte d'enfosquir les inactives,efecte de pantalla enfosquida,efecte de lliscar cap arrere,vistositat,vistós,efecte de mostrar els FPS,efecte de mostrar el pintat,efecte de canvi de tapa,efecte d'animació de cub d'escriptori,efecte de quadrícula d'escriptori,efecte de canvi en roda,efecte de contrast de fons,bling,esvaïment,moviment,efecte de vista general de finestres,accessibilitat,cursor,punter,ratolí,oculta cursor,efecte d'ocultació de cursor",
"X-KDE-Keywords[ca]": "kwin,finestra,gestor,efecte,efectes 3D,efectes 2D,efectes gràfics,efectes d'escriptori,animacions,animacions diverses,efectes de gestió de finestres,efecte de commutació de finestres,efecte de commutació d'escriptori,animacions,animacions d'escriptori,controladors,configuració de controladors,efecte d'inversió,efecte «looking glass»,efecte de lupa,efecte d'ajuda d'ajust,efecte de seguiment de ratolí,efecte de zoom,efecte de difuminat,efecte d'esvaïment,efecte d'esvaïment d'escriptori,efecte de trencament,efecte de lliscament,efecte de ressaltat de finestra,efecte d'inici de sessió,efecte de sortida de sessió,efecte de làmpada màgica,efecte d'animació de minimització,efecte de marca de ratolí,efecte d'escala,efecte de captura de pantalla,efecte de full,efecte de missatges emergents desplaçant-se,efecte de miniatures al costat,translucidesa,efecte de translucidesa,transparència,efecte de geometria de les finestres,efecte de finestres sacsejades,efecte de retroacció en iniciar,efecte de diàleg principal,efecte d'enfosquir les inactives,efecte de pantalla enfosquida,efecte de lliscar cap enrere,vistositat,vistós,efecte de mostrar els FPS,efecte de mostrar el pintat,efecte de canvi de tapa,efecte d'animació de cub d'escriptori,efecte de quadrícula d'escriptori,efecte de canvi en roda,efecte de contrast de fons,bling,esvaïment,moviment,efecte de vista general de finestres,accessibilitat,cursor,punter,ratolí,oculta cursor,efecte d'ocultació de cursor",
"X-KDE-Keywords[es]": "kwin,ventana,gestor,efecto,efectos 3D,efectos 2D,efectos gráficos,efectos del escritorio,animaciones,animaciones varias,animaciones diversas,efectos de gestión de ventanas,efecto de cambio de ventana,efecto de selección de ventana,efecto de cambio de escritorio,efecto de selección de escritorio,animaciones del escritorio,controladores,preferencias del controlador,renderizado,renderizar,efecto de invertir,efecto de espejo,efecto de lupa,efecto auxiliar de ajuste,efecto de seguimiento del ratón,efecto de ampliación,efecto de desenfoque,efecto de atenuación,efecto de desvanecimiento,efecto de desvanecer el escritorio,defecto de desmoronar,efecto de planeo,efecto de resaltar ventana,efecto de inicio de sesión,efecto de cierre de sesión,efecto de lámpara mágica,efecto de lámpara maravillosa,efecto de animación de minimización,efecto de marcar con el ratón,efecto de escalado,efecto de captura de pantalla,efecto de hoja,efecto de deslizar,efecto de deslizar ventanas emergentes,efecto de miniaturas laterales,transparencia,transparente,efecto de transparencia,efecto de geometría de la ventana,efecto de ventanas tambaleantes,efecto de notificación de lanzamiento,efecto de diálogo padre,efecto de oscurecer inactiva,efecto de atenuar inactiva,efecto de desenfocar inactiva,efecto de oscurecer pantalla,efecto de atenuar pantalla,efecto de desenfocar pantalla,efecto de deslizar hacia atrás,atractivo,efecto de mostrar FPS,efecto de mostrar pintado,efecto de selección de carátulas,efecto de selección de portadas,efecto del cubo del escritorio,efecto de animación del cubo del escritorio,efecto de la cuadrícula de escritorios,efecto de selección de volteo,efecto de volteo,efecto de contraste del fondo,desvanecimiento,desvanecer,atenuar,atenuación,movimiento,efecto de resumen de ventanas,efecto de vista general de ventanas,accesibilidad,cursor,puntero,ratón,ocultar el cursor,efecto de ocultar el cursor,ocultar el puntero,efecto de ocultar el puntero,ocultar el ratón,efecto de ocultar el ratón",
"X-KDE-Keywords[eu]": "kwin,leihoa,kudeatzailea,efektua,3D efektuak,2D efektuak,efektu grafikoak,mahaigaineko efektuak,animazioak,animazio batzuk,leihoak kudeatzeko animazioak,leihoak aldatzeko efektua,mahaigaina aldatzeko efektua,animazioak,mahaigaineko animazioak,gidariak,gidari-ezarpenak,errendatzea,errendatu,alderantzizko efektua,lupa efektua,handiagotze efektua,atxikitzeko efektu laguntzailea,saguaren jarraipen efektua,zoom efektua,lausotze efektua,koloregabetze efektua,mahaigaina koloregabetzeko efektua,puskatze efektua,irristatze efektua,leihoa nabarmentzeko efektua,saioan sartzeko efektua,saiotik irteteko efektua,lanpara magikoa efektua,ikonotzeko animazio efektua,saguaren arrasto efektua,eskalatze efektua,pantaila-argazki efektua,orri efektua,irristatze efektua,gainerakor irristakor efektua,koadro txikiak alboan efektua,zeharrargitasuna,zeharrargitasun efektua,gardentasuna,leihoaren geometria efektua,leiho dardarti efektua,abiatze berrelikadura efektua,guraso elkarrizketa-koadro efektua,ahuldu ez-aktiboa efektua,ahuldu pantaila efektua,irristatu atzerantz efektua,begiaren gozagarri,gozagarria,erakutsi FPS efektua,erakutsi pintura efektua,azal aldaketa efektua,mahaigain kubo efektua,mahaigain kubo animazio efektua,mahaigain sareta efektua,etengailua sakatu efektua,atzeko planoaren kontrastea efektua,dir-dir,itzaleztatu,koloregabetu,mugimendua,higidura,leihoen ikuspegi orokor efektua,irisgarritasuna,kurtsorea, erakuslea,sagua,ezkutatu sagua,sagua ezkutatzeko efektua,ezkutatu erakuslea, erakuslea ezkutatzeko efektua,ezkutatu sagua,sagua ezkutatzeko efektua ",
"X-KDE-Keywords[fi]": "kwin,ikkuna,hallinta,tehoste,3D-tehosteet,2D-tehosteet,graafiset tehosteet,työpöytätehosteet,animoinnit,animaatiot,tehoste,ikkunatehoste,ikkunatehosteet,ikkunanvaihtotehoste,työpöytävaihtotehoste,työpöydänvaihtotehoste,vaihtotehoste,ajurit,ajuriasetukset,hahmonnus,renderöinti,käänteinen,suurennuslasi,tarttuminen,kiinnittyminen,jäljitä hiiri,suurennustehoste,sumennustehoste,häivytystehoste,häivytä työpöytä,uloskirjautumistehoste,taikalampputehoste,pienennystehoste,hiiren jälki,skaalaus,ruutukaappaustehoste,näyttökuvatehoste,näyttökaappaustehoste,liuku,liukuvat ponnahdusikkunat,pienoiskuva sivulla,läpinäkyvyys,läpikuultavuus,ikkunageometria,huojuvat ikkunat,käynnistyspalaute,emoikkuna,himmennä passiivinen,himmennä näyttö,liuuta taakse,esitä ikkunat,ikkunan koon muuttaminen,muuta ikkunan kokoa,silmäkarkki,näytä FPS,näytä maalaus,näytä piirto,kansikuva,työpöytäkuutio,työpöytäkuution animointi,työpöytäruudukko,näytä ikkunat,taustakontrasti,taustan kontrasti,bling,häivytys,liike,yleiskuva,ikkunayleiskuva,saavutettavuus,esteettömyys,tiili,laatta,laatoitus,osoitin,kohdistin,hiiri,piilota osoitin,piilota kohdistin,piilota hiiri,piilota osoitin -tehoste,piilota hiiri -tehoste",
"X-KDE-Keywords[fr]": "kwin, fenêtre, gestionnaire, effet, effets 3D, effets 2D, effets visuels, effets de bureau, animations, diverses animations, effets de gestion de fenêtres, effet de basculement de fenêtres, effet de basculement de bureaux, animations, animations de bureaux, pilotes, configuration de pilote, rendu, réaliser un rendu, effet d'inversion, effet de miroir, effet de loupe, effet d'aide à l'aimantage, effet de suivi de souris, effet de zoom, effet de flou, effet de fondu, effet de fondu de bureaux, effet de chute en morceaux, effet de glissement, effet de mise en évidence de fenêtre, effet de connexion, effet de déconnexion, effet de lampe magique, effet de minimisation d'animation, effet de marquage de souris, effet d'échelle, effet de copie d'écran, effet de feuille, effet de diapositive, effet de fenêtres contextuelles flottantes, effet de vignette sur le côté, translucidité, effet de translucidité, transparence, géométrie de fenêtres, effet de fenêtres en gélatine, effet de suivi du démarrage, effet de boîte de dialogue parente, réglage d'écran inactif, réglage d'écran actif, plaisir des yeux, brillant, effet d'affichage du nombre de trames par seconde, effet d'affichage de peinture, effet de commutateur de couverture, effet de cube de bureaux, effet d'animation pour cube de bureaux, effet de grille de bureaux, effet de bouton en bascule, effet de présentation de fenêtres, effet de redimensionnent de fenêtres, effet de contraste d'arrière-plan, clignotement, estompage, mouvement, déplacement, effet d'aperçu de fenêtre, accessibilité,tuile, effet de modification de tuiles, curseur, pointeur, souris, masquer le pointeur, effet de masquage du curseur, masquer le pointeur, effet de masquage, masquer la souris, effet de masquage de la souris",
"X-KDE-Keywords[gl]": "kwin,window,xanela,ventá,fiestra,manager,xestor,manexador,effect,efecto,3D effects,efectos 3D,2D effects,efectos 2D,graphical effects,efectos gráficos,desktop effects,efectos de escritorio,animations,animacións,various animations,window management effects,efectos do xestor de xanelas,efectos do xestor de ventás,efectos do xestos de fiestras,efectos do manexador de xanelas,efectos do manexador de ventás,efectos do manexador de fiestras,window switching effect,efecto de cambio de xanela,efecto de cambio de ventá,efecto de cambio de fiestra,desktop switching effect,efecto de cambio de escritorio,animations,animacións,desktop animations,animacións de escritorio,drivers,controladores,driver settings,configuración de controlador,configuración dos controladores,rendering,renderización,render,renderizar,invert effect,efecto de inversión,inverter un efecto,looking glass effect,efecto de lupa,magnifier effect,snap helper effect,efecto de axudante de colocación,track mouse effect,efecto de seguimento do rato,zoom effect,efecto de ampliación,blur effect,efecto borroso,fade effect,efecto de esvaer,fade desktop effect,efecto de escritorio de esvaer,fall apart effect,efecto de desfacer,glide effect,efecto de desprazar,highlight window effect,efecto de realce de xanela,efecto de realce de ventá,efecto de realce de fiestra,login effect,efecto de acceso,logout effect,efecto de saída,magic lamp effect,efecto de lámpada máxima,minimize animation effect,efecto de animación de minimizar,mouse mark effect,efecto de marca do rato,scale effect,efecto de escala,efecto de axuste de tamaño,screenshot effect,efecto de captura de pantalla,sheet effect,efecto de páxina,slide effect,efecto de esvarar,sliding popups effect,thumbnail aside effect,efecto de miniatura lateral,translucency,translúcido,translúcida,translucency effect,transparency,transparencia,window geometry effect,efecto de xeometría da xanela,efecto de xeometría da ventá,efecto de xeometría da fiestra,wobbly windows effect,efecto de xanelas flexíbeis,startup feedback effect,efecto de resposta de inicio,dialog parent effect,efecto de diálogo contedor,dim inactive effect,efecto de escurecer o inactivo,dim screen effect,efecto de escurecer a pantalla,slide back effect,efecto de esvarar cara atrás,eye candy,estética,candy,show FPS effect,efecto de amosar os FPS,efecto de FPS,show paint effect,efecto de amosar a pintura,cover switch effect,efecto de portadas,desktop cube effect,efecto de cubo,desktop cube animation effect,desktop grid effect,efecto de grade,flip switch effect,background contrast effect,fondo,contraste,bling,fading,movement,movemento,motion,overview windows effect,resumo,vista previa,vista xeral,accessibility,accesibilidade,cursor,pointer,punteiro,mouse,rato,hide cursor,agochar,ocultar,agochado,oculto,hide cursor effect,hide pointer,hide pointer effect,hide mouse,hide mouse effect",
"X-KDE-Keywords[he]": "kwin,חלון,מנהל,אפקט,אפקטים תלת־ממדיים,אפקטים דו־ממדיים,אפקטים גרפיים,אפקטי שולחן עבודה,אנימציות,הנפשות,אנימציות שונות,הנפשות שונות,אפקטי ניהול חלונות,אפקט החלפת חלון,אפקט החלפת שולחן עבודה,אנימציות,הנפשות,אנימציות שולחן עבודה,הנפשות שולחן עבודה,מנהלי התקנים,הגדרות מנהל התקן,רינדור,עיבוד גרפי,אפקט היפוך,אפקט זכוכית מגדלת,אפקט הגדלה,אפקט עזר הצמדה,אפקט מעקב עכבר,אפקט זום,אפקט טשטוש,אפקט עמעום,אפקט עמעום שולחן עבודה,אפקט התפרקות,אפקט גלישה,אפקט הדגשת חלון,אפקט כניסה,אפקט יציאה,אפקט מנורת קסם,אפקט הנפשת מזעור,אפקט סימון עכבר,אפקט שינוי קנה מידה,אפקט צילום מסך,אפקט גיליון,אפקט החלקה,אפקט חלונות קופצים מחליקים,אפקט תמונה ממוזערת בצד,שקיפות למחצה,אפקט שקיפות למחצה,שקיפות,אפקט גאומטריית חלון,אפקט חלונות מתנודדים,אפקטמשוב הפעלה,אפקט תיבת־דו־שיח הורה,אפקט עמעום־לא־פעיל,אפקט עמעום־מסך,אפקט החלקה־לאחור,קישוטים,ממתק,אפקט הצגת־FPS,אפקט הצגת ציור,אפקט החלפת כיסוי,אפקט קוביית שולחן עבודה,אפקט הנפשת־קוביית־שולחן־עבודה,אפקט רשת שולחן עבודה,אפקטהחלפת־היפוך,אפקט הצגת־חלונות,אפקט שינוי־גודל־חלון,אפקט ניגודיות רקע,נצנוץ,דהייה,תנועה,תנועה,אפקט סקירת־חלונות,נגישות,אריח,אפקט עורך־אריחים,סמן,מצביע,עכבר,הסתרת סמן,אפקט הסתרת סמן,הסתרת מצביע,אפקט הסתרת מצביע,הסתרת עכבר,אפקט הסתרת עכבר, אפקט הצגת חלונות, אפקט עורך פריסה",
"X-KDE-Keywords[hu]": "kwin,ablak,kezelő,effektus,3D effektusok,2D effektusok,grafikai effektusok,asztali effektusok,animációk,különböző animációk,ablakkezelési effektusok,ablakváltási effektusok,asztalváltási effektusok,animációk,asztali animációk,illesztőprogramok,illesztőprogram-beállítások,renderelés,render,inverz effektus,távcső effektus,nagyító effektus,középpontkereső effektus,egérkövetés effektus,nagyítás effektus,elmosás effektus,elhalványítás effektus,asztal elhalványítása effektus,szétbontás effektus,csúsztatás effektus,ablak kiemelése effektus,bejelentkezési effektus,kijelentkezési effektus,varázslámpa effektus,minimalizálási animáció effektus,egérnyom effektus,méretezés effektus,képernyőkép effektus,fólia effektus,csúszás effektus,csúszó felugrók effektus,ablakbetekintő oldal effektus,áttetszőség,áttettszőség effektus,átlátszóság,ablakgeometria effektus,tekergő ablak effektus,alkalmazásindítási effektus,párbeszédablak-szülő effektus,inaktívak kiszürkítése effektus,képernyő kiszürkítése effektus,visszacsúszás effektus,szemcukorka,cukorka,FPS megjelenítése effektus,rajzkiemelés effektus,borító effektus,asztalkocka effektus,asztalkocka animációs effektus,asztalrács effektus,tükrözés effektus,háttérkontraszt effektus,elhalványítás,mozgatás,mozgás,áttekintő ablakok effektus,akadálymentesítés,kurzor,mutató,egér,kurzor elrejtése,kurzor elrejtése effektus,mutató elrejtése,mutató elrejtése effektus,egér elrejtése,egér elrejtése effekturs",
"X-KDE-Keywords[ia]": "kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,background contrast effect,bling,fading,movement,motion,overview windows effect,accessibility,cursor,pointer,mouse,hide cursor,hide cursor effect,hide pointer,hide pointer effect,hide mouse,hide mouse effect",
"X-KDE-Keywords[it]": "kwin,window,manager,effect,effetti 3D,effetti 2D,effetti grafici,effetti desktop,animazioni,animazioni varie,effetti gestione finestre,effetto cambio finestra,effetto cambio desktop,animazioni,animazioni desktop,driver,impostazioni driver,rendering,render,effetto inverti,effetto specchio,effetto lente d'ingrandimento,effetto snap helper,effetto traccia mouse,effetto zoom,effetto sfocatura,effetto dissolvenza,effetto dissolvenza desktop,effetto disfacimento,effetto scorrimento,effetto finestra evidenziata,effetto accesso,effetto chiusura sessione,effetto lampada magica,effetto animazione minimizzata,effetto segno mouse,effetto scala,effetto schermata,effetto foglio,effetto diapositiva,effetto finestre a comparsa scorrevoli,effetto miniatura a lato,traslucenza,effetto traslucenza,trasparenza,effetto geometria finestra,effetto finestre traballanti,effetto feedback avvio,effetto finestra genitrice,effetto oscuramento inattivo,effetto oscuramento schermo,effetto scorrimento indietro,gradevole,effetto mostra FPS,effetto mostra disegno,effetto interruttore di copertura,effetto cubo desktop,effetto animazione cubo desktop,effetto griglia desktop,effetto selezione con inversione,effetto contrasto sfondo,bling,dissolvenza,movimento,effetto panoramica finestre,accessibilità,cursore,puntatore,mouse,nascondi cursore,effetto nascondi cursore,nascondi puntatore,effetto nascondi puntatore,nascondi mouse,effetto nascondi mouse",
"X-KDE-Keywords[ka]": "kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect,bling,fading,movement,motion,overview windows effect,accessibility,tile,tiling editor effect,cursor,pointer,mouse,hide cursor,hide cursor effect,hide pointer,hide pointer effect,hide mouse,hide mouse effect,ეფექტები,სამუშაო მაგიდის ეფექტები",
"X-KDE-Keywords[nb]": "kwin,vindu,behandler,vindusbehandler,effekt,3D-effekter,2D-effekter,bildeeffekter,skrivebordeffekter,animasjoner,flere animasjonar,vindusbytteeffekter,effekter ved skrivebordbytte,animasjoner,skrivebordsanimasjoner,drivere,driverinnstillinger,opptegning,opptegner,inverteringseffekt,speileffekt,skalereffekt,gripehjelpereffekt,musmerkeeffekt,forstørringseffekt,zoomeffekt,sløringseffekt,uklar-effekt,kontrollpulteffekt,uttoningseffekt,skrivebordtoningseffekt,gå-i-knas-effekt,glideeffekt,fremhev vinduseffekt,innloggingseffekt,utloggingseffekt,magisk lampe-effekt,animasjonseffekt ved vindusminimering,musmerkeeffekt,skaleringseffekt,skjermdumpeffekt,ark-effekt,lysbiledeffekt,glidende sprettopp-effekt,effekt for minibilde på siden,gjennomsiktseffekt,gjennomsikt,vindusgeometri-effekt,vinglende vinduseffekt,effekt for oppstartsmelding,effekt for forelderdialog,effekt for mørk inaktiv,effekt for mørk skjerm,gli tilbake-effekt,øyegodteri,vis FPS-effekt,vis målingseffekt,omslagsbytteeffekt,skrivebordskube-effekt,effekt for animert skrivebordskube,effekt for skrivebordrutenett,effekt for flipp-byte,presenter vindus-effekt,vindusskaleringseffekt,bakgrunnskontrast-effekt,bling,uttonning,inntoning,bevegelse,flytting,oversiktseffekt,tilgjengelighet,musepeker,peker,mus,skjul musepeker,skjul museffekt,skjul musepeker,skjul musepeker-effekt,skjul mus,skjul museeffekt",
"X-KDE-Keywords[nl]": "kwin,venster,beheerder,effect,3D effecten,2D effecten,grafische effecten,bureaubladeffecten,animaties,verschillende animaties,vensterbeheereffecten,vensterwisselingseffect,bureaubladwisselingseffect,animaties,bureaubladanimaties,stuurprogramma's,stuurprogramma-instellingen,renderen,render,omgekeerd effect,vergrootglaseffect,vergrotingseffect,vastklik-helper-effect,muis-volgen-effect,zoomeffect,vervagingseffect,bureaubladvervagingseffect,uiteenvallen-effect,glij-effect,vensteraccentueringseffect,aanmeldeffect,afmeldeffect,magisch-lamp-effect,animatie-minimaliseren-effect,muismarkeringseffect,schaaleffect,schermafdrukeffect,papiervel-effect,dia-effect,verschuivende-popups-effect,miniaturen-opzij-effect,doorzichtigheid,doorzichtigheidseffect,transparantie,venster-geometrie-effect,wiebelende vensters effect,terugkoppeling-van-opstarten-effect,dialoogoudereffect,inactief-dimmen-effect,scherm-dimmen-effect,terug-glijden-effect,oogversiering,versiering,FPS-tonen-effect,schilderen-tonen-effect,deksel-schakelaar-effect,bureaublad-kubus-effect,bureaubladkubus-animatie-effect,bureaublad-raster-effect,schakelaar-omzetten-effect,achtergrondcontrast-effect,bling,uitdoven,verplaatsing,beweging,vensteroverzicht-effect,toegankelijkheid,cursor,aanwijzer,muis,cursor verbergen,cursor verbergen-effect,aanwijzer verbergen,aanwijzer verbergen-effect,muis verbergen,muis verbergen-effect",
"X-KDE-Keywords[pl]": "kwin,okno,menadżer,efekt,efekty 3D,efekty 2D,efekty graficzne,efekty pulpitu,animacje,różne animacje,efekty zarządzania oknami,efekty przełączania okien,efekty przełączania pulpitów,animacje,animacje pulpitu,sterowniki,ustawienia sterowników,renderowania, efekt odwrócenia,szkło powiększające,efekt powiększenia,efekt pomocnika przyciągania, efekt śledzenia myszy,efekt przybliżenia,rozmycie,tablica,efekt eksplozji,efekt zanikania,efekt zanikania pulpitu,efekt rozpadania,efekt slajdu,efekt podświetlania okna, efekt logowania,efekt wylogowywania,efekt magicznej lampy,efekt animacji minimalizacji, efekt znacznika myszy,efekt skalowania,efekt zrzutu ekranu,efekt arkusza,efekt slajdu,efekt wysuwających się elementów wyskakujących,efekt prześwitywania,przezroczystość,efekt geometrii okna,efekt chwiejnych okien,efekt odczuć przy starcie,efekt okna rodzica,efekt przyciemniania nieaktywnych,efekt przyciemniania ekranu,efekt przesuwania do tył,cukierki dla oczu,cukierek,efekt pokazania ilości klatek na sekundę,efekt pokazywania malowania,efekt przełączania okładek,efekt kostki pulpitu,efekt animacji kostki pulpitu,efekt siatki pulpitu,efekt przełączania przełącznikiem,efekt przedstawiania okien,efekt zmiany rozmiaru okien,efekt kontrastu tła,bling,zanikanie,ruch,ruch,efekt przeglądu okien,dostępność,kursor,wskaźnik,mysz,ukryj kursor,efekt ukrywania kursora,ukryj wskaźnik,efekt ukrywania wskaźnika,ukryj mysz,efekt ukrywania myszy",
"X-KDE-Keywords[pt_BR]": "kwin,janela,gerenciador,efeito,efeitos 3D,efeitos 2D,efeitos gráficos,efeitos de área de trabalho,animações,animações variadas,efeitos de gerenciamento de janela,efeito de troca de janela,efeito de troca de área de trabalho,animações,animações de área de trabalho,drivers,configurações de driver,renderização,renderizar,efeito de inversão,efeito de vidro de aumento,efeito de magnificador,efeito de ajuda para encaixe,efeito de rastrear o mouse,efeito de zoom,efeito de desfoque,efeito de desvanecimento,efeito de desvanecimento da área de trabalho,efeito de desintegração,efeito de deslizamento,efeito de destacar janela,efeito de login,efeito de logout,efeito de lâmpada mágica,efeito de animação de minimizar,efeito de marca de mouse,efeito de escala,efeito de captura de tela,efeito de folha,efeito de deslizamento,efeito de pop-ups deslizantes,efeito de miniatura ao lado,translucidez,efeito de translucidez,transparência,efeito de geometria de janela,efeito de janelas onduladas,efeito de feedback de inicialização,efeito de pai de diálogo,efeito de escurecimento de inatividade,efeito de escurecimento de tela,efeito de voltar a deslizar,doces visuais,candy,efeito de mostrar FPS,efeito de mostrar pintura,efeito de troca de capa,efeito de cubo de área de trabalho,efeito de animação de cubo de área de trabalho,efeito de grade de área de trabalho,efeito de troca de flip,efeito de contraste de fundo,bling,desvanecimento,movimento,motion,efeito de visão geral das janelas,acessibilidade,cursor,ponteiro,mouse,ocultar cursor,efeito de ocultar cursor,ocultar ponteiro,efeito de ocultar ponteiro,ocultar mouse,efeito de ocultar mouse",
"X-KDE-Keywords[sl]": "kwin,okno,upravljalnik,učinek,3D učinki,2D učinki,grafični učinki,namizni učinki,animacije,različne animacije,učinki upravljanja oken,učinek preklopa oken,učinek preklopa namizja,animacije,animacije namizja,gonilniki,nastavitve gonilnika,upodabljanje,upodobitev,obrnjeni učinek,učinek ogledala,učinek povečevalnika,učinek pomočnika za pripenjanje,učinek sledenja miški,učinek povečave,učinek zamegljenosti,učinek bledenja,učinek bledenja namizja,učinek razpadanja,učinek drsenja,učinek osvetlitve okna,učinek prijave,učinek odjave,čarovnija učinek svetilke,učinek minimiziranja animacije,učinek oznake miške,učinek merila,učinek posnetka zaslona, učinek lista, učinek diapozitiva, učinek drsnih pojavnih oken, stranski učinek sličice, prosojnost, učinek prosojnosti, prosojnost, učinek geometrije okna, učinek majavih oken,učinek povratne informacije ob zagonu,nadrejeni učinek pogovornega okna,učinek zatemnitve neaktivnosti,učinek zatemnjenega zaslona,učinek drsenja nazaj,bonboni,pokaži učinek FPS,pokaži učinek barve,učinek stikala na pokrovu,učinek kocke na namizju,učinek animacije kocke na namizju,učinek mreže na namizju,učinek preklopnega stikala,prisoten učinek oken,učinek spreminjanja velikosti okna,učinek kontrasta ozadja,bleščanje,bledenje,gibanje,premikanje,učinek preglednih oken,dostopnost,ploščica,učinek urejevalnika ploščic,kazalec,kazalnik,miška,skrij kazalec,skrij učinek kazalca,skrij kazalnik,skrij učinek kazalnika,skrij miško,skrij učinek miške",
"X-KDE-Keywords[sv]": "kwin,fönster,hanterare,effekt,tredimensionella effekter,tvådimensionella effekter,grafiska effekter,skrivbordseffekter,animeringar,olika animeringar,fönsterhanteringseffekter,fönsterbyteseffekt,skrivbordsbyteseffekt,animeringar,skrivbordsanimeringar,drivrutiner,drivrutinsinställningar,återgivning,återge,inverteringseffekt,förstoringsglasseffekt,förstoringseffekt,låshjälpeffekt,musföljningseffekt,zoomeffekt,suddighetseffekt,borttoningseffekt,skrivbordstoningseffekt,fall sönder-effekt,glideffekt,markeringsfönstereffekt,inloggningseffekt,utloggningseffekt,magisk lanterneffekt,minimeringsanimeringseffekt, musmarkeringseffekt,inskalningseffekt, skärmbildseffekt, bladeffekt, bildeffekt, glidande ruteffekt,miniatyrbild vid sidan om,genomskinlighet,genomskinlighetseffekt, transparens, fönstergeometrieffekt, ostadiga fönstereffekt,startgensvarseffekt, dialogrutors ägareffekt,dämpa inaktiva effekt, dämpa skärmen effekt,glid tillbaka effekt,ögongodis,godis,visa ramar/s-effekt,visa uppritningseffekt,byte med ruta effekt, skrivbordskubeffekt, animeringseffekt för skrivbordskub,skrivbordsrutnätseffekt,blädderbyteseffekt,bakgrundskontrasteffekt,bling,borttoning,förflyttning,rörelse, översiktsfönstereffekt,handikappstöd,markör,pekare,mus,dölj markör,dölj marköreffekt,dölj pekare,dölj pekareffekt,dölj mus,dölj museffekt",
"X-KDE-Keywords[tr]": "kwin,pencere,yönetici,efekt,3b efektler,3d efektler,2b efektler,2d efektler,grafik efektler,masaüstü efektleri,canlandırma,animasyon,çeşitli animasyon,çeşitli canlandırma,pencere yönetimi efektleri,pencere değiştirme efektleri,masaüstü canlandırmaları,masaüstü animasyonları,sürücüler,sürücü ayarları,sunum,oluşturma,çizim,ters çevir efekti,dürbün efekti,büyüteç efekti,tutturma yardımcısı efekti,fareyi izle efekti,yakınlaştırma efekti,bulanıklaştırma efekti,solma efekti,masaüstü solma efekti,düşme efekti,süzülme efekti,pencereyi vurgula efekti,oturum aç efekti,oturumu kapat efekti,sihirli lamba efekti,küçültme canlandırması,fare işareti efekti,ölçek efekti,ekran görüntüsü efekti,sayfa efekti,kaydırma efekti,kayan açılır pencereler efekti,küçük görsel yana efekti,yarısaydamlık,yarısaydamlık efekti,saydamlık,pencere geometrisi efekti,sallanan pencereler efekti,başlangıç bildirimi efekti,üst iletişim kutusu efekti,etkin olmayan pencereyi karart efekti,geri kaydır efekti,janjan efekti,FPS göster efekti,boyama efekti,küp efekti,küp canlandırması,küp animasyonu,masaüstü ızgarası efekti,pencereleri sun efekti,pencereyi yeniden boyutlandır efekti,arka plan karşıtlık efekti,solma,taşıma efekti,erişilebilirlik döşemesi,döşeme düzenleyicisi,imleç,işaretçi,imleci gizle,işaretçiyi gizle,fareyi gizle",
"X-KDE-Keywords[uk]": "kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,background contrast effect,bling,fading,movement,motion,overview windows effect,accessibility,cursor,pointer,mouse,hide cursor,hide cursor effect,hide pointer,hide pointer effect,hide mouse,hide mouse effect,квін,вікно,керування,ефект,просторові,плоскі,двовимірні,графічні ефекти,ефекти стільниці,анімації,різні анімації,ефекти керування вікнами,ефект перемикання вікон,ефект перемикання стільниць,анімації,стільничні анімації,драйвери,параметри драйверів,обробка,обробляти,ефект інвертування,ефект лупи,ефект збільшувального скла,ефект збільшення,ефект прилипання,ефект стеження за мишею,ефект масштабування,ефект розмивання,ефект притлумлення,ефект притлумлення стільниці,ефект розпадання,ефект ковзання,ефект підсвічування вікна,ефект входу,ефект виходу,ефект магічної лампи,ефект анімації мінімізації,ефект позначки миші,ефект масштабування,ефект знімка екрана,ефект зсування,ефект аркуша,ефект проковзування,ефект бічної мініатюри,прозорість,ефект прозорості,ефект геометрії вікна,ефект желе,ефект супроводу запуску,ефект батьківського вікна,ефект притлумення неактивного,ефект притлумлення екрана,зручність,показ частоти кадрів,ефект показу малювання,ефект перемикання обкладинок,ефект куба стільниць,ефект анімації куба стільниць,ефект таблиці стільниць,ефект перемикання дзеркал,ефект презентації вікон,ефект зміни розмірів вікон,ефект контрастності тла,тьмянішання,пересування,курсор,вказівник,приховування вказівника,ефект приховування вказівника,приховати вказівник,миша,ефект приховування миші",
"X-KDE-Keywords[x-test]": "xxkwinxx,xxwindowxx,xxmanagerxx,xxeffectxx,xx3D effectsxx,xx2D effectsxx,xxgraphical effectsxx,xxdesktop effectsxx,xxanimationsxx,xxvarious animationsxx,xxwindow management effectsxx,xxwindow switching effectxx,xxdesktop switching effectxx,xxanimationsxx,xxdesktop animationsxx,xxdriversxx,xxdriver settingsxx,xxrenderingxx,xxrenderxx,xxinvert effectxx,xxlooking glass effectxx,xxmagnifier effectxx,xxsnap helper effectxx,xxtrack mouse effectxx,xxzoom effectxx,xxblur effectxx,xxfade effectxx,xxfade desktop effectxx,xxfall apart effectxx,xxglide effectxx,xxhighlight window effectxx,xxlogin effectxx,xxlogout effectxx,xxmagic lamp effectxx,xxminimize animation effectxx,xxmouse mark effectxx,xxscale effectxx,xxscreenshot effectxx,xxsheet effectxx,xxslide effectxx,xxsliding popups effectxx,xxthumbnail aside effectxx,xxtranslucencyxx,xxtranslucency effectxx,xxtransparencyxx,xxwindow geometry effectxx,xxwobbly windows effectxx,xxstartup feedback effectxx,xxdialog parent effectxx,xxdim inactive effectxx,xxdim screen effectxx,xxslide back effectxx,xxeye candyxx,xxcandyxx,xxshow FPS effectxx,xxshow paint effectxx,xxcover switch effectxx,xxdesktop cube effectxx,xxdesktop cube animation effectxx,xxdesktop grid effectxx,xxflip switch effectxx,xxbackground contrast effectxx,xxblingxx,xxfadingxx,xxmovementxx,xxmotionxx,xxoverview windows effectxx,xxaccessibilityxx,xxcursorxx,xxpointerxx,xxmousexx,xxhide cursorxx,xxhide cursor effectxx,xxhide pointerxx,xxhide pointer effectxx,xxhide mousexx,xxhide mouse effectxx",
"X-KDE-Keywords[zh_CN]": "kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,explosion effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window kwin,window,manager,effect,3D effects,2D effects,graphical effects,desktop effects,animations,various animations,window management effects,window switching effect,desktop switching effect,animations,desktop animations,drivers,driver settings,rendering,render,invert effect,looking glass effect,magnifier effect,snap helper effect,track mouse effect,zoom effect,blur effect,fade effect,fade desktop effect,fall apart effect,glide effect,highlight window effect,login effect,logout effect,magic lamp effect,minimize animation effect,mouse mark effect,scale effect,screenshot effect,sheet effect,slide effect,sliding popups effect,thumbnail aside effect,translucency,translucency effect,transparency,window geometry effect,wobbly windows effect,startup feedback effect,dialog parent effect,dim inactive effect,dim screen effect,slide back effect,eye candy,candy,show FPS effect,show paint effect,cover switch effect,desktop cube effect,desktop cube animation effect,desktop grid effect,flip switch effect,present windows effect,resize window effect,background contrast effect,tile,tiling editor effect,cursor,pointer,mouse,hide cursor,hide cursor effect,hide pointer,hide pointer effect,hide mouse,hide mouse effect,chuangkou,guanli,texiao,3D texiao,2D texiao,tuxingtexiao,zhuomiantexiao,donghua,chuangkouguanlitexiao,chuangkouqiehuantexiao,zhuomianqiehuantexiao,zhuomiandonghua,qudong,qudiaoshezhi,xuanran,fanse,fangdajingtexiao,shubiaogenzong,suofangtexiao,mohutexiao,jianbiantexiao,posuitexiao,huadongtexiao,gaoliangchuangkou,denglutexiao,zhuxiaotexiao,shendengtexiao,zuixiaohuadonghua,shubiaobiaoji,jieping,piaoluo,huadongtanchuchuangkou,suolvetuzhibian,toumingtexiao,yaobaichuangkou,qidongfankuitexiao,chengxuqidongdongxiao,andanduihuakuangtexiao,andanpingmutexiao,shijuexiaoguo,xianshi FPS texiao,xianshihuizhiquyutexiao,fengmianqiehuantexiao,zhuomianlifangtitexiao,zhuomianlifangtidonghuatexiao,fanzhuanqiehuantexiao,zhanshichuangkoutexiao,tiaozhengchuangkoudaxiaotexiao,beijingduibitexiao,shanguang,shanyao,shandong,xiaoshi,jianbian,jianru,jianchu,dongtai,zonglan,gailan,chuangkougailantexiao,wuzhangai,fuzhugongneng,wuzhangaifuzhu,citie,pintie,cizhuan,tukuai,citiebianjiqixiaoguo,guangbiao,zhizhen,shubiao,yincangguangbiao,yincangguangbiaoxiaoguo,yincangzhizhen,yincangzhizhenxiaoguo,yincangshubiao,yincangshubiaoxiaoguo,窗口,管理,特效,3D 特效,2D 特效,图形特效,桌面特效,动画,窗口管理特效,窗口切换特效,桌面切换特效,桌面动画,驱动,去掉设置,渲染,反色,放大镜特效,鼠标跟踪,缩放特效,模糊特效,渐变特效,破碎特效,滑动特效,高亮窗口,登录特效,注销特效,神灯特效,最小化动画,鼠标标记,截屏,飘落,滑动弹出窗口,缩略图置边,透明特效,摇摆窗口,启动反馈特效,程序启动动效,黯淡对话框特效,黯淡屏幕特效,视觉效果,显示 FPS 特效,显示绘制区域特效,封面切换特效,桌面立方体特效,桌面立方体动画特效,翻转切换特效,背景对比特效,闪光,闪耀,闪动,消失,渐变,渐入,渐出,动态,总览,概览,窗口概览特效,无障碍,辅助功能,无障碍辅助,光标,指针,鼠标,隐藏光标,隐藏光标效果,隐藏指针,隐藏指针效果,隐藏鼠标,隐藏鼠标效果",
"X-KDE-Keywords[zh_TW]": "kwin,視窗,視窗管理員,效果,3D 效果,2D 效果,圖形效果,桌面效果,動畫,各種動畫,視窗管理效果,視窗切換效果,桌面切換效果,桌面動畫,驅動程式,驅動程式設定,渲染,繪製,反轉效果,放大鏡效果,貼齊助手效果,追蹤滑鼠效果,縮放效果,模糊效果,淡化效果,淡化桌面效果,粉碎效果,滑行效果,突顯視窗效果,登入效果,登出效果,魔術燈效果,最小化動畫效果,滑鼠標記效果,螢幕截圖效果,薄紙效果,滑動效果,滑動彈出視窗效果,縮圖在一旁效果,透明效果,透明,視窗幾何效果,擺動視窗效果,啟動回饋效果,對話框上層效果,暗化非作用中效果,暗化螢幕效果,滑動到後方效果,裝飾,顯示FPS效果,顯示繪製效果,封面切換效果,桌面方塊效果,桌面方塊動畫效果,桌面格線效果,翻轉切換效果,背景對比效果,淡化,移動,總覽效果,無障礙使用,游標,指標,滑鼠,隱藏游標,隱藏游標效果,隱藏指標,隱藏指標效果,隱藏滑鼠,隱藏滑鼠效果",
"X-KDE-System-Settings-Parent-Category": "windowmanagement",
"X-KDE-Weight": 30
}
@@ -0,0 +1,66 @@
[KNewStuff3]
Name=Desktop Effects
Name[ar]=تأثيرات سطح المكتب
Name[az]=İş masası effektləri
Name[be]=Эфекты працоўнага стала
Name[bg]=Ефекти на работния плот
Name[bs]=Efekti površi
Name[ca]=Efectes d'escriptori
Name[ca@valencia]=Efectes de l'escriptori
Name[cs]=Efekty na ploše
Name[da]=Skrivebordseffekter
Name[de]=Arbeitsflächen-Effekte
Name[el]=Εφέ επιφάνειας εργασίας
Name[en_GB]=Desktop Effects
Name[eo]=Labortablo-Efikoj
Name[es]=Efectos del escritorio
Name[et]=Töölauaefektid
Name[eu]=Mahaigaineko efektuak
Name[fi]=Työpöytätehosteet
Name[fr]=Effets de bureau
Name[gl]=Efectos do escritorio
Name[he]=אפקטים של שולחן עבודה
Name[hu]=Asztali effektusok
Name[ia]=Effectos de scriptorio
Name[id]=Efek Desktop
Name[is]=Skjáborðsbrellur
Name[it]=Effetti del desktop
Name[ja]=デスクトップ効果
Name[ka]=სამუშაო მაგიდის ეფექტები
Name[ko]=데스크톱 효과
Name[lt]=Darbalaukio efektai
Name[lv]=Darbvirsmas efekti
Name[nb]=Skrivebordseffekter
Name[nds]=Schriefdischeffekten
Name[nl]=Bureaubladeffecten
Name[nn]=Skrivebords­effektar
Name[pa]=ਡੈਸਕਟਾਪ ਪਰਭਾਵ
Name[pl]=Efekty pulpitu
Name[pt]=Efeitos do Ecrã
Name[pt_BR]=Efeitos da área de trabalho
Name[ro]=Efecte de birou
Name[ru]=Эффекты
Name[sa]=डेस्कटॉप प्रभाव
Name[se]=Čállinbeavdeeffeavttat
Name[sk]=Efekty plochy
Name[sl]=Učinki namizja
Name[sr]=Ефекти површи
Name[sr@ijekavian]=Ефекти површи
Name[sr@ijekavianlatin]=Efekti površi
Name[sr@latin]=Efekti površi
Name[sv]=Skrivbordseffekter
Name[ta]=பணிமேடை அசைவூட்டங்கள்
Name[tg]=Таъсирҳои мизи корӣ
Name[tr]=Masaüstü Efektleri
Name[uk]=Ефекти стільниці
Name[vi]=Hiệu ứng bàn làm việc
Name[x-test]=xxDesktop Effectsxx
Name[zh_CN]=桌面特效
Name[zh_TW]=桌面效果
ProvidersUrl=https://autoconfig.kde.org/ocs/providers.xml
ContentWarning=Executables
Categories=KWin Effects Plasma 6
StandardResource=tmp
Uncompress=kpackage
KPackageStructure=KWin/Effect
@@ -0,0 +1,143 @@
/*
SPDX-FileCopyrightText: 2013 Antonis Tsiapaliokas <kok3rs@gmail.com>
SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami 2 as Kirigami
import org.kde.kcmutils as KCM
QQC2.ItemDelegate {
id: listItem
hoverEnabled: true
onClicked: {
if (ListView.isCurrentItem) {
// Collapse list item
ListView.view.currentIndex = -1;
} else {
// Expand list item
ListView.view.currentIndex = index;
}
}
contentItem: RowLayout {
spacing: Kirigami.Units.smallSpacing
QQC2.RadioButton {
readonly property bool _exclusive: model.ExclusiveRole != ""
property bool _toggled: false
checked: model.StatusRole
visible: _exclusive
QQC2.ButtonGroup.group: _exclusive ? effectsList.findButtonGroup(model.ExclusiveRole) : null
onToggled: {
model.StatusRole = checked ? Qt.Checked : Qt.Unchecked;
_toggled = true;
}
onClicked: {
// Uncheck the radio button if it's clicked.
if (checked && !_toggled) {
model.StatusRole = Qt.Unchecked;
}
_toggled = false;
}
KCM.SettingHighlighter {
highlight: model.EnabledByDefaultFunctionRole ? parent.checkState !== Qt.PartiallyChecked : parent.checked !== model.EnabledByDefaultRole
}
}
QQC2.CheckBox {
checkState: model.StatusRole
visible: model.ExclusiveRole == ""
onToggled: model.StatusRole = checkState
KCM.SettingHighlighter {
highlight: model.EnabledByDefaultFunctionRole ? parent.checkState !== Qt.PartiallyChecked : parent.checked !== model.EnabledByDefaultRole
}
}
ColumnLayout {
Layout.topMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: Kirigami.Units.smallSpacing
spacing: 0
Kirigami.Heading {
Layout.fillWidth: true
level: 5
text: model.NameRole
wrapMode: Text.Wrap
}
QQC2.Label {
Layout.fillWidth: true
text: model.DescriptionRole
opacity: listItem.hovered ? 0.8 : 0.6
wrapMode: Text.Wrap
}
QQC2.Label {
id: aboutItem
Layout.fillWidth: true
text: i18n("Author: %1\nLicense: %2", model.AuthorNameRole, model.LicenseRole)
opacity: listItem.hovered ? 0.8 : 0.6
visible: listItem.ListView.isCurrentItem
wrapMode: Text.Wrap
}
Loader {
id: videoItem
active: false
source: "Video.qml"
visible: false
function showHide() {
if (!videoItem.active) {
videoItem.active = true;
videoItem.visible = true;
} else {
videoItem.active = false;
videoItem.visible = false;
}
}
}
}
QQC2.ToolButton {
visible: model.VideoRole.toString() !== ""
icon.name: "videoclip-amarok"
text: i18nc("@info:tooltip", "Show/Hide Video")
display: QQC2.AbstractButton.IconOnly
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
onClicked: videoItem.showHide()
}
QQC2.ToolButton {
visible: model.ConfigurableRole
enabled: model.StatusRole != Qt.Unchecked
icon.name: "configure"
text: i18nc("@info:tooltip", "Configure…")
display: QQC2.AbstractButton.IconOnly
QQC2.ToolTip.text: text
QQC2.ToolTip.visible: hovered
onClicked: kcm.configure(model.ServiceNameRole, listItem)
}
}
}
@@ -0,0 +1,43 @@
/*
SPDX-FileCopyrightText: 2013 Antonis Tsiapaliokas <kok3rs@gmail.com>
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import QtMultimedia as Multimedia
Multimedia.Video {
id: videoItem
source: model.VideoRole
width: 400
height: 400
QQC2.BusyIndicator {
anchors.centerIn: parent
visible: videoItem.status === Multimedia.MediaPlayer.Loading
running: true
}
QQC2.Button {
id: replayButton
visible: false
anchors.centerIn: parent
icon.name: "media-playback-start"
onClicked: {
replayButton.visible = false;
videoItem.play();
}
}
onStopped: {
replayButton.visible = true
}
}
@@ -0,0 +1,113 @@
/*
SPDX-FileCopyrightText: 2013 Antonis Tsiapaliokas <kok3rs@gmail.com>
SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kcmutils
import org.kde.config
import org.kde.kirigami 2 as Kirigami
import org.kde.newstuff as NewStuff
import org.kde.private.kcms.kwin.effects as Private
ScrollViewKCM {
implicitHeight: Kirigami.Units.gridUnit * 30
implicitWidth: Kirigami.Units.gridUnit * 40
actions: NewStuff.Action {
text: i18nc("@action:button get new KWin effects", "Get New…")
visible: KAuthorized.authorize(KAuthorized.GHNS)
configFile: "kwineffect.knsrc"
onEntryEvent: (entry, event) => {
if (event === NewStuff.Engine.StatusChangedEvent) {
kcm.onGHNSEntriesChanged()
}
}
}
header: RowLayout {
spacing: Kirigami.Units.smallSpacing
Kirigami.SearchField {
id: searchField
Layout.fillWidth: true
}
QQC2.ToolButton {
id: filterButton
icon.name: "view-filter"
checkable: true
checked: menu.opened
onClicked: menu.popup(filterButton, filterButton.width - menu.width, filterButton.height)
QQC2.ToolTip {
text: i18n("Configure Filter")
}
}
QQC2.Menu {
id: menu
modal: true
QQC2.MenuItem {
checkable: true
checked: searchModel.excludeUnsupported
text: i18n("Exclude unsupported effects")
onToggled: searchModel.excludeUnsupported = checked
}
}
}
view: ListView {
id: effectsList
// { string name: QQC2.ButtonGroup group }
property var _buttonGroups: new Map()
clip: true
model: Private.EffectsFilterProxyModel {
id: searchModel
query: searchField.text
sourceModel: kcm.effectsModel
}
delegate: Effect {
width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
}
section.property: "CategoryRole"
section.delegate: Kirigami.ListSectionHeader {
width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
text: section
}
Component {
id: buttonGroupComponent
QQC2.ButtonGroup {}
}
function findButtonGroup(name: string): QQC2.ButtonGroup {
let group = _buttonGroups.get(name);
if (group === undefined) {
group = buttonGroupComponent.createObject(this);
_buttonGroups.set(name, group);
}
return group;
}
}
}
@@ -0,0 +1,12 @@
Please use https://bugs.kde.org to report bugs.
The following authors may have retired by the time you read this :-)
KWM Configuration Module:
Pat Dowler (dowler@pt1B1106.FSH.UVic.CA)
Bernd Wuebben <wuebben@kde.org>
Conversion to kcontrol applet:
Matthias Hoelzer (hoelzer@physik.uni-wuerzburg.de)
@@ -0,0 +1,34 @@
########### next target ###############
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwm\")
set(kcm_kwinoptions_PART_SRCS
main.cpp
mouse.cpp
windows.cpp
)
ki18n_wrap_ui(kcm_kwinoptions_PART_SRCS
actions.ui
advanced.ui
focus.ui
mouse.ui
moving.ui
)
kcmutils_generate_module_data(
kcm_kwinoptions_PART_SRCS
MODULE_DATA_HEADER kwinoptionsdata.h
MODULE_DATA_CLASS_NAME KWinOptionsData
SETTINGS_HEADERS kwinoptions_settings.h kwinoptions_kdeglobals_settings.h
SETTINGS_CLASSES KWinOptionsSettings KWinOptionsKDEGlobalsSettings
)
kconfig_add_kcfg_files(kcm_kwinoptions_PART_SRCS kwinoptions_settings.kcfgc GENERATE_MOC)
kconfig_add_kcfg_files(kcm_kwinoptions_PART_SRCS kwinoptions_kdeglobals_settings.kcfgc GENERATE_MOC)
qt_add_dbus_interface(kcm_kwinoptions_PART_SRCS ${KWin_SOURCE_DIR}/src/org.kde.kwin.Effects.xml kwin_effects_interface)
kcoreaddons_add_plugin(kcm_kwinoptions SOURCES ${kcm_kwinoptions_PART_SRCS} INSTALL_NAMESPACE "plasma/kcms/systemsettings_qwidgets")
kcmutils_generate_desktop_file(kcm_kwinoptions)
target_link_libraries(kcm_kwinoptions kwin Qt::DBus KF6::KCMUtils KF6::I18n KF6::WindowSystem)
@@ -0,0 +1,51 @@
1999-03-06 Mario Weilguni <mweilguni@kde.org>
* changes for Qt 2.0
1998-11-29 Alex Zepeda <garbanzo@hooked.net>
* pics/Makefile.am, pics/mini/Makefile.am: Install icons from their
"proper" subdirectories.
1998-11-20 Cristian Tibirna <ctibirna@gch.ulaval.ca>
* advanced.[cpp,h]: fixed bugs. Mostly a disgusting one:
no lists saving for the special options (Decor, Focus a.o.)
1998-11-09 Cristian Tibirna <ctibirna@gch.ulaval.ca>
* advanced.[cpp,h] : new tab for some of the last of the
kwm's options which remained out of the GUI config:
CtrlTab, TraverseAll, AltTabeMode, Button3Grab and
the filter lists for decorations, focus, stickyness,
session management ignore ( I kinda disklike the solution
I got for the latest)
1998-11-06 Cristian Tibirna <ctibirna@gch.ulaval.ca>
* titlebar.[cpp,h] : added title alignment config
1998-10-23 Cristian Tibirna <ctibirna@gch.ulaval.ca>
* titlebar.cpp: completed what Matthias started (took out
useless checks)
* widows.cpp: make autoRaise toggling clearer
1998-10-22 Matthias Ettrich <ettrich@kde.org>
* titlebar.cpp: less options on titlebar doubleclick
1998-10-21 Cristian Tibirna <ctibirna@gch.ulaval.ca>
* desktop.[cpp,h]: now with consistent layout use
resizeEvent() deleted
1998-10-19 Cristian Tibirna <ctibirna@gch.ulaval.ca>
* windows.[cpp,h]: now with consistent layout use
resizeEvent() deleted
1998-10-18 Cristian Tibirna <ctibirna@gch.ulaval.ca>
* titlebar.[cpp,h]: fixed the (in)activetitleebar pixmap selection
1998-10-21 (still buggy, don't quite understand why)
@@ -0,0 +1,3 @@
#! /usr/bin/env bash
$EXTRACTRC `find . -name \*.ui` >> rc.cpp || exit 11
$XGETTEXT *.cpp -o $podir/kcmkwm.pot
@@ -0,0 +1,554 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KWinActionsConfigForm</class>
<widget class="QWidget" name="KWinActionsConfigForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>500</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_1">
<property name="flat">
<bool>true</bool>
</property>
<property name="title">
<string>Inactive Inner Window Actions</string>
</property>
<layout class="QFormLayout" name="formLayout_1">
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_1">
<property name="text">
<string>&amp;Left click:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandWindow1</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_0">
<item>
<widget class="QComboBox" name="kcfg_CommandWindow1">
<property name="whatsThis">
<string>In this row you can customize left click behavior when clicking into an inactive inner window ('inner' means: not titlebar, not frame).</string>
</property>
<item>
<property name="text">
<string>Activate, pass click and raise on release</string>
</property>
</item>
<item>
<property name="text">
<string>Activate, raise and pass click</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and pass click</string>
</property>
</item>
<item>
<property name="text">
<string>Activate</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and raise</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="KContextualHelpButton" name="info_1">
<property name="contextualHelpText">
<string>Note that "Activate, pass click and raise on release" doesn't work on X11, and falls back to "Activate, raise and pass click" instead</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Middle click:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandWindow2</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="kcfg_CommandWindow2">
<property name="whatsThis">
<string>In this row you can customize middle click behavior when clicking into an inactive inner window ('inner' means: not titlebar, not frame).</string>
</property>
<item>
<property name="text">
<string>Activate, raise and pass click</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and pass click</string>
</property>
</item>
<item>
<property name="text">
<string>Activate</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and raise</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&amp;Right click:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandWindow3</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="kcfg_CommandWindow3">
<property name="whatsThis">
<string>In this row you can customize right click behavior when clicking into an inactive inner window ('inner' means: not titlebar, not frame).</string>
</property>
<item>
<property name="text">
<string>Activate, raise and pass click</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and pass click</string>
</property>
</item>
<item>
<property name="text">
<string>Activate</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and raise</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Mouse &amp;wheel:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandWindowWheel</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="kcfg_CommandWindowWheel">
<property name="whatsThis">
<string>In this row you can customize behavior when scrolling into an inactive inner window ('inner' means: not titlebar, not frame).</string>
</property>
<item>
<property name="text">
<string>Scroll</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and scroll</string>
</property>
</item>
<item>
<property name="text">
<string>Activate, raise and scroll</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="flat">
<bool>true</bool>
</property>
<property name="title">
<string>Inner Window, Titlebar and Frame Actions</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<layout class="QFormLayout" name="formLayout_2">
<property name="formAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Mo&amp;difier key:</string>
</property>
<property name="buddy">
<cstring>kcfg_CommandAllKey</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="kcfg_CommandAllKey">
<property name="whatsThis">
<string>Here you select whether holding the Meta key or Alt key will allow you to perform the following actions.</string>
</property>
<item>
<property name="text">
<string>Meta</string>
</property>
</item>
<item>
<property name="text">
<string>Alt</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>0</height>
</size>
</property>
<property name="text">
<string> + </string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>L&amp;eft click:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandAll1</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="kcfg_CommandAll1">
<property name="whatsThis">
<string>In this row you can customize left click behavior when clicking into the titlebar or the frame.</string>
</property>
<item>
<property name="text">
<string>Move</string>
</property>
</item>
<item>
<property name="text">
<string>Activate, raise and move</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Resize</string>
</property>
</item>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Decrease opacity</string>
</property>
</item>
<item>
<property name="text">
<string>Increase opacity</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Middle &amp;click:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandAll2</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="kcfg_CommandAll2">
<property name="whatsThis">
<string>In this row you can customize middle click behavior when clicking into the titlebar or the frame.</string>
</property>
<item>
<property name="text">
<string>Move</string>
</property>
</item>
<item>
<property name="text">
<string>Activate, raise and move</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Resize</string>
</property>
</item>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Decrease opacity</string>
</property>
</item>
<item>
<property name="text">
<string>Increase opacity</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Right clic&amp;k:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandAll3</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="kcfg_CommandAll3">
<property name="whatsThis">
<string>In this row you can customize right click behavior when clicking into the titlebar or the frame.</string>
</property>
<item>
<property name="text">
<string>Move</string>
</property>
</item>
<item>
<property name="text">
<string>Activate, raise and move</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Resize</string>
</property>
</item>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Decrease opacity</string>
</property>
</item>
<item>
<property name="text">
<string>Increase opacity</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Mo&amp;use wheel:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandAllWheel</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="kcfg_CommandAllWheel">
<property name="whatsThis">
<string>Here you can customize KDE's behavior when scrolling with the mouse wheel in a window while pressing the modifier key.</string>
</property>
<item>
<property name="text">
<string>Raise/lower</string>
</property>
</item>
<item>
<property name="text">
<string>Shade/unshade</string>
</property>
</item>
<item>
<property name="text">
<string>Maximize/restore</string>
</property>
</item>
<item>
<property name="text">
<string>Keep above/below</string>
</property>
</item>
<item>
<property name="text">
<string>Move to previous/next desktop</string>
</property>
</item>
<item>
<property name="text">
<string>Change opacity</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_1">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KWinAdvancedConfigForm</class>
<widget class="QWidget" name="KWinAdvancedConfigForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1001</width>
<height>297</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="shadeHoverLabel">
<property name="text">
<string>Window &amp;unshading:</string>
</property>
<property name="buddy">
<cstring>kcfg_ShadeHover</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QCheckBox" name="kcfg_ShadeHover">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If this option is enabled, a shaded window will unshade automatically when the mouse pointer has been over the titlebar for some time.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>On titlebar hover after:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="kcfg_ShadeHoverInterval">
<property name="whatsThis">
<string>Sets the time in milliseconds before the window unshades when the mouse pointer goes over the shaded window.</string>
</property>
<property name="suffix">
<string> ms</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>3000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>250</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="windowPlacementLabel">
<property name="text">
<string>Window &amp;placement:</string>
</property>
<property name="buddy">
<cstring>kcfg_Placement</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="kcfg_Placement">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The placement policy determines where a new window will appear on the desktop.&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Smart&lt;/span&gt; will try to achieve a minimum overlap of windows&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Maximizing&lt;/span&gt; will try to maximize every window to fill the whole screen. It might be useful to selectively affect placement of some windows using the window-specific settings.&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Random&lt;/span&gt; will use a random position&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Centered&lt;/span&gt; will place the window centered&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Zero-cornered&lt;/span&gt; will place the window in the top-left corner&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Under mouse&lt;/span&gt; will place the window under the pointer&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string>Minimal Overlapping</string>
</property>
</item>
<item>
<property name="text">
<string>Maximized</string>
</property>
</item>
<item>
<property name="text">
<string>Random</string>
</property>
</item>
<item>
<property name="text">
<string>Centered</string>
</property>
</item>
<item>
<property name="text">
<string>In Top-Left Corner</string>
</property>
</item>
<item>
<property name="text">
<string>Under mouse</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="kcfg_AllowKDEAppsToRememberWindowPositions">
<property name="whatsThis">
<string>When turned on, apps which are able to remember the positions of their windows are allowed to do so. This will override the window placement mode defined above.</string>
</property>
<property name="text">
<string>Allow apps to remember the positions of their own windows, if they support it</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="activationDesktopPolicyLabel">
<property name="text">
<string>Virtual Desktop behavior:</string>
</property>
<property name="buddy">
<cstring>kcfg_ActivationDesktopPolicy</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="activationDesktopPolicyDescriptionLabel">
<property name="text">
<string>When activating a window on a different Virtual Desktop:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="kcfg_ActivationDesktopPolicy">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This setting controls what happens when an open window located on a Virtual Desktop other than the current one is activated. &lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Switch to that Virtual Desktop&lt;/span&gt; will switch to the Virtual Desktop where the window is currently located. &lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Bring window to current Virtual Desktop&lt;/span&gt; will cause the window to jump to the active Virtual Desktop. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string>Switch to that Virtual Desktop</string>
</property>
</item>
<item>
<property name="text">
<string>Bring window to current Virtual Desktop</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,284 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KWinFocusConfigForm</class>
<widget class="QWidget" name="KWinFocusConfigForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>500</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout_1">
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="windowFocusPolicyLabel">
<property name="text">
<string>Window &amp;activation policy:</string>
</property>
<property name="buddy">
<cstring>windowFocusPolicy</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="windowFocusPolicy">
<property name="whatsThis">
<string>With this option you can specify how and when windows will be focused.</string>
</property>
<item>
<property name="text">
<string comment="sassa asas">Click to focus</string>
</property>
</item>
<item>
<property name="text">
<string>Click to focus (mouse precedence)</string>
</property>
</item>
<item>
<property name="text">
<string>Focus follows mouse</string>
</property>
</item>
<item>
<property name="text">
<string>Focus follows mouse (mouse precedence)</string>
</property>
</item>
<item>
<property name="text">
<string>Focus under mouse</string>
</property>
</item>
<item>
<property name="text">
<string>Focus strictly under mouse</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="delayFocusOnLabel">
<property name="text">
<string>&amp;Delay focus by:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_DelayFocusInterval</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="kcfg_DelayFocusInterval">
<property name="whatsThis">
<string>This is the delay after which the window the mouse pointer is over will automatically receive focus.</string>
</property>
<property name="suffix">
<string> ms</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>3000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="focusStealingLabel">
<property name="text">
<string>Focus &amp;stealing prevention:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_FocusStealingPreventionLevel</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="kcfg_FocusStealingPreventionLevel">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This option specifies how much KWin will try to prevent unwanted focus stealing caused by unexpected activation of new windows. (Note: This feature does not work with the &lt;span style=&quot; font-style:italic;&quot;&gt;Focus under mouse&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Focus strictly under mouse&lt;/span&gt; focus policies.) &lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;None:&lt;/span&gt; Prevention is turned off and new windows always become activated.&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Low:&lt;/span&gt; Prevention is enabled; when some window does not have support for the underlying mechanism and KWin cannot reliably decide whether to activate the window or not, it will be activated. This setting may have both worse and better results than the medium level, depending on the applications.&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Medium:&lt;/span&gt; Prevention is enabled.&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;High:&lt;/span&gt; New windows get activated only if no window is currently active or if they belong to the currently active application. This setting is probably not really usable when not using mouse focus policy.&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Extreme:&lt;/span&gt; All windows must be explicitly activated by the user.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Windows that are prevented from stealing focus are marked as demanding attention, which by default means their taskbar entry will be highlighted. This can be changed in the Notifications control module.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string extracomment="Focus Stealing Prevention Level">None</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="Focus Stealing Prevention Level">Low</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="Focus Stealing Prevention Level">Medium</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="Focus Stealing Prevention Level">High</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="Focus Stealing Prevention Level">Extreme</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="raisingWindowsLabel">
<property name="text">
<string>Raising windows:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="kcfg_ClickRaise">
<property name="whatsThis">
<string>When this option is enabled, the active window will be brought to the front when you click somewhere into the window contents. To change it for inactive windows, you need to change the settings in the Actions tab.</string>
</property>
<property name="text">
<string>&amp;Click raises active window</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QCheckBox" name="kcfg_AutoRaise">
<property name="whatsThis">
<string>When this option is enabled, a window in the background will automatically come to the front when the mouse pointer has been over it for some time.</string>
</property>
<property name="text">
<string>&amp;Raise on hover, delayed by:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="kcfg_AutoRaiseInterval">
<property name="enabled">
<bool>false</bool>
</property>
<property name="whatsThis">
<string>This is the delay after which the window that the mouse pointer is over will automatically come to the front.</string>
</property>
<property name="suffix">
<string> ms</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>3000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QLabel" name="multiscreenBehaviorLabel">
<property name="text">
<string>Multiscreen behavior:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="kcfg_SeparateScreenFocus">
<property name="whatsThis">
<string>When this option is enabled, focus operations are limited only to the active screen</string>
</property>
<property name="text">
<string>&amp;Separate screen focus</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="windowFocusPolicyDescriptionLabel">
<property name="minimumSize">
<size>
<width>280</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Window activation policy description</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>kcfg_AutoRaise</sender>
<signal>toggled(bool)</signal>
<receiver>kcfg_AutoRaiseInterval</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>338</x>
<y>189</y>
</hint>
<hint type="destinationlabel">
<x>485</x>
<y>189</y>
</hint>
</hints>
</connection>
<connection>
<sender>kcfg_AutoRaise</sender>
<signal>toggled(bool)</signal>
<receiver>kcfg_ClickRaise</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>338</x>
<y>189</y>
</hint>
<hint type="destinationlabel">
<x>333</x>
<y>155</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,139 @@
{
"Categories": "Qt;KDE;X-KDE-settings-looknfeel;",
"KPlugin": {
"BugReportUrl": "https://bugs.kde.org/enter_bug.cgi?product=systemsettings&component=kcm_kwinoptions",
"Description": "Configure window actions and behavior",
"Description[ar]": "اضبط سلوك النوافذ وإجراءاتها",
"Description[az]": "Pəncərə fəaliyyətləri və davranışlarını tənzimləyin",
"Description[be]": "Наладжванне дзеянняў і паводзін акон",
"Description[bg]": "Настройки на поведение и действия на прозорците",
"Description[ca@valencia]": "Configura les accions i comportament de les finestres",
"Description[ca]": "Configura les accions i comportament de les finestres",
"Description[cs]": "Nastavte činností a chování oken",
"Description[da]": "Konfigurér vindueshandlinger og -opførsel",
"Description[de]": "Fenster-Aktionen und -verhalten einrichten",
"Description[en_GB]": "Configure window actions and behaviour",
"Description[eo]": "Agordi fenestrajn agojn kaj konduton",
"Description[es]": "Configurar las acciones y el comportamiento de las ventanas",
"Description[et]": "Akende toimingute ja käitumise seadistamine",
"Description[eu]": "Konfiguratu leihoaren ekintzak eta jokabidea",
"Description[fi]": "Ikkunoiden toiminnan asetukset",
"Description[fr]": "Configurer les actions et le comportement des fenêtres",
"Description[gl]": "Configurar o comportamento e as accións das xanelas.",
"Description[he]": "הגדרות פעולות והתנהגות חלון",
"Description[hu]": "Az ablakműveletek és -működés beállítása",
"Description[ia]": "Cnfigura comportamento e actiones de fenestra",
"Description[id]": "Konfigurasikan perilaku dan aksi jendela",
"Description[is]": "Grunnstilla aðgerðir og hegðun glugga",
"Description[it]": "Configura azioni e comportamento delle finestre",
"Description[ja]": "ウィンドウのアクションと挙動を設定",
"Description[ka]": "ფანჯრის ქმედებისა და ქცევის მორგება",
"Description[ko]": "창 동작과 행동 설정",
"Description[lt]": "Konfigūruoti langų elgseną ir veiksmus su jais",
"Description[lv]": "Konfigurēt logu darbības un uzvedību",
"Description[nb]": "Sett opp utseende og atferd for vindu",
"Description[nl]": "Vensteracties en gedrag configureren",
"Description[nn]": "Set opp utsjånad og åtferd for vindauge",
"Description[pl]": "Ustawienia działań i zachowań okien",
"Description[pt]": "Configurar as acções e comportamento das janelas",
"Description[pt_BR]": "Configure as ações e comportamento das janelas",
"Description[ro]": "Configurează acțiunile și comportamentul ferestrelor",
"Description[ru]": "Настройка поведения окон",
"Description[sa]": "विण्डो क्रियाः व्यवहारः च विन्यस्यताम्",
"Description[sk]": "Nastaviť akcie a správanie okien",
"Description[sl]": "Prilagodite dejavnosti in vedenje oken",
"Description[sv]": "Anpassa fönsteråtgärder och beteende",
"Description[ta]": "சாளர நடத்தையையும் செயல்களையும் அமையுங்கள்",
"Description[tr]": "Pencere eylemlerini ve davranışını yapılandır",
"Description[uk]": "Налаштовування реакції та поведінки вікон",
"Description[vi]": "Cấu hình các hành động và ứng xử của cửa sổ",
"Description[x-test]": "xxConfigure window actions and behaviorxx",
"Description[zh_CN]": "配置窗口操作和行为",
"Description[zh_TW]": "設定視窗動作與行為",
"Icon": "preferences-system-windows-actions",
"Name": "Window Behavior",
"Name[ar]": "سلوك النوافذ",
"Name[az]": "Pəncərə davranışı",
"Name[be]": "Паводзіны акон",
"Name[bg]": "Поведение на прозорците",
"Name[ca@valencia]": "Comportament de les finestres",
"Name[ca]": "Comportament de les finestres",
"Name[cs]": "Chování oken",
"Name[da]": "Vinduesopførsel",
"Name[de]": "Fensterverhalten",
"Name[en_GB]": "Window Behaviour",
"Name[eo]": "Fenestra Konduto",
"Name[es]": "Comportamiento de las ventanas",
"Name[et]": "Akende käitumine",
"Name[eu]": "Leihoen jokabidea",
"Name[fi]": "Ikkunoiden toiminta",
"Name[fr]": "Comportement des fenêtres",
"Name[gl]": "Comportamento das xanelas",
"Name[he]": "התנהגות חלון",
"Name[hu]": "Ablakműködés",
"Name[ia]": "Comportamento de fenestra",
"Name[id]": "Perilaku Jendela",
"Name[is]": "Gluggahegðun",
"Name[it]": "Comportamento delle finestre",
"Name[ja]": "ウィンドウの挙動",
"Name[ka]": "ფანჯრის ქცევა",
"Name[ko]": "창 동작",
"Name[lt]": "Langų elgsena",
"Name[lv]": "Logu uzvedība",
"Name[nb]": "Vindusatferd",
"Name[nl]": "Venstergedrag",
"Name[nn]": "Vindaugs­åtferd",
"Name[pl]": "Zachowania okien",
"Name[pt]": "Comportamento das Janelas",
"Name[pt_BR]": "Comportamento das janelas",
"Name[ro]": "Comportament ferestre",
"Name[ru]": "Поведение окон",
"Name[sa]": "खिडकी व्यवहार",
"Name[sk]": "Správanie okien",
"Name[sl]": "Vedenje oken",
"Name[sv]": "Fönsterbeteende",
"Name[ta]": "சாளர நடத்தை",
"Name[tr]": "Pencere Davranışı",
"Name[uk]": "Поведінка вікон",
"Name[vi]": "Ứng xử của cửa sổ",
"Name[x-test]": "xxWindow Behaviorxx",
"Name[zh_CN]": "窗口行为",
"Name[zh_TW]": "視窗行為"
},
"X-DocPath": "kcontrol/windowbehaviour/index.html",
"X-KDE-Keywords": "focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,desktop,snap,movement,shading,shade,unshade,unshading,activation,activate",
"X-KDE-Keywords[ar]": "التركيز,الموضع,سلوك النافذة,إجراءات النافذة,الرسوم المتحركة,الرفع,الرفع التلقائي,النوافذ,الإطار,شريط العنوان,النقر المزدوج,سطح المكتب,الالتقاط,الحركة,التظليل,التظليل,إزالة التظليل,إزالة التظليل,نشط,التنشيط",
"X-KDE-Keywords[bg]": "фокус,разположение,поведение на прозореца,действия на прозореца,анимация,повдигане,автоматично повдигане,прозорци,рамка,заглавна лента,двойно щракване,работен плот,щракване,движение,засенчване,засенчване,премахване засенчване,премахване засенчване,активиране,активиране",
"X-KDE-Keywords[ca@valencia]": "focus,emplaçament,comportament de les finestres,accions de les finestres,animació,elevació,elevació automàtica,finestres,marc,barra de títol,doble clic,escriptori,ajusta,moviment,ombreig,ombra,desombreja,desombreig,activació,activa",
"X-KDE-Keywords[ca]": "focus,emplaçament,comportament de les finestres,accions de les finestres,animació,elevació,elevació automàtica,finestres,marc,barra de títol,doble clic,escriptori,ajusta,moviment,ombreig,ombra,desombreja,desombreig,activació,activa",
"X-KDE-Keywords[en_GB]": "focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,desktop,snap,movement,shading,shade,unshade,unshading,activation,activate",
"X-KDE-Keywords[es]": "foco,colocación,ubicación,situación,comportamiento de la ventana,acciones de la ventana,animación,elevar,primer plano,elevar automáticamente,pasar a primer plano,ventanas,marco,borde,barra de título,doble clic,escritorio,ajuste,movimiento,plegar,desplegar,recoger,expandir,activación,activar",
"X-KDE-Keywords[eu]": "fokua,arreta,jartzea,leihoaren jokabidea,leihoaren ekintzak,animazioa,altxatu,automatikoki altxatu,leihoak,markoa,fotograma,titulu-barra,klik bikoitza,mahaigaina,atxiki,mugimendua,itzaldura,itzala,geriza,itzala kendu,itzala kentzea,aktibazioa,aktibatu",
"X-KDE-Keywords[fi]": "kohdistus,fokus,sijoittaminen,sijoitus,ikkunan toiminta,ikkunatoiminnot,animointi,animaatio,nosta,automaattinosto,kehys,otsikkorivi,otsikkopalkki,kaksoisnapsautus,työpöytä,kiinnitä,kiinnitys,snap,liike,siirtyminen,varjostus,aktivoi,aktivointi,aktivaatio",
"X-KDE-Keywords[fr]": "focus, placement, comportement des fenêtres, actions des fenêtres, animation, relance, relance automatique, fenêtres, cadre, barre de titre, double-clic, bureau, aimantation, mouvement,ombrage, ombrer, dé-ombrer, dé-ombrage, activation, activer",
"X-KDE-Keywords[gl]": "foco,posicionamento,comportamento das xanelas,accións das xanelas, animación,xanelas,moldura,barra de título,marco,desktop,escritorio,snap,axustar,aliñar,movement,movemento,shading,sombra,shade,unshade,unshading,activation,activación,activate,activar",
"X-KDE-Keywords[he]": "מיקוד,הצבה,מיקום,מקום,התנהגות חלון,פעולות חלון,הנפשה,הגבהה,הרמה,הגבהה אוטומטית,הרמה אוטומטית,חלונות,מסגרת,שורת כותרת,לחיצה כפולה,דאבלקליק,דאבל קליק,הצמדה,תנועה,תזוזה,צל,הצללה,צללית,ביטול הצללה,הפעלה,מופעל,פועל,פעיל,פעילות",
"X-KDE-Keywords[hu]": "fókusz,elhelyezés,ablakműködés,ablakműveletek,animáció,felemelés,automatikus felemelés,keret,címsor,dupla kattintás,asztal,levágás,mozgatás,felgördítés,felgördít,legördít,legördítés,aktiválás,aktivál",
"X-KDE-Keywords[ia]": "focus,placiamento,comportamento de fenestra,actiones de fenestra,animation,altiar,auto altiar,fenestras,quadro,barra de titulo,duple click,scriptorio, snap, movemento, umbrar, umbra,de umbra,deumbrar,activation,activar",
"X-KDE-Keywords[is]": "fókus,staðsetning,gluggahegðun,gluggaaðgerðir,hreyfiáhrif,hækka,hækka sjálfvirkt,gluggar,rammi,titilstika,tvísmella,skjáborð,smella,hreyfing,rúllun,rúlla upp,rúlla niður,niðurrúllun,virkjun,virkja",
"X-KDE-Keywords[it]": "fuoco,posizionamento,comportamento della finestra,azioni delle finestre,animazione,sollevamento,sollevamento automatico,finestre,riquadro,barra del titolo,doppio clic,desktop,snap,movimento,arrotolare,arrotola,srotola,srotolare,attivazione,attivare",
"X-KDE-Keywords[ka]": "focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,desktop,snap,movement,shading,shade,unshade,unshading,activation,activate,ფოკუსი, მოთავსება,ფანჯრის ქცევა,ფანჯრების ქცევა,ანიმაცია,ამოწევა,ავტოამოწევა,ფანჯრები,ჩარჩო,სათაურის ზოლი,სამუშაო მაგიდა,მიმაგრება,დაჩრდილვა",
"X-KDE-Keywords[ko]": "포커스,초점,위치,창 행동,애니메이션,올리기,창,프레임,제목 표시줄,바탕 화면,데스크톱,이동,말아 올리기,풀어 내리기,활성화,활성,클릭,두 번 클릭",
"X-KDE-Keywords[lv]": "fokuss,novietojums,logu uzvedība,logu darbības,animācija,pacelt,automātiski pacelt,logi,apmale,rāmis,virsrakstjosla,dubultklikšķis,darbvirsma,pievilkšana,pārvietošana,ēnošana,ēna,noņemt ēnu,ēnas noņemšana,aktivizēšana,aktivizēt",
"X-KDE-Keywords[nb]": "fokus,plassering,vindusatferd,vindusbehandler,animering,hev,autohev,vindu,ramme,tittellinje,dobbeltklikk,skrivebord,flytting,bevegelse,opprulling,nedrulling,skjuling,aktivering,aktivere",
"X-KDE-Keywords[nl]": "focus,plaatsing,venstergedrag,vensteracties,animatie,omhoog brengen, automatisch omhoog brengen,vensters,frame,titelbalk,dubbel-klik,bureaublad,vastklikken,verplaatsing,schaduw aanbrengen,schaduw,schaduw weghalen,activatie,activeren",
"X-KDE-Keywords[nn]": "fokus,plassering,vindaugsåtferd,vindaugshandlingar,animering,hev,autohev,vindauge,ramme,tittellinje,dobbeltklikk,skrivebord,flytting,rørsle,opprulling,nedrulling,gøyming,aktivering,aktivera",
"X-KDE-Keywords[pl]": "uaktywnienie,umieszczenie,zachowanie okna,działania okien,animacja,wzniesienie,auto-wzniesienie, okna,ramka,pasek tytułu,dwukrotne kliknięcie,pulpit,przyciąganie,ruch,zwijanie,zwiń,rozwiń,rozwijanie,uaktywnianie,uaktywnij",
"X-KDE-Keywords[pt_BR]": "foco,colocação,comportamento de janela,ações de janela,animação,levantar,levantar automático,janelas,quadro,barra de título,duplo clique,área de trabalho,encaixe,movimento,sombreamento,escurecer,clarear,desescurecimento,ativação,ativar",
"X-KDE-Keywords[ru]": "focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,desktop,snap,movement,shading,shade,unshade,unshading,activation,activate,фокус,расположение,размещение,поведение окон,действия окна,анимация,поднять,поднять автоматически,автоматическое поднятие,окна,рамка,строка заголовка,заголовок,двойной щелчок,рабочий стол,привязка,прилипание,перемещение,сворачивание в заголовок,свернуть в заголовок,разворачивание из заголовка,развернуть из заголовка,активация,активировать",
"X-KDE-Keywords[sa]": "फोकस,प्लेसमेंट,विंडो व्यवहार,विंडो क्रियाएँ,एनीमेशन,उत्थापन,स्वयं उठाना,विंडोज,फ्रेम,शीर्षकपट्टी,डबलक्लिक,डेस्कटॉप,स्नैप,मूवमेंट,छायाकरण,छाया,अनशेड,अनशेडिंग,सक्रियता,सक्रिय",
"X-KDE-Keywords[sl]": "fokus,postavitev,vedenje okna,dejanja oken,animacija,dvig,samodejni dvig,okna,okvir,naslovna vrstica,dvoklik,namizje,pripenjanje,gibanje,senčenje,senčenje,odsenči,odsenčenje,aktivacija,aktiviraj",
"X-KDE-Keywords[sv]": "fokus,placering,fönsterbeteende,fönsteråtgärder,animering,höjning,automatisk höjning,fönster,ram,namnlist,dubbelklicka,skrivbord,lås,rörelse,rulla upp, rulla ner,aktivering,aktivera",
"X-KDE-Keywords[tr]": "odak,yerleşim,pencere davranışı,pencere eylemleri,canlandırma,animasyon,yükselt,çerçeve,başlık çubuğu,çift tık,masaüstü,tuttur,hareket,taşı,panjur,etkinleştir",
"X-KDE-Keywords[uk]": "focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,desktop,snap,movement,shading,shade,unshade,unshading,activation,activate,фокус,розташування,місце,вікно,поведінка,поведінка вікон,дії,реакція,дії з вікнами,реакція вікон,анімація,підняти,підняття,автоматична,автоматично,рамка,заголовок,смужка заголовка,клацання,подвійне,стільниця,прилипання,рух,тіні,тінь,активація,активувати",
"X-KDE-Keywords[x-test]": "xxfocusxx,xxplacementxx,xxwindow behaviorxx,xxwindow actionsxx,xxanimationxx,xxraisexx,xxauto raisexx,xxwindowsxx,xxframexx,xxtitlebarxx,xxdoubleclickxx,xxdesktopxx,xxsnapxx,xxmovementxx,xxshadingxx,xxshadexx,xxunshadexx,xxunshadingxx,xxactivationxx,xxactivatexx",
"X-KDE-Keywords[zh_CN]": "focus,placement,window behavior,window actions,animation,raise,auto raise,windows,frame,titlebar,doubleclick,desktop,snap,movement,shading,shade,unshade,unshading,activation,activate,jiaodian,fangzhi,weizhi,chuangkouxingwei,chuangkoucaozuo,donghua,tisheng,zidongtisheng,chuangkou,kuangjia,biaotilan,shuangji,zhuomian,xifu,yidong,juanqi,zhankai,jihuo,焦点,放置,位置,窗口行为,窗口操作,动画,提升,自动提升,窗口,框架,标题栏,双击,桌面,吸附,移动,卷起,展开,激活",
"X-KDE-Keywords[zh_TW]": "焦點,聚焦,視窗行為,視窗動作,動畫,抬升,提升,自動抬升,視窗,框架,邊框,標題列,標題欄,雙擊,連點,桌面,貼齊,移動,隱藏,觸發",
"X-KDE-System-Settings-Parent-Category": "windowmanagement",
"X-KDE-Weight": 10
}
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 name="kdeglobals"/>
<group name="General">
<entry name="AllowKDEAppsToRememberWindowPositions" type="Bool">
<default>true</default>
</entry>
</group>
</kcfg>
@@ -0,0 +1,6 @@
File=kwinoptions_kdeglobals_settings.kcfg
ClassName=KWinOptionsKDEGlobalsSettings
IncludeFiles=options.h
Mutators=true
DefaultValueGetters=true
ParentInConstructor=true
@@ -0,0 +1,368 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 name="kwinrc"/>
<group name="Windows">
<entry key="BorderSnapZone" type="Int">
<default>10</default>
<min>0</min>
<max>100</max>
</entry>
<entry key="WindowSnapZone" type="Int">
<default>10</default>
<min>0</min>
<max>100</max>
</entry>
<entry key="CenterSnapZone" type="Int">
<default>0</default>
<min>0</min>
<max>100</max>
</entry>
<entry key="SnapOnlyWhenOverlapping" type="Bool">
<default>false</default>
</entry>
<entry key="ShadeHover" type="Bool">
<default>false</default>
</entry>
<entry key="ShadeHoverInterval" type="Int">
<default>250</default>
<min>0</min>
</entry>
<entry name="Placement" type="Enum">
<choices name="PlacementChoices">
<choice name="Smart"></choice>
<choice name="Maximizing"></choice>
<choice name="Random"></choice>
<choice name="Centered"></choice>
<choice name="ZeroCornered"></choice>
<choice name="UnderMouse"></choice>
</choices>
<default>Centered</default>
</entry>
<entry name="ActivationDesktopPolicy" type="Enum">
<choices name="ActivationDesktopPolicyChoices">
<choice name="SwitchToOtherDesktop"></choice>
<choice name="BringToCurrentDesktop"></choice>
</choices>
<default>SwitchToOtherDesktop</default>
</entry>
<entry key="TitlebarDoubleClickCommand" type="Enum">
<default>Maximize</default>
<choices>
<choice name="Maximize"></choice>
<choice name="MaximizeVerticalOnly" value="Maximize (vertical only)"></choice>
<choice name="MaximizeHorizontalOnly" value="Maximize (horizontal only)"></choice>
<choice name="Minimize"></choice>
<choice name="Shade"></choice>
<choice name="Lower"></choice>
<choice name="Close"></choice>
<choice name="OnAllDesktops"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="MaximizeButtonLeftClickCommand" type="Enum">
<default>Maximize</default>
<choices>
<choice name="Maximize"></choice>
<choice name="MaximizeVerticalOnly" value="Maximize (vertical only)"></choice>
<choice name="MaximizeHorizontalOnly" value="Maximize (horizontal only)"></choice>
</choices>
</entry>
<entry key="MaximizeButtonMiddleClickCommand" type="Enum">
<default>MaximizeVerticalOnly</default>
<choices>
<choice name="Maximize"></choice>
<choice name="MaximizeVerticalOnly" value="Maximize (vertical only)"></choice>
<choice name="MaximizeHorizontalOnly" value="Maximize (horizontal only)"></choice>
</choices>
</entry>
<entry key="MaximizeButtonRightClickCommand" type="Enum">
<default>MaximizeHorizontalOnly</default>
<choices>
<choice name="Maximize"></choice>
<choice name="MaximizeVerticalOnly" value="Maximize (vertical only)"></choice>
<choice name="MaximizeHorizontalOnly" value="Maximize (horizontal only)"></choice>
</choices>
</entry>
<entry key="FocusPolicy" type="Enum">
<default>ClickToFocus</default>
<choices>
<choice name="ClickToFocus"/>
<choice name="FocusFollowsMouse"/>
<choice name="FocusUnderMouse"/>
<choice name="FocusStrictlyUnderMouse"/>
</choices>
</entry>
<entry key="NextFocusPrefersMouse" type="Bool">
<default>false</default>
</entry>
<entry key="AutoRaiseInterval" type="Int">
<default>750</default>
<min>0</min>
</entry>
<entry key="DelayFocusInterval" type="Int">
<default>300</default>
<min>0</min>
</entry>
<entry key="AutoRaise" type="Bool">
<default>false</default>
</entry>
<entry key="ClickRaise" type="Bool">
<default>true</default>
</entry>
<entry key="SeparateScreenFocus" type="Bool">
<default>true</default>
</entry>
<entry key="FocusStealingPreventionLevel" type="Int">
<default>1</default>
<min>0</min>
<max>4</max>
</entry>
</group>
<group name="MouseBindings">
<entry key="CommandActiveTitlebar1" type="Enum">
<default>Raise</default>
<choices>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Minimize"></choice>
<choice name="Shade"></choice>
<choice name="Close"></choice>
<choice name="OperationsMenu" value="Operations menu"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandActiveTitlebar2" type="Enum">
<default>Nothing</default>
<choices>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Minimize"></choice>
<choice name="Shade"></choice>
<choice name="Close"></choice>
<choice name="OperationsMenu" value="Operations menu"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandActiveTitlebar3" type="Enum">
<default>OperationsMenu</default>
<choices>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Minimize"></choice>
<choice name="Shade"></choice>
<choice name="Close"></choice>
<choice name="OperationsMenu" value="Operations menu"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandTitlebarWheel" type="Enum">
<default>Nothing</default>
<choices>
<choice name="RaiseLower" value="Raise/Lower"></choice>
<choice name="ShadeUnshade" value="Shade/Unshade"></choice>
<choice name="MaxmizeRestore" value="Maximize/Restore"></choice>
<choice name="AboveBelow" value="Above/Below"></choice>
<choice name="PreviousNextDesktop" value="Previous/Next Desktop"></choice>
<choice name="ChangeOpacity" value="Change Opacity"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandInactiveTitlebar1" type="Enum">
<default>ActivateRaiseOnReleaseAndPassClick</default>
<choices>
<choice name="ActivateRaiseOnReleaseAndPassClick" value="Activate, pass click and raise on release"></choice>
<choice name="ActivateAndRaise" value="Activate and raise"></choice>
<choice name="ActivateAndLower" value="Activate and lower"></choice>
<choice name="Activate"></choice>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Minimize"></choice>
<choice name="Shade"></choice>
<choice name="Close"></choice>
<choice name="OperationsMenu" value="Operations menu"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandInactiveTitlebar2" type="Enum">
<default>Nothing</default>
<choices>
<choice name="ActivateAndRaise" value="Activate and raise"></choice>
<choice name="ActivateAndLower" value="Activate and lower"></choice>
<choice name="Activate"></choice>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Minimize"></choice>
<choice name="Shade"></choice>
<choice name="Close"></choice>
<choice name="OperationsMenu" value="Operations menu"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandInactiveTitlebar3" type="Enum">
<default>OperationsMenu</default>
<choices>
<choice name="ActivateAndRaise" value="Activate and raise"></choice>
<choice name="ActivateAndLower" value="Activate and lower"></choice>
<choice name="Activate"></choice>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Minimize"></choice>
<choice name="Shade"></choice>
<choice name="Close"></choice>
<choice name="OperationsMenu" value="Operations menu"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandWindow1" type="Enum">
<default>ActivateRaisePassClick</default>
<choices>
<choice name="ActivateRaisePassClick" value="Activate, raise and pass click"></choice>
<choice name="ActivatePassClick" value="Activate and pass click"></choice>
<choice name="Activate"></choice>
<choice name="ActivateRaise" value="Activate and raise"></choice>
</choices>
</entry>
<entry key="CommandWindow2" type="Enum">
<default>ActivatePassClick</default>
<choices>
<choice name="ActivateRaisePassClick" value="Activate, raise and pass click"></choice>
<choice name="ActivatePassClick" value="Activate and pass click"></choice>
<choice name="Activate"></choice>
<choice name="ActivateRaise" value="Activate and raise"></choice>
</choices>
</entry>
<entry key="CommandWindow3" type="Enum">
<default>ActivatePassClick</default>
<choices>
<choice name="ActivateRaisePassClick" value="Activate, raise and pass click"></choice>
<choice name="ActivatePassClick" value="Activate and pass click"></choice>
<choice name="Activate"></choice>
<choice name="ActivateRaise" value="Activate and raise"></choice>
</choices>
</entry>
<entry key="CommandWindowWheel" type="Enum">
<default>Scroll</default>
<choices>
<choice name="Scroll"></choice>
<choice name="ActivateScroll" value="Activate and scroll"></choice>
<choice name="ActivateRaiseAndScroll" value="Activate, raise and scroll"></choice>
</choices>
</entry>
<entry key="CommandAllKey" type="Enum">
<default>Meta</default>
<choices>
<choice name="Meta"></choice>
<choice name="Alt"></choice>
</choices>
</entry>
<entry key="CommandAll1" type="Enum">
<default>Move</default>
<choices>
<choice name="Move"></choice>
<choice name="ActivateRaiseAndMove" value="Activate, raise and move"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Resize"></choice>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="Minimize"></choice>
<choice name="DecreaseOpacity" value="Decrease Opacity"></choice>
<choice name="IncreaseOpactiy" value="Increase Opacity"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandAll2" type="Enum">
<default>ToggleRaiseAndLower</default>
<choices>
<choice name="Move"></choice>
<choice name="ActivateRaiseAndMove" value="Activate, raise and move"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Resize"></choice>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="Minimize"></choice>
<choice name="DecreaseOpacity" value="Decrease Opacity"></choice>
<choice name="IncreaseOpactiy" value="Increase Opacity"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandAll3" type="Enum">
<default>Resize</default>
<choices>
<choice name="Move"></choice>
<choice name="ActivateRaiseAndMove" value="Activate, raise and move"></choice>
<choice name="ToggleRaiseAndLower" value="Toggle raise and lower"></choice>
<choice name="Resize"></choice>
<choice name="Raise"></choice>
<choice name="Lower"></choice>
<choice name="Minimize"></choice>
<choice name="DecreaseOpacity" value="Decrease Opacity"></choice>
<choice name="IncreaseOpactiy" value="Increase Opacity"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="CommandAllWheel" type="Enum">
<default>Nothing</default>
<choices>
<choice name="RaiseLower" value="Raise/Lower"></choice>
<choice name="ShadeUnshade" value="Shade/Unshade"></choice>
<choice name="MaxmizeRestore" value="Maximize/Restore"></choice>
<choice name="AboveBelow" value="Above/Below"></choice>
<choice name="PreviousNextDesktop" value="Previous/Next Desktop"></choice>
<choice name="ChangeOpacity" value="Change Opacity"></choice>
<choice name="Nothing"></choice>
</choices>
</entry>
<entry key="DoubleClickBorderToMaximize" type="Bool">
<default>true</default>
</entry>
</group>
</kcfg>
@@ -0,0 +1,6 @@
File=kwinoptions_settings.kcfg
ClassName=KWinOptionsSettings
IncludeFiles=options.h
Mutators=true
DefaultValueGetters=true
ParentInConstructor=true
@@ -0,0 +1,229 @@
/*
SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "main.h"
#include <QLayout>
// Added by qt3to4:
#include <QVBoxLayout>
#include <QtDBus>
#include <KLocalizedString>
#include <KPluginFactory>
#include <kconfig.h>
#include "kwinoptions_kdeglobals_settings.h"
#include "kwinoptions_settings.h"
#include "kwinoptionsdata.h"
#include "mouse.h"
#include "windows.h"
K_PLUGIN_CLASS_WITH_JSON(KWinOptions, "kcm_kwinoptions.json")
class KFocusConfigStandalone : public KFocusConfig
{
Q_OBJECT
public:
KFocusConfigStandalone(QWidget *parent, const QVariantList &)
: KFocusConfig(true, nullptr, parent)
{
initialize(new KWinOptionsSettings(this));
}
};
class KMovingConfigStandalone : public KMovingConfig
{
Q_OBJECT
public:
KMovingConfigStandalone(QWidget *parent, const QVariantList &)
: KMovingConfig(true, nullptr, parent)
{
initialize(new KWinOptionsSettings(this));
}
};
class KAdvancedConfigStandalone : public KAdvancedConfig
{
Q_OBJECT
public:
KAdvancedConfigStandalone(QWidget *parent, const QVariantList &)
: KAdvancedConfig(true, nullptr, nullptr, parent)
{
initialize(new KWinOptionsSettings(this), new KWinOptionsKDEGlobalsSettings(this));
}
};
KWinOptions::KWinOptions(QObject *parent, const KPluginMetaData &data)
: KCModule(parent, data)
{
mSettings = new KWinOptionsSettings(this);
QVBoxLayout *layout = new QVBoxLayout(widget());
layout->setContentsMargins(0, 0, 0, 0);
tab = new QTabWidget(widget());
tab->setDocumentMode(true);
tab->tabBar()->setExpanding(true);
layout->addWidget(tab);
const auto connectKCM = [this](KCModule *mod) {
connect(mod, &KCModule::needsSaveChanged, this, &KWinOptions::updateUnmanagedState);
connect(this, &KCModule::defaultsIndicatorsVisibleChanged, mod, [mod, this]() {
mod->setDefaultsIndicatorsVisible(defaultsIndicatorsVisible());
});
};
mFocus = new KFocusConfig(false, mSettings, widget());
mFocus->setObjectName(QLatin1String("KWin Focus Config"));
tab->addTab(mFocus->widget(), i18n("&Focus"));
connectKCM(mFocus);
mTitleBarActions = new KTitleBarActionsConfig(false, mSettings, widget());
mTitleBarActions->setObjectName(QLatin1String("KWin TitleBar Actions"));
tab->addTab(mTitleBarActions->widget(), i18n("Titlebar A&ctions"));
connectKCM(mTitleBarActions);
mWindowActions = new KWindowActionsConfig(false, mSettings, widget());
mWindowActions->setObjectName(QLatin1String("KWin Window Actions"));
tab->addTab(mWindowActions->widget(), i18n("W&indow Actions"));
connectKCM(mWindowActions);
mMoving = new KMovingConfig(false, mSettings, widget());
mMoving->setObjectName(QLatin1String("KWin Moving"));
tab->addTab(mMoving->widget(), i18n("Mo&vement"));
connectKCM(mMoving);
mAdvanced = new KAdvancedConfig(false, mSettings, new KWinOptionsKDEGlobalsSettings(this), widget());
mAdvanced->setObjectName(QLatin1String("KWin Advanced"));
tab->addTab(mAdvanced->widget(), i18n("Adva&nced"));
connectKCM(mAdvanced);
}
void KWinOptions::load()
{
KCModule::load();
mTitleBarActions->load();
mWindowActions->load();
mMoving->load();
mAdvanced->load();
// mFocus is last because it may send unmanagedWidgetStateChanged
// that need to have the final word
mFocus->load();
}
void KWinOptions::save()
{
KCModule::save();
mFocus->save();
mTitleBarActions->save();
mWindowActions->save();
mMoving->save();
mAdvanced->save();
// Send signal to all kwin instances
QDBusMessage message =
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
void KWinOptions::defaults()
{
KCModule::defaults();
mTitleBarActions->defaults();
mWindowActions->defaults();
mMoving->defaults();
mAdvanced->defaults();
// mFocus is last because it may send unmanagedWidgetDefaulted
// that need to have the final word
mFocus->defaults();
}
void KWinOptions::updateUnmanagedState()
{
bool changed = false;
changed |= mFocus->needsSave();
changed |= mTitleBarActions->needsSave();
changed |= mWindowActions->needsSave();
changed |= mMoving->needsSave();
changed |= mAdvanced->needsSave();
unmanagedWidgetChangeState(changed);
bool isDefault = true;
isDefault &= mFocus->representsDefaults();
isDefault &= mTitleBarActions->representsDefaults();
isDefault &= mWindowActions->representsDefaults();
isDefault &= mMoving->representsDefaults();
isDefault &= mAdvanced->representsDefaults();
unmanagedWidgetDefaultState(isDefault);
}
KActionsOptions::KActionsOptions(QObject *parent, const KPluginMetaData &data)
: KCModule(parent, data)
{
mSettings = new KWinOptionsSettings(this);
QVBoxLayout *layout = new QVBoxLayout(widget());
layout->setContentsMargins(0, 0, 0, 0);
tab = new QTabWidget(widget());
layout->addWidget(tab);
mTitleBarActions = new KTitleBarActionsConfig(false, mSettings, widget());
mTitleBarActions->setObjectName(QLatin1String("KWin TitleBar Actions"));
tab->addTab(mTitleBarActions->widget(), i18n("&Titlebar Actions"));
connect(mTitleBarActions, &KCModule::needsSaveChanged, this, [this]() {
setNeedsSave(mTitleBarActions->needsSave());
});
connect(mTitleBarActions, &KCModule::representsDefaultsChanged, this, [this]() {
setRepresentsDefaults(mTitleBarActions->representsDefaults());
});
mWindowActions = new KWindowActionsConfig(false, mSettings, widget());
mWindowActions->setObjectName(QLatin1String("KWin Window Actions"));
tab->addTab(mWindowActions->widget(), i18n("Window Actio&ns"));
connect(mWindowActions, &KCModule::needsSaveChanged, this, [this]() {
setNeedsSave(mWindowActions->needsSave());
});
connect(mWindowActions, &KCModule::representsDefaultsChanged, this, [this]() {
setRepresentsDefaults(mWindowActions->representsDefaults());
});
}
void KActionsOptions::load()
{
mTitleBarActions->load();
mWindowActions->load();
}
void KActionsOptions::save()
{
mTitleBarActions->save();
mWindowActions->save();
setNeedsSave(false);
// Send signal to all kwin instances
QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
void KActionsOptions::defaults()
{
mTitleBarActions->defaults();
mWindowActions->defaults();
}
void KActionsOptions::moduleChanged(bool state)
{
setNeedsSave(state);
}
#include "main.moc"
#include "moc_main.cpp"
@@ -0,0 +1,73 @@
/*
main.h
SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org>
Requires the Qt widget libraries, available at no cost at
https://www.qt.io
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <KCModule>
#include <QTabWidget>
class KWinOptionsSettings;
class KWinOptionsKDEGlobalsSettings;
class KFocusConfig;
class KTitleBarActionsConfig;
class KWindowActionsConfig;
class KAdvancedConfig;
class KMovingConfig;
class KWinOptions : public KCModule
{
Q_OBJECT
public:
explicit KWinOptions(QObject *parent, const KPluginMetaData &data);
void load() override;
void save() override;
void defaults() override;
protected Q_SLOTS:
void updateUnmanagedState();
private:
QTabWidget *tab;
KFocusConfig *mFocus;
KTitleBarActionsConfig *mTitleBarActions;
KWindowActionsConfig *mWindowActions;
KMovingConfig *mMoving;
KAdvancedConfig *mAdvanced;
KWinOptionsSettings *mSettings;
};
class KActionsOptions : public KCModule
{
Q_OBJECT
public:
KActionsOptions(QObject *parent, const KPluginMetaData &data);
void load() override;
void save() override;
void defaults() override;
protected Q_SLOTS:
void moduleChanged(bool state);
private:
QTabWidget *tab;
KTitleBarActionsConfig *mTitleBarActions;
KWindowActionsConfig *mWindowActions;
KWinOptionsSettings *mSettings;
};
@@ -0,0 +1,83 @@
/*
SPDX-FileCopyrightText: 1998 Matthias Ettrich <ettrich@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "mouse.h"
#include "kwinoptions_settings.h"
#include <KWindowSystem>
#include <QDBusConnection>
#include <QDBusMessage>
KWinMouseConfigForm::KWinMouseConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(parent);
}
KWinActionsConfigForm::KWinActionsConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(parent);
}
KTitleBarActionsConfig::KTitleBarActionsConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent)
: KCModule(parent, KPluginMetaData())
, standAlone(_standAlone)
, m_ui(new KWinMouseConfigForm(widget()))
{
if (settings) {
initialize(settings);
}
}
void KTitleBarActionsConfig::initialize(KWinOptionsSettings *settings)
{
m_settings = settings;
addConfig(m_settings, widget());
}
void KTitleBarActionsConfig::save()
{
KCModule::save();
if (standAlone) {
// Send signal to all kwin instances
QDBusMessage message =
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
}
KWindowActionsConfig::KWindowActionsConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent)
: KCModule(parent, KPluginMetaData())
, standAlone(_standAlone)
, m_ui(new KWinActionsConfigForm(widget()))
{
if (settings) {
initialize(settings);
}
}
void KWindowActionsConfig::initialize(KWinOptionsSettings *settings)
{
m_settings = settings;
addConfig(m_settings, widget());
m_ui->info_1->setVisible(KWindowSystem::isPlatformX11());
}
void KWindowActionsConfig::save()
{
KCModule::save();
if (standAlone) {
// Send signal to all kwin instances
QDBusMessage message =
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
}
#include "moc_mouse.cpp"
@@ -0,0 +1,77 @@
/*
mouse.h
SPDX-FileCopyrightText: 1998 Matthias Ettrich <ettrich@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
class KConfig;
#include <KCModule>
#include <KLocalizedString>
#include "ui_actions.h"
#include "ui_mouse.h"
class KWinOptionsSettings;
class KWinMouseConfigForm : public QWidget, public Ui::KWinMouseConfigForm
{
Q_OBJECT
public:
explicit KWinMouseConfigForm(QWidget *parent);
};
class KWinActionsConfigForm : public QWidget, public Ui::KWinActionsConfigForm
{
Q_OBJECT
public:
explicit KWinActionsConfigForm(QWidget *parent);
};
class KTitleBarActionsConfig : public KCModule
{
Q_OBJECT
public:
KTitleBarActionsConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent);
void save() override;
protected:
void initialize(KWinOptionsSettings *settings);
private:
bool standAlone;
KWinMouseConfigForm *m_ui;
KWinOptionsSettings *m_settings;
};
class KWindowActionsConfig : public KCModule
{
Q_OBJECT
public:
KWindowActionsConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent);
void save() override;
bool isDefaults() const;
bool isSaveNeeded() const;
protected:
void initialize(KWinOptionsSettings *settings);
private:
bool standAlone;
KWinActionsConfigForm *m_ui;
KWinOptionsSettings *m_settings;
};
@@ -0,0 +1,749 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KWinMouseConfigForm</class>
<widget class="QWidget" name="KWinMouseConfigForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>500</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_1">
<property name="title">
<string>Titlebar Actions</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_1">
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_1">
<property name="text">
<string>&amp;Double-click:</string>
</property>
<property name="buddy">
<cstring>kcfg_TitlebarDoubleClickCommand</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="kcfg_TitlebarDoubleClickCommand">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;double&lt;/em&gt; click into the titlebar.</string>
</property>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Maximize</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Vertically maximize</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Horizontally maximize</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Minimize</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Shade</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Lower</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Close</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Show on all desktops</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="@item:inlistbox behavior on double click">Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Mouse &amp;wheel:</string>
</property>
<property name="buddy">
<cstring>kcfg_CommandTitlebarWheel</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="kcfg_CommandTitlebarWheel">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;mouse wheel&lt;/em&gt; scroll over the titlebar.</string>
</property>
<item>
<property name="text">
<string>Raise/lower</string>
</property>
</item>
<item>
<property name="text">
<string>Shade/unshade</string>
</property>
</item>
<item>
<property name="text">
<string>Maximize/restore</string>
</property>
</item>
<item>
<property name="text">
<string>Keep above/below</string>
</property>
</item>
<item>
<property name="text">
<string>Move to previous/next desktop</string>
</property>
</item>
<item>
<property name="text">
<string>Change opacity</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Titlebar and Frame Actions</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<spacer name="horizontalSpacer_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_1">
<item row="0" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Active</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&amp;Left click:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandActiveTitlebar1</cstring>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Inactive</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Middle click:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandActiveTitlebar2</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>&amp;Right click:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>kcfg_CommandActiveTitlebar3</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="kcfg_CommandActiveTitlebar1">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>Behavior on &lt;em&gt;left&lt;/em&gt; click into the titlebar or frame of an &lt;em&gt;active&lt;/em&gt; window.</string>
</property>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Shade</string>
</property>
</item>
<item>
<property name="text">
<string>Close</string>
</property>
</item>
<item>
<property name="text">
<string>Show actions menu</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="kcfg_CommandInactiveTitlebar1">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;left&lt;/em&gt; click into the titlebar or frame of an &lt;em&gt;inactive&lt;/em&gt; window.</string>
</property>
<item>
<property name="text">
<string>Activate and raise</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Activate</string>
</property>
</item>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Shade</string>
</property>
</item>
<item>
<property name="text">
<string>Close</string>
</property>
</item>
<item>
<property name="text">
<string>Show actions menu</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="kcfg_CommandActiveTitlebar2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>Behavior on &lt;em&gt;left&lt;/em&gt; click into the titlebar or frame of an &lt;em&gt;active&lt;/em&gt; window.</string>
</property>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Shade</string>
</property>
</item>
<item>
<property name="text">
<string>Close</string>
</property>
</item>
<item>
<property name="text">
<string>Show actions menu</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="kcfg_CommandInactiveTitlebar2">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;left&lt;/em&gt; click into the titlebar or frame of an &lt;em&gt;inactive&lt;/em&gt; window.</string>
</property>
<item>
<property name="text">
<string>Activate and raise</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Activate</string>
</property>
</item>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Shade</string>
</property>
</item>
<item>
<property name="text">
<string>Close</string>
</property>
</item>
<item>
<property name="text">
<string>Show actions menu</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="kcfg_CommandActiveTitlebar3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>Behavior on &lt;em&gt;left&lt;/em&gt; click into the titlebar or frame of an &lt;em&gt;active&lt;/em&gt; window.</string>
</property>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Shade</string>
</property>
</item>
<item>
<property name="text">
<string>Close</string>
</property>
</item>
<item>
<property name="text">
<string>Show actions menu</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="3" column="2">
<widget class="QComboBox" name="kcfg_CommandInactiveTitlebar3">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;left&lt;/em&gt; click into the titlebar or frame of an &lt;em&gt;inactive&lt;/em&gt; window.</string>
</property>
<item>
<property name="text">
<string>Activate and raise</string>
</property>
</item>
<item>
<property name="text">
<string>Activate and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Activate</string>
</property>
</item>
<item>
<property name="text">
<string>Raise</string>
</property>
</item>
<item>
<property name="text">
<string>Lower</string>
</property>
</item>
<item>
<property name="text">
<string>Toggle raise and lower</string>
</property>
</item>
<item>
<property name="text">
<string>Minimize</string>
</property>
</item>
<item>
<property name="text">
<string>Shade</string>
</property>
</item>
<item>
<property name="text">
<string>Close</string>
</property>
</item>
<item>
<property name="text">
<string>Show actions menu</string>
</property>
</item>
<item>
<property name="text">
<string>Do nothing</string>
</property>
</item>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QCheckBox" name="kcfg_DoubleClickBorderToMaximize">
<property name="text">
<string>Maximize window by double clicking its frame</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Maximize Button Actions</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;left&lt;/em&gt; click onto the maximize button.</string>
</property>
<property name="text">
<string>L&amp;eft click:</string>
</property>
<property name="buddy">
<cstring>kcfg_MaximizeButtonLeftClickCommand</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="kcfg_MaximizeButtonLeftClickCommand">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;left&lt;/em&gt; click onto the maximize button.</string>
</property>
<item>
<property name="text">
<string>Maximize</string>
</property>
</item>
<item>
<property name="text">
<string>Vertically maximize</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontally maximize</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;middle&lt;/em&gt; click onto the maximize button.</string>
</property>
<property name="text">
<string>Middle c&amp;lick:</string>
</property>
<property name="buddy">
<cstring>kcfg_MaximizeButtonMiddleClickCommand</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="kcfg_MaximizeButtonMiddleClickCommand">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;middle&lt;/em&gt; click onto the maximize button.</string>
</property>
<item>
<property name="text">
<string>Maximize</string>
</property>
</item>
<item>
<property name="text">
<string>Vertically maximize</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontally maximize</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;right&lt;/em&gt; click onto the maximize button.</string>
</property>
<property name="text">
<string>Right clic&amp;k:</string>
</property>
<property name="buddy">
<cstring>kcfg_MaximizeButtonRightClickCommand</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="kcfg_MaximizeButtonRightClickCommand">
<property name="whatsThis">
<string>Behavior on &lt;em&gt;right&lt;/em&gt; click onto the maximize button.</string>
</property>
<item>
<property name="text">
<string>Maximize</string>
</property>
</item>
<item>
<property name="text">
<string>Vertically maximize</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontally maximize</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_1">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>kcfg_TitlebarDoubleClickCommand</tabstop>
<tabstop>kcfg_CommandTitlebarWheel</tabstop>
<tabstop>kcfg_CommandActiveTitlebar1</tabstop>
<tabstop>kcfg_CommandInactiveTitlebar1</tabstop>
<tabstop>kcfg_CommandActiveTitlebar2</tabstop>
<tabstop>kcfg_CommandInactiveTitlebar2</tabstop>
<tabstop>kcfg_CommandActiveTitlebar3</tabstop>
<tabstop>kcfg_CommandInactiveTitlebar3</tabstop>
<tabstop>kcfg_MaximizeButtonLeftClickCommand</tabstop>
<tabstop>kcfg_MaximizeButtonMiddleClickCommand</tabstop>
<tabstop>kcfg_MaximizeButtonRightClickCommand</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KWinMovingConfigForm</class>
<widget class="QWidget" name="KWinMovingConfigForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>500</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="formAlignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="borderSnapLabel">
<property name="text">
<string>Screen &amp;edge snap zone:</string>
</property>
<property name="buddy">
<cstring>kcfg_BorderSnapZone</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="kcfg_BorderSnapZone">
<property name="whatsThis">
<string>Here you can set the snap zone for screen edges, i.e. the 'strength' of the magnetic field which will make windows snap to the border when moved near it.</string>
</property>
<property name="specialValueText">
<string>None</string>
</property>
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="windowSnapLabel">
<property name="text">
<string>&amp;Window snap zone:</string>
</property>
<property name="buddy">
<cstring>kcfg_WindowSnapZone</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="kcfg_WindowSnapZone">
<property name="whatsThis">
<string>Here you can set the snap zone for windows, i.e. the 'strength' of the magnetic field which will make windows snap to each other when they are moved near another window.</string>
</property>
<property name="specialValueText">
<string>None</string>
</property>
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="centerSnaplabel">
<property name="text">
<string>&amp;Center snap zone:</string>
</property>
<property name="buddy">
<cstring>kcfg_CenterSnapZone</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="kcfg_CenterSnapZone">
<property name="whatsThis">
<string>Here you can set the snap zone for the screen center, i.e. the 'strength' of the magnetic field which will make windows snap to the center of the screen when moved near it.</string>
</property>
<property name="specialValueText">
<string>None</string>
</property>
<property name="suffix">
<string> px</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="OverlapSnapLabel">
<property name="text">
<string>&amp;Snap windows:</string>
</property>
<property name="buddy">
<cstring>kcfg_SnapOnlyWhenOverlapping</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="kcfg_SnapOnlyWhenOverlapping">
<property name="whatsThis">
<string>Here you can set that windows will be only snapped if you try to overlap them, i.e. they will not be snapped if the windows comes only near another window or border.</string>
</property>
<property name="text">
<string>Only when overlapping</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,310 @@
/*
windows.cpp
SPDX-FileCopyrightText: 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <QApplication>
#include <QCheckBox>
#include <QFormLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QRadioButton>
#include <QScreen>
#include <QtDBus>
#include <KConfig>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KWindowSystem>
#include "kwinoptions_settings.h"
#include "windows.h"
#include <kwin_effects_interface.h>
#include "kwinoptions_kdeglobals_settings.h"
#include "kwinoptions_settings.h"
#define CLICK_TO_FOCUS 0
#define CLICK_TO_FOCUS_MOUSE_PRECEDENT 1
#define FOCUS_FOLLOWS_MOUSE 2
#define FOCUS_FOLLOWS_MOUSE_PRECEDENT 3
#define FOCUS_UNDER_MOUSE 4
#define FOCUS_STRICTLY_UNDER_MOUSE 5
namespace
{
constexpr int defaultFocusPolicyIndex = CLICK_TO_FOCUS;
}
KWinFocusConfigForm::KWinFocusConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(parent);
}
KFocusConfig::KFocusConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent)
: KCModule(parent, KPluginMetaData())
, standAlone(_standAlone)
, m_ui(new KWinFocusConfigForm(widget()))
{
if (settings) {
initialize(settings);
}
}
void KFocusConfig::initialize(KWinOptionsSettings *settings)
{
m_settings = settings;
addConfig(m_settings, widget());
connect(m_ui->windowFocusPolicy, qOverload<int>(&QComboBox::currentIndexChanged), this, &KFocusConfig::focusPolicyChanged);
connect(m_ui->windowFocusPolicy, qOverload<int>(&QComboBox::currentIndexChanged), this, &KFocusConfig::updateDefaultIndicator);
connect(this, SIGNAL(defaultsIndicatorsVisibleChanged(bool)), this, SLOT(updateDefaultIndicator()));
connect(qApp, &QGuiApplication::screenAdded, this, &KFocusConfig::updateMultiScreen);
connect(qApp, &QGuiApplication::screenRemoved, this, &KFocusConfig::updateMultiScreen);
updateMultiScreen();
}
void KFocusConfig::updateMultiScreen()
{
m_ui->multiscreenBehaviorLabel->setVisible(QApplication::screens().count() > 1);
m_ui->kcfg_SeparateScreenFocus->setVisible(QApplication::screens().count() > 1);
}
void KFocusConfig::updateDefaultIndicator()
{
const bool isDefault = m_ui->windowFocusPolicy->currentIndex() == defaultFocusPolicyIndex;
m_ui->windowFocusPolicy->setProperty("_kde_highlight_neutral", defaultsIndicatorsVisible() && !isDefault);
m_ui->windowFocusPolicy->update();
}
void KFocusConfig::updateFocusPolicyExplanatoryText()
{
const int focusPolicy = m_ui->windowFocusPolicy->currentIndex();
switch (focusPolicy) {
case CLICK_TO_FOCUS:
m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Click to focus:</em> A window becomes active when you click into it. This behavior is common on other operating systems and likely what you want."));
break;
case CLICK_TO_FOCUS_MOUSE_PRECEDENT:
m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Click to focus (mouse precedence):</em> Mostly the same as <em>Click to focus</em>. If an active window has to be chosen by the system (eg. because the currently active one was closed) the window under the mouse is the preferred candidate. Unusual, but possible variant of <em>Click to focus</em>."));
break;
case FOCUS_FOLLOWS_MOUSE:
m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Focus follows mouse:</em> Moving the mouse onto a window will activate it. Eg. windows randomly appearing under the mouse will not gain the focus. <em>Focus stealing prevention</em> takes place as usual. Think as <em>Click to focus</em> just without having to actually click."));
break;
case FOCUS_FOLLOWS_MOUSE_PRECEDENT:
m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("This is mostly the same as <em>Focus follows mouse</em>. If an active window has to be chosen by the system (eg. because the currently active one was closed) the window under the mouse is the preferred candidate. Choose this, if you want a hover controlled focus."));
break;
case FOCUS_UNDER_MOUSE:
m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Focus under mouse:</em> The focus always remains on the window under the mouse.<br/><strong>Warning:</strong> <em>Focus stealing prevention</em> and the <em>tabbox ('Alt+Tab')</em> contradict the activation policy and will not work. You very likely want to use <em>Focus follows mouse (mouse precedence)</em> instead!"));
break;
case FOCUS_STRICTLY_UNDER_MOUSE:
m_ui->windowFocusPolicyDescriptionLabel->setText(i18n("<em>Focus strictly under mouse:</em> The focus is always on the window under the mouse (in doubt nowhere) very much like the focus behavior in an unmanaged legacy X11 environment.<br/><strong>Warning:</strong> <em>Focus stealing prevention</em> and the <em>tabbox ('Alt+Tab')</em> contradict the activation policy and will not work. You very likely want to use <em>Focus follows mouse (mouse precedence)</em> instead!"));
break;
}
}
void KFocusConfig::focusPolicyChanged()
{
int selectedFocusPolicy = 0;
bool selectedNextFocusPrefersMouseItem = false;
const bool loadedNextFocusPrefersMouseItem = m_settings->nextFocusPrefersMouse();
updateFocusPolicyExplanatoryText();
int focusPolicy = m_ui->windowFocusPolicy->currentIndex();
switch (focusPolicy) {
case CLICK_TO_FOCUS:
selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::ClickToFocus;
break;
case CLICK_TO_FOCUS_MOUSE_PRECEDENT:
selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::ClickToFocus;
selectedNextFocusPrefersMouseItem = true;
break;
case FOCUS_FOLLOWS_MOUSE:
selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse;
break;
case FOCUS_FOLLOWS_MOUSE_PRECEDENT:
selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse;
selectedNextFocusPrefersMouseItem = true;
break;
case FOCUS_UNDER_MOUSE:
selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusUnderMouse;
break;
case FOCUS_STRICTLY_UNDER_MOUSE:
selectedFocusPolicy = KWinOptionsSettings::EnumFocusPolicy::FocusStrictlyUnderMouse;
break;
}
unmanagedWidgetChangeState(m_settings->focusPolicy() != selectedFocusPolicy || loadedNextFocusPrefersMouseItem != selectedNextFocusPrefersMouseItem);
unmanagedWidgetDefaultState(focusPolicy == defaultFocusPolicyIndex);
// the auto raise related widgets are: autoRaise
m_ui->kcfg_AutoRaise->setEnabled(focusPolicy != CLICK_TO_FOCUS && focusPolicy != CLICK_TO_FOCUS_MOUSE_PRECEDENT);
m_ui->kcfg_FocusStealingPreventionLevel->setDisabled(focusPolicy == FOCUS_UNDER_MOUSE || focusPolicy == FOCUS_STRICTLY_UNDER_MOUSE);
// the delayed focus related widgets are: delayFocus
m_ui->delayFocusOnLabel->setEnabled(focusPolicy != CLICK_TO_FOCUS);
m_ui->kcfg_DelayFocusInterval->setEnabled(focusPolicy != CLICK_TO_FOCUS);
}
void KFocusConfig::load(void)
{
KCModule::load();
const bool loadedNextFocusPrefersMouseItem = m_settings->nextFocusPrefersMouse();
int focusPolicy = m_settings->focusPolicy();
switch (focusPolicy) {
// the ClickToFocus and FocusFollowsMouse have special values when
// NextFocusPrefersMouse is true
case KWinOptionsSettings::EnumFocusPolicy::ClickToFocus:
m_ui->windowFocusPolicy->setCurrentIndex(CLICK_TO_FOCUS + loadedNextFocusPrefersMouseItem);
break;
case KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse:
m_ui->windowFocusPolicy->setCurrentIndex(FOCUS_FOLLOWS_MOUSE + loadedNextFocusPrefersMouseItem);
break;
default:
// +2 to ignore the two special values
m_ui->windowFocusPolicy->setCurrentIndex(focusPolicy + 2);
break;
}
updateFocusPolicyExplanatoryText();
}
void KFocusConfig::save(void)
{
KCModule::save();
int idxFocusPolicy = m_ui->windowFocusPolicy->currentIndex();
switch (idxFocusPolicy) {
case CLICK_TO_FOCUS:
case CLICK_TO_FOCUS_MOUSE_PRECEDENT:
m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::ClickToFocus);
break;
case FOCUS_FOLLOWS_MOUSE:
case FOCUS_FOLLOWS_MOUSE_PRECEDENT:
// the ClickToFocus and FocusFollowsMouse have special values when
// NextFocusPrefersMouse is true
m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusFollowsMouse);
break;
case FOCUS_UNDER_MOUSE:
m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusUnderMouse);
break;
case FOCUS_STRICTLY_UNDER_MOUSE:
m_settings->setFocusPolicy(KWinOptionsSettings::EnumFocusPolicy::FocusStrictlyUnderMouse);
break;
}
m_settings->setNextFocusPrefersMouse(idxFocusPolicy == CLICK_TO_FOCUS_MOUSE_PRECEDENT || idxFocusPolicy == FOCUS_FOLLOWS_MOUSE_PRECEDENT);
m_settings->save();
if (standAlone) {
// Send signal to all kwin instances
QDBusMessage message =
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
}
void KFocusConfig::defaults()
{
KCModule::defaults();
m_ui->windowFocusPolicy->setCurrentIndex(defaultFocusPolicyIndex);
}
KWinAdvancedConfigForm::KWinAdvancedConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(parent);
}
KAdvancedConfig::KAdvancedConfig(bool _standAlone, KWinOptionsSettings *settings, KWinOptionsKDEGlobalsSettings *globalSettings, QWidget *parent)
: KCModule(parent, KPluginMetaData())
, standAlone(_standAlone)
, m_ui(new KWinAdvancedConfigForm(widget()))
{
if (settings && globalSettings) {
initialize(settings, globalSettings);
}
}
void KAdvancedConfig::initialize(KWinOptionsSettings *settings, KWinOptionsKDEGlobalsSettings *globalSettings)
{
m_settings = settings;
addConfig(m_settings, widget());
addConfig(globalSettings, widget());
m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Smart, "Smart");
m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Maximizing, "Maximizing");
m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Random, "Random");
m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::Centered, "Centered");
m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::ZeroCornered, "ZeroCornered");
m_ui->kcfg_Placement->setItemData(KWinOptionsSettings::PlacementChoices::UnderMouse, "UnderMouse");
// Don't show the option to prevent apps from remembering their window
// positions on Wayland because it doesn't work on Wayland and the feature
// will eventually be implemented in a different way there.
// This option lives in the kdeglobals file because it is consumed by
// kxmlgui.
m_ui->kcfg_AllowKDEAppsToRememberWindowPositions->setVisible(KWindowSystem::isPlatformX11());
m_ui->kcfg_ActivationDesktopPolicy->setItemData(KWinOptionsSettings::ActivationDesktopPolicyChoices::SwitchToOtherDesktop, "SwitchToOtherDesktop");
m_ui->kcfg_ActivationDesktopPolicy->setItemData(KWinOptionsSettings::ActivationDesktopPolicyChoices::BringToCurrentDesktop, "BringToCurrentDesktop");
}
void KAdvancedConfig::save(void)
{
KCModule::save();
if (standAlone) {
// Send signal to all kwin instances
QDBusMessage message =
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
}
KWinMovingConfigForm::KWinMovingConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(parent);
}
KMovingConfig::KMovingConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent)
: KCModule(parent, KPluginMetaData())
, standAlone(_standAlone)
, m_ui(new KWinMovingConfigForm(widget()))
{
if (settings) {
initialize(settings);
}
}
void KMovingConfig::initialize(KWinOptionsSettings *settings)
{
m_settings = settings;
addConfig(m_settings, widget());
}
void KMovingConfig::save(void)
{
KCModule::save();
if (standAlone) {
// Send signal to all kwin instances
QDBusMessage message =
QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
}
#include "moc_windows.cpp"
@@ -0,0 +1,116 @@
/*
windows.h
SPDX-FileCopyrightText: 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <KCModule>
#include <QWidget>
#include "ui_advanced.h"
#include "ui_focus.h"
#include "ui_moving.h"
class QRadioButton;
class QCheckBox;
class QPushButton;
class QGroupBox;
class QLabel;
class QSlider;
class QGroupBox;
class QSpinBox;
class KColorButton;
class KWinOptionsSettings;
class KWinOptionsKDEGlobalsSettings;
class KWinFocusConfigForm : public QWidget, public Ui::KWinFocusConfigForm
{
Q_OBJECT
public:
explicit KWinFocusConfigForm(QWidget *parent);
};
class KWinMovingConfigForm : public QWidget, public Ui::KWinMovingConfigForm
{
Q_OBJECT
public:
explicit KWinMovingConfigForm(QWidget *parent);
};
class KWinAdvancedConfigForm : public QWidget, public Ui::KWinAdvancedConfigForm
{
Q_OBJECT
public:
explicit KWinAdvancedConfigForm(QWidget *parent);
};
class KFocusConfig : public KCModule
{
Q_OBJECT
public:
KFocusConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent);
void load() override;
void save() override;
void defaults() override;
protected:
void initialize(KWinOptionsSettings *settings);
private Q_SLOTS:
void focusPolicyChanged();
void updateMultiScreen();
void updateDefaultIndicator();
private:
bool standAlone;
KWinFocusConfigForm *m_ui;
KWinOptionsSettings *m_settings;
void updateFocusPolicyExplanatoryText();
};
class KMovingConfig : public KCModule
{
Q_OBJECT
public:
KMovingConfig(bool _standAlone, KWinOptionsSettings *settings, QWidget *parent);
void save() override;
protected:
void initialize(KWinOptionsSettings *settings);
private:
KWinOptionsSettings *m_settings;
bool standAlone;
KWinMovingConfigForm *m_ui;
};
class KAdvancedConfig : public KCModule
{
Q_OBJECT
public:
KAdvancedConfig(bool _standAlone, KWinOptionsSettings *settings, KWinOptionsKDEGlobalsSettings *globalSettings, QWidget *parent);
void save() override;
protected:
void initialize(KWinOptionsSettings *settings, KWinOptionsKDEGlobalsSettings *globalSettings);
private:
bool standAlone;
KWinAdvancedConfigForm *m_ui;
KWinOptionsSettings *m_settings;
};
@@ -0,0 +1,47 @@
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_kwinrules\")
add_definitions(-DKCMRULES)
set(kwinrules_SRCS
../../rulebooksettings.cpp
../../rules.cpp
../../utils/common.cpp
../../virtualdesktopsdbustypes.cpp
kwinsrc.cpp
optionsmodel.cpp
ruleitem.cpp
rulesmodel.cpp
rulebookmodel.cpp
)
kconfig_add_kcfg_files(kwinrules_SRCS ../../rulesettings.kcfgc)
kconfig_add_kcfg_files(kwinrules_SRCS ../../rulebooksettingsbase.kcfgc)
add_library(KWinRulesObjects STATIC ${kwinrules_SRCS})
set_property(TARGET KWinRulesObjects PROPERTY POSITION_INDEPENDENT_CODE ON)
if (KWIN_BUILD_X11)
set(kwin_kcm_rules_XCB_LIBS
XCB::CURSOR
XCB::XCB
XCB::XFIXES
)
endif()
set(kcm_libs
Qt::Quick
KF6::KCMUtils
KF6::I18n
KF6::KCMUtilsQuick
KF6::WindowSystem
KF6::XmlGui
)
if (KWIN_BUILD_ACTIVITIES)
set(kcm_libs ${kcm_libs} Plasma::Activities)
endif()
target_link_libraries(KWinRulesObjects ${kcm_libs} ${kwin_kcm_rules_XCB_LIBS})
kcmutils_add_qml_kcm(kcm_kwinrules SOURCES kcmrules.cpp)
target_link_libraries(kcm_kwinrules PRIVATE KWinRulesObjects)
@@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT `find . -name \*.cpp -o -name \*.h -o -name \*.qml` -o $podir/kcm_kwinrules.pot
@@ -0,0 +1,144 @@
{
"Categories": "Qt;KDE;X-KDE-settings-looknfeel;",
"KPlugin": {
"BugReportUrl": "https://bugs.kde.org/enter_bug.cgi?product=systemsettings&component=kcm_kwinrules",
"Description": "Individual Window Behavior",
"Description[ar]": "سلوك النافذ المفردة",
"Description[az]": "Fərdi pəncərə davranışı",
"Description[be]": "Паводзіны асобных акон",
"Description[bg]": "Индивидуално поведение на прозорците",
"Description[ca@valencia]": "Comportament individual de les finestres",
"Description[ca]": "Comportament individual de les finestres",
"Description[cs]": "Chování individuálních oken",
"Description[da]": "Individuel vinduesopførsel",
"Description[de]": "Individuelles Fensterverhalten",
"Description[en_GB]": "Individual Window Behaviour",
"Description[eo]": "Individua Fenestra Konduto",
"Description[es]": "Comportamiento de ventanas individuales",
"Description[et]": "Konkreetse akna käitumine",
"Description[eu]": "Leihoen banakako portaera",
"Description[fi]": "Yksittäisen ikkunan toiminta",
"Description[fr]": "Comportement individuel des fenêtres",
"Description[gl]": "Comportamento individual das xanelas.",
"Description[he]": "התנהגות חלון יחיד",
"Description[hu]": "Egyedi ablakműködés",
"Description[ia]": "Comportamento de fenestra individual",
"Description[id]": "Perilaku Jendela Individu",
"Description[is]": "Hegðun einstakra glugga",
"Description[it]": "Comportamento della singola finestra",
"Description[ja]": "個別のウィンドウの挙動",
"Description[ka]": "ინდივიდუალური ფანჯრების ქცევა",
"Description[ko]": "개별 창 동작",
"Description[lt]": "Atskira lango elgsena",
"Description[lv]": "Uzvedība atsevišķiem logiem",
"Description[nb]": "Atferd for enkeltvindu",
"Description[nl]": "Individueel venstergedrag",
"Description[nn]": "Åtferd for einskildvindauge",
"Description[pl]": "Wyjątkowe okna",
"Description[pt]": "Comportamento da Janela Individual",
"Description[pt_BR]": "Comportamento das janelas individuais",
"Description[ro]": "Comportament al ferestrelor individuale",
"Description[ru]": "Особые параметры конкретных окон",
"Description[sa]": "व्यक्तिगत खिडकी व्यवहार",
"Description[sk]": "Individuálne správanie okien",
"Description[sl]": "Individualno vedenje oken",
"Description[sv]": "Individuellt fönsterbeteende",
"Description[ta]": "தனிப்பட்ட சாளரங்களின் நடத்தை",
"Description[tr]": "Bireysel Pencere Davranışı",
"Description[uk]": "Поведінка окремих вікон",
"Description[vi]": "Ứng xử của riêng từng cửa sổ",
"Description[x-test]": "xxIndividual Window Behaviorxx",
"Description[zh_CN]": "个别窗口行为",
"Description[zh_TW]": "個別視窗行為",
"FormFactors": [
"desktop",
"tablet"
],
"Icon": "preferences-system-windows-actions",
"Name": "Window Rules",
"Name[ar]": "قواعد النوافذ",
"Name[az]": "Pəncərə qaydası",
"Name[be]": "Правілы для акон",
"Name[bg]": "Правила за прозорци",
"Name[ca@valencia]": "Regles de les finestres",
"Name[ca]": "Regles de les finestres",
"Name[cs]": "Pravidla oken",
"Name[da]": "Vinduesroller",
"Name[de]": "Fensterregeln",
"Name[en_GB]": "Window Rules",
"Name[eo]": "Fenestraj Reguloj",
"Name[es]": "Reglas de las ventanas",
"Name[et]": "Aknareeglid",
"Name[eu]": "Leihoaren arauak",
"Name[fi]": "Ikkunasäännöt",
"Name[fr]": "Règles de fenêtres",
"Name[gl]": "Regras de xanelas",
"Name[he]": "כללי חלון",
"Name[hu]": "Ablakszabályok",
"Name[ia]": "Regulas de fenestra",
"Name[id]": "Peraturan Jendela",
"Name[is]": "Gluggareglur",
"Name[it]": "Regole delle finestre",
"Name[ja]": "ウィンドウのルール",
"Name[ka]": "ფანჯრების წესები",
"Name[ko]": "창 규칙",
"Name[lt]": "Langų taisyklės",
"Name[lv]": "Logu noteikumi",
"Name[nb]": "Vindusregler",
"Name[nl]": "Vensterregels",
"Name[nn]": "Vindaugsreglar",
"Name[pl]": "Zasady okien",
"Name[pt]": "Regras das Janelas",
"Name[pt_BR]": "Regras das janelas",
"Name[ro]": "Reguli ferestre",
"Name[ru]": "Особые параметры окон",
"Name[sa]": "विण्डो नियम",
"Name[sk]": "Pravidlá okien",
"Name[sl]": "Pravila oken",
"Name[sv]": "Fönsterregler",
"Name[ta]": "சாளர விதிமுறைகள்",
"Name[tr]": "Pencere Kuralları",
"Name[uk]": "Правила вікон",
"Name[vi]": "Luật cửa sổ",
"Name[x-test]": "xxWindow Rulesxx",
"Name[zh_CN]": "窗口规则",
"Name[zh_TW]": "視窗規則"
},
"X-DocPath": "kcontrol/windowspecific/index.html",
"X-KDE-Keywords": "size,position,state,window behavior,windows,specific,workarounds,remember,rules,window rules,apps,applications",
"X-KDE-Keywords[ar]": "الحجم,الموضع,الحالة,سلوك النافذة,النوافذ,محدد,الحلول البديلة,التذكر,القواعد,قواعد النافذة,التطبيقات,التطبيقات",
"X-KDE-Keywords[bg]": "размер,позиция,състояние,поведение на прозореца,прозорци,специфични,заобикалящи решения,запомнете,правила,правила за прозорец,приложения,приложения",
"X-KDE-Keywords[ca@valencia]": "mida,posició,estat,comportament de les finestres,finestres,específic,solució temporal,recorda,regles,regles de finestres,apps,aplicacions",
"X-KDE-Keywords[ca]": "mida,posició,estat,comportament de les finestres,finestres,específic,solució temporal,recorda,regles,regles de finestres,apps,aplicacions",
"X-KDE-Keywords[de]": "Größe,Position,Zustand,Fensterverhalten,Fenster,spezifisch,Übergangslösungen,Notlösungen,erinnern,Regeln,Fensterregeln,Anwendungen,Programme",
"X-KDE-Keywords[en_GB]": "size,position,state,window behavior,windows,specific,workarounds,remember,rules,window rules,apps,applications",
"X-KDE-Keywords[es]": "tamaño,posición,estado,comportamiento de la ventana,ventanas,específico,método alternativo,solución alternativa,recordar,reglas,reglas de la ventana,apps,aplicaciones",
"X-KDE-Keywords[eu]": "neurria,tamaina,kokalekua,egoera,leihoaren jokabidea,leihoak,jakina,zehatza,konponbideak,gogoratu,oroitu,araua,leihoaren arauak,aplikazioak",
"X-KDE-Keywords[fi]": "koko,sijainti,paikka,tila,ikkunan toiminta,ikkunoiden toiminta,ikkunat,muista,muistisäännöt,säännöt,ikkunasäännöt,sovellukset,ohjelmat",
"X-KDE-Keywords[fr]": "taille, position, état, comportement des fenêtres, fenêtres,spécifiques,solutions de contournement, mémoriser, règles, règles de fenêtre, applications",
"X-KDE-Keywords[gl]": "tamaño,posición,estado,comportamento da xanela,xanelas,específico,regras,window rules,apps,aplis,applications,aplicacións",
"X-KDE-Keywords[he]": "גודל,מקום,מיקום,הצבה,מצב,התנהגות חלון,חלונות,מסוים,מסוימים,מעקפים,שמירה,זכירה,כללי חלון,יישומים,יישומונים",
"X-KDE-Keywords[hu]": "méret,pozíció,állapot,ablakműködés,ablakok,specifikus,kerülőút,emlékeztető,szabályok,ablakszabályok,alkalmazások",
"X-KDE-Keywords[ia]": "grandor,position,stato,comportamento de fenestra,fenestras,specific,workarounds,memora,regulas, regulas de fenestra,apps,applicationes",
"X-KDE-Keywords[is]": "stærð,staðsetning,staða,gluggahegðun,gluggar,tilgreint,aukalausnir,muna,reglur,gluggareglur,forrit,hugbúnaður",
"X-KDE-Keywords[it]": "dimensione,posizione,stato,comportamento della finestra,finestre,specifico,espedienti,ricorda,regole,regole delle finestre,applicazioni",
"X-KDE-Keywords[ka]": "size,position,state,window behavior,windows,specific,workarounds,remember,rules,window rules,apps,applications,აპლიკაციები,აპები,ფანჯრის წესები,წესები,დამახსოვრება,ფანჯრები,ფანჯრების ქცევა,მდებარეობა,ზომა",
"X-KDE-Keywords[ko]": "크기,위치,창 행동,창,창 지정,규칙,프로그램,앱",
"X-KDE-Keywords[lv]": "izmērs,pozīcija,stāvoklis,logu uzvedība,logi,specifiski,apiešana,atcerēties,noteikumi,logu noteikumi,lietotnes,programmas",
"X-KDE-Keywords[nb]": "størrelse,plassering,tilstand,vindusatferd,vindu,enkelt,løsninger,unntak,husk,regler,vindusregler,apper,applikasjoner,program,brukerprogram",
"X-KDE-Keywords[nl]": "grootte,positie,status,venstergedrag,vensters,specifiek,omwegen,onthouden,regels,vensterregels,apps,toepassingen",
"X-KDE-Keywords[nn]": "storleik,plassering,tilstand,vindaugsåtferd,vindauge,einskild,løysingar,unntak,hugs,reglar,vindaugsreglar,appar,applikasjonar,program,brukarprogram",
"X-KDE-Keywords[pl]": "rozmiar,pozycja,stan,zachowanie okna,okna,specyficzne,obejścia,zapamiętaj,zasady,zasady okien,appki,aplikacje",
"X-KDE-Keywords[pt_BR]": "tamanho,posição,estado,comportamento de janela,janelas,específico,soluções alternativas,lembrar,regras,regras de janela,aplicativos,aplicações",
"X-KDE-Keywords[ru]": "size,position,state,window behavior,windows,specific,workarounds,remember,rules,window rules,apps,applications,размер,позиция,положение,состояние,поведение окон,окна,конкретный,обходные пути,запомнить,правила,правила окон,приложения",
"X-KDE-Keywords[sa]": "आकार,स्थिति,स्थिति,विंडो व्यवहार,विंडोज,विशिष्ट,कार्यपरिहार,स्मरण,नियम,विंडो नियम,एप्स,अनुप्रयोग",
"X-KDE-Keywords[sl]": "velikost,položaj,stanje,vedenje oken,okna,specifično,rešitve,zapomni si,pravila,pravila oken,aplikacije,programi",
"X-KDE-Keywords[sv]": "storlek,position,tillstånd,fönsterbeteende,fönster,specifik,lösningar,komma ihåg,regler,fönsterregler,program,applikationer",
"X-KDE-Keywords[tr]": "boyut,konum,durum,davranış,pencereler,başka yöntem,anımsa,kural,uygulama,app,uygulamalar",
"X-KDE-Keywords[uk]": "size,position,state,window behavior,windows,specific,workarounds,remember,rules,window rules,apps,applications,розмір,розташування,місце,стан,поведінка,вікно,вікна,поведінка вікон,окрема,специфічна,окремо,запам’ятати,пам’ять,правило,правила,правила вікон,програми",
"X-KDE-Keywords[x-test]": "xxsizexx,xxpositionxx,xxstatexx,xxwindow behaviorxx,xxwindowsxx,xxspecificxx,xxworkaroundsxx,xxrememberxx,xxrulesxx,xxwindow rulesxx,xxappsxx,xxapplicationsxx",
"X-KDE-Keywords[zh_CN]": "size,position,state,window behavior,windows,specific,workarounds,remember,rules,daxiao,weizhi,chuangkouxingwei,teding,gebie,zhiding,jizhu,jiyi,jilu,guize,chuangkouguize,yingyong,yingyongchengxu,大小,位置,窗口行为,特定,个别,指定,记住,记忆,记录,规则,窗口规则,应用,应用程序",
"X-KDE-Keywords[zh_TW]": "大小,尺寸,位置,狀態,視窗行為,視窗,特定,專用,記住,規則,視窗規則,應用程式,程式",
"X-KDE-System-Settings-Parent-Category": "windowmanagement",
"X-KDE-Weight": 40
}
@@ -0,0 +1,483 @@
/*
SPDX-FileCopyrightText: 2004 Lubos Lunak <l.lunak@kde.org>
SPDX-FileCopyrightText: 2020 Ismael Asensio <isma.af@gmail.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "kcmrules.h"
#include "rulesettings.h"
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
#include <KConfig>
#include <KLocalizedString>
#include <KPluginFactory>
namespace KWin
{
KCMKWinRules::KCMKWinRules(QObject *parent, const KPluginMetaData &metaData, const QVariantList &arguments)
: KQuickConfigModule(parent, metaData)
, m_ruleBookModel(new RuleBookModel(this))
, m_rulesModel(new RulesModel(this))
{
QStringList argList;
for (const QVariant &arg : arguments) {
argList << arg.toString();
}
parseArguments(argList);
connect(m_rulesModel, &RulesModel::descriptionChanged, this, [this] {
if (m_editIndex.isValid()) {
m_ruleBookModel->setDescriptionAt(m_editIndex.row(), m_rulesModel->description());
}
});
connect(m_rulesModel, &RulesModel::dataChanged, this, [this] {
Q_EMIT m_ruleBookModel->dataChanged(m_editIndex, m_editIndex, {});
});
connect(m_ruleBookModel, &RuleBookModel::dataChanged, this, &KCMKWinRules::updateNeedsSave);
}
void KCMKWinRules::parseArguments(const QStringList &args)
{
// When called from window menu, "uuid" and "whole-app" are set in arguments list
bool nextArgIsUuid = false;
QUuid uuid = QUuid();
// TODO: Use a better argument parser
for (const QString &arg : args) {
if (arg == QLatin1String("uuid")) {
nextArgIsUuid = true;
} else if (nextArgIsUuid) {
uuid = QUuid(arg);
nextArgIsUuid = false;
} else if (arg.startsWith("uuid=")) {
uuid = QUuid(arg.mid(strlen("uuid=")));
} else if (arg == QLatin1String("whole-app")) {
m_wholeApp = true;
}
}
if (uuid.isNull()) {
qDebug() << "Invalid window uuid.";
return;
}
// Get the Window properties
QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KWin"),
QStringLiteral("/KWin"),
QStringLiteral("org.kde.KWin"),
QStringLiteral("getWindowInfo"));
message.setArguments({uuid.toString()});
QDBusPendingReply<QVariantMap> async = QDBusConnection::sessionBus().asyncCall(message);
QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this);
connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this, uuid](QDBusPendingCallWatcher *self) {
QDBusPendingReply<QVariantMap> reply = *self;
self->deleteLater();
if (!reply.isValid() || reply.value().isEmpty()) {
qDebug() << "Error retrieving properties for window" << uuid;
return;
}
qDebug() << "Retrieved properties for window" << uuid;
m_winProperties = reply.value();
if (m_alreadyLoaded) {
createRuleFromProperties();
}
});
}
void KCMKWinRules::load()
{
m_ruleBookModel->load();
if (!m_winProperties.isEmpty() && !m_alreadyLoaded) {
createRuleFromProperties();
} else {
m_editIndex = QModelIndex();
Q_EMIT editIndexChanged();
}
m_alreadyLoaded = true;
updateNeedsSave();
}
void KCMKWinRules::save()
{
m_ruleBookModel->save();
// Notify kwin to reload configuration
QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
void KCMKWinRules::updateNeedsSave()
{
setNeedsSave(m_ruleBookModel->isSaveNeeded());
Q_EMIT needsSaveChanged();
}
void KCMKWinRules::createRuleFromProperties()
{
if (m_winProperties.isEmpty()) {
return;
}
QModelIndex matchedIndex = findRuleWithProperties(m_winProperties, m_wholeApp);
if (!matchedIndex.isValid()) {
m_ruleBookModel->insertRow(0);
fillSettingsFromProperties(m_ruleBookModel->ruleSettingsAt(0), m_winProperties, m_wholeApp);
matchedIndex = m_ruleBookModel->index(0);
updateNeedsSave();
}
editRule(matchedIndex.row());
m_rulesModel->setSuggestedProperties(m_winProperties);
m_winProperties.clear();
}
int KCMKWinRules::editIndex() const
{
if (!m_editIndex.isValid()) {
return -1;
}
return m_editIndex.row();
}
void KCMKWinRules::setRuleDescription(int index, const QString &description)
{
if (index < 0 || index >= m_ruleBookModel->rowCount()) {
return;
}
if (m_editIndex.row() == index) {
m_rulesModel->setDescription(description);
return;
}
m_ruleBookModel->setDescriptionAt(index, description);
updateNeedsSave();
}
void KCMKWinRules::editRule(int index)
{
if (index < 0 || index >= m_ruleBookModel->rowCount()) {
return;
}
m_editIndex = m_ruleBookModel->index(index);
Q_EMIT editIndexChanged();
m_rulesModel->setSettings(m_ruleBookModel->ruleSettingsAt(m_editIndex.row()));
// Set the active page to rules editor (0:RulesList, 1:RulesEditor)
setCurrentIndex(1);
}
void KCMKWinRules::createRule()
{
const int newIndex = m_ruleBookModel->rowCount();
m_ruleBookModel->insertRow(newIndex);
updateNeedsSave();
editRule(newIndex);
}
void KCMKWinRules::removeRule(int index)
{
if (index < 0 || index >= m_ruleBookModel->rowCount()) {
return;
}
m_ruleBookModel->removeRow(index);
Q_EMIT editIndexChanged();
updateNeedsSave();
}
void KCMKWinRules::moveRule(int sourceIndex, int destIndex)
{
const int lastIndex = m_ruleBookModel->rowCount() - 1;
if (sourceIndex == destIndex
|| (sourceIndex < 0 || sourceIndex > lastIndex)
|| (destIndex < 0 || destIndex > lastIndex)) {
return;
}
m_ruleBookModel->moveRow(QModelIndex(), sourceIndex, QModelIndex(), destIndex);
Q_EMIT editIndexChanged();
updateNeedsSave();
}
void KCMKWinRules::duplicateRule(int index)
{
if (index < 0 || index >= m_ruleBookModel->rowCount()) {
return;
}
const int newIndex = index + 1;
const QString newDescription = i18n("Copy of %1", m_ruleBookModel->descriptionAt(index));
m_ruleBookModel->insertRow(newIndex);
m_ruleBookModel->setRuleSettingsAt(newIndex, *(m_ruleBookModel->ruleSettingsAt(index)));
m_ruleBookModel->setDescriptionAt(newIndex, newDescription);
updateNeedsSave();
}
void KCMKWinRules::exportToFile(const QUrl &path, const QList<int> &indexes)
{
if (indexes.isEmpty()) {
return;
}
const auto config = KSharedConfig::openConfig(path.toLocalFile(), KConfig::SimpleConfig);
const QStringList groups = config->groupList();
for (const QString &groupName : groups) {
config->deleteGroup(groupName);
}
for (int index : indexes) {
if (index < 0 || index > m_ruleBookModel->rowCount()) {
continue;
}
const RuleSettings *origin = m_ruleBookModel->ruleSettingsAt(index);
RuleSettings exported(config, origin->description());
RuleBookModel::copySettingsTo(&exported, *origin);
exported.save();
}
}
void KCMKWinRules::importFromFile(const QUrl &path)
{
const auto config = KSharedConfig::openConfig(path.toLocalFile(), KConfig::SimpleConfig);
const QStringList groups = config->groupList();
if (groups.isEmpty()) {
return;
}
for (const QString &groupName : groups) {
RuleSettings settings(config, groupName);
const bool remove = settings.deleteRule();
const QString importDescription = settings.description();
if (importDescription.isEmpty()) {
continue;
}
// Try to find a rule with the same description to replace
int newIndex = -2;
for (int index = 0; index < m_ruleBookModel->rowCount(); index++) {
if (m_ruleBookModel->descriptionAt(index) == importDescription) {
newIndex = index;
break;
}
}
if (remove) {
m_ruleBookModel->removeRow(newIndex);
continue;
}
if (newIndex < 0) {
newIndex = m_ruleBookModel->rowCount();
m_ruleBookModel->insertRow(newIndex);
}
m_ruleBookModel->setRuleSettingsAt(newIndex, settings);
// Reset rule editor if the current rule changed when importing
if (m_editIndex.row() == newIndex) {
m_rulesModel->setSettings(m_ruleBookModel->ruleSettingsAt(newIndex));
}
}
updateNeedsSave();
}
// Code adapted from original `findRule()` method in `kwin_rules_dialog::main.cpp`
QModelIndex KCMKWinRules::findRuleWithProperties(const QVariantMap &info, bool wholeApp) const
{
const QString wmclass_class = info.value("resourceClass").toString();
const QString wmclass_name = info.value("resourceName").toString();
const QString role = info.value("role").toString();
const WindowType type = static_cast<WindowType>(info.value("type").toInt());
const QString title = info.value("caption").toString();
const QString machine = info.value("clientMachine").toString();
const bool isLocalHost = info.value("localhost").toBool();
int bestMatchRow = -1;
int bestMatchScore = 0;
for (int row = 0; row < m_ruleBookModel->rowCount(); row++) {
const RuleSettings *settings = m_ruleBookModel->ruleSettingsAt(row);
// If the rule doesn't match try the next one
const Rules rule = Rules(settings);
/* clang-format off */
if (!rule.matchWMClass(wmclass_class, wmclass_name)
|| !rule.matchType(type)
|| !rule.matchRole(role)
|| !rule.matchTitle(title)
|| !rule.matchClientMachine(machine, isLocalHost)) {
continue;
}
/* clang-format on */
if (settings->wmclassmatch() != Rules::ExactMatch) {
continue; // too generic
}
// Now that the rule matches the window, check the quality of the match
// It stablishes a quality depending on the match policy of the rule
int score = 0;
bool generic = true;
// from now on, it matches the app - now try to match for a specific window
if (settings->wmclasscomplete()) {
score += 1;
generic = false; // this can be considered specific enough (old X apps)
}
if (!wholeApp) {
if (settings->windowrolematch() != Rules::UnimportantMatch) {
score += settings->windowrolematch() == Rules::ExactMatch ? 5 : 1;
generic = false;
}
if (settings->titlematch() != Rules::UnimportantMatch) {
score += settings->titlematch() == Rules::ExactMatch ? 3 : 1;
generic = false;
}
if (settings->types() != NET::AllTypesMask) {
// Checks that type fits the mask, and only one of the types
int bits = 0;
for (unsigned int bit = 1; bit < 1U << 31; bit <<= 1) {
if (settings->types() & bit) {
++bits;
}
}
if (bits == 1) {
score += 2;
}
}
if (generic) { // ignore generic rules, use only the ones that are for this window
continue;
}
} else {
if (settings->types() == NET::AllTypesMask) {
score += 2;
}
}
if (score > bestMatchScore) {
bestMatchRow = row;
bestMatchScore = score;
}
}
if (bestMatchRow < 0) {
return QModelIndex();
}
return m_ruleBookModel->index(bestMatchRow);
}
// Code adapted from original `findRule()` method in `kwin_rules_dialog::main.cpp`
void KCMKWinRules::fillSettingsFromProperties(RuleSettings *settings, const QVariantMap &info, bool wholeApp) const
{
const QString wmclass_class = info.value("resourceClass").toString();
const QString wmclass_name = info.value("resourceName").toString();
const QString role = info.value("role").toString();
const NET::WindowType type = static_cast<NET::WindowType>(info.value("type").toInt());
const QString title = info.value("caption").toString();
const QString machine = info.value("clientMachine").toString();
settings->setDefaults();
if (wholeApp) {
if (!wmclass_class.isEmpty()) {
settings->setDescription(i18n("Application settings for %1", wmclass_class));
}
// TODO maybe exclude some types? If yes, then also exclude them when searching.
settings->setTypes(NET::AllTypesMask);
settings->setTitlematch(Rules::UnimportantMatch);
settings->setClientmachine(machine); // set, but make unimportant
settings->setClientmachinematch(Rules::UnimportantMatch);
settings->setWindowrolematch(Rules::UnimportantMatch);
if (wmclass_name == wmclass_class) {
settings->setWmclasscomplete(false);
settings->setWmclass(wmclass_class);
settings->setWmclassmatch(Rules::ExactMatch);
} else {
// WM_CLASS components differ - perhaps the app got -name argument
settings->setWmclasscomplete(true);
settings->setWmclass(QStringLiteral("%1 %2").arg(wmclass_name, wmclass_class));
settings->setWmclassmatch(Rules::ExactMatch);
}
return;
}
if (!wmclass_class.isEmpty()) {
settings->setDescription(i18n("Window settings for %1", wmclass_class));
}
if (type == NET::Unknown) {
settings->setTypes(NET::NormalMask);
} else {
settings->setTypes(NET::WindowTypeMask(1 << type)); // convert type to its mask
}
settings->setTitle(title); // set, but make unimportant
settings->setTitlematch(Rules::UnimportantMatch);
settings->setClientmachine(machine); // set, but make unimportant
settings->setClientmachinematch(Rules::UnimportantMatch);
if (!role.isEmpty() && role != "unknown" && role != "unnamed") { // Qt sets this if not specified
settings->setWindowrole(role);
settings->setWindowrolematch(Rules::ExactMatch);
if (wmclass_name == wmclass_class) {
settings->setWmclasscomplete(false);
settings->setWmclass(wmclass_class);
settings->setWmclassmatch(Rules::ExactMatch);
} else {
// WM_CLASS components differ - perhaps the app got -name argument
settings->setWmclasscomplete(true);
settings->setWmclass(QStringLiteral("%1 %2").arg(wmclass_name, wmclass_class));
settings->setWmclassmatch(Rules::ExactMatch);
}
} else { // no role set
if (wmclass_name != wmclass_class) {
// WM_CLASS components differ - perhaps the app got -name argument
settings->setWmclasscomplete(true);
settings->setWmclass(QStringLiteral("%1 %2").arg(wmclass_name, wmclass_class));
settings->setWmclassmatch(Rules::ExactMatch);
} else {
// This is a window that has no role set, and both components of WM_CLASS
// match (possibly only differing in case), which most likely means either
// the application doesn't give a damn about distinguishing its various
// windows, or it's an app that uses role for that, but this window
// lacks it for some reason. Use non-complete WM_CLASS matching, also
// include window title in the matching, and pray it causes many more positive
// matches than negative matches.
// WM_CLASS components differ - perhaps the app got -name argument
settings->setTitlematch(Rules::ExactMatch);
settings->setWmclasscomplete(false);
settings->setWmclass(wmclass_class);
settings->setWmclassmatch(Rules::ExactMatch);
}
}
}
K_PLUGIN_CLASS_WITH_JSON(KCMKWinRules, "kcm_kwinrules.json");
} // namespace
#include "kcmrules.moc"
#include "moc_kcmrules.cpp"

Some files were not shown because too many files have changed in this diff Show More