diff --git a/kcmkwin/kwindecoration/CMakeLists.txt b/kcmkwin/kwindecoration/CMakeLists.txt index e04ed3a87..7fda58158 100644 --- a/kcmkwin/kwindecoration/CMakeLists.txt +++ b/kcmkwin/kwindecoration/CMakeLists.txt @@ -1,41 +1,30 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwindecoration\") add_subdirectory(declarative-plugin) -set(kcm_kwindecoration_PART_SRCS +set(kcmkwindecoration_SRCS kcm.cpp + utils.cpp decorationmodel.cpp declarative-plugin/buttonsmodel.cpp ) -ki18n_wrap_ui(kcm_kwindecoration_PART_SRCS - kcm.ui -) +add_library(kcm_kwindecoration MODULE ${kcmkwindecoration_SRCS}) -add_library(kcm_kwindecoration MODULE ${kcm_kwindecoration_PART_SRCS}) target_link_libraries(kcm_kwindecoration KDecoration2::KDecoration - Qt5::DBus - Qt5::Quick - Qt5::QuickWidgets - Qt5::UiTools - KF5::Completion - KF5::ConfigWidgets - KF5::Declarative KF5::I18n + KF5::QuickAddons KF5::NewStuff - KF5::WindowSystem - KF5::Service + Qt5::Quick ) -install(TARGETS kcm_kwindecoration DESTINATION ${PLUGIN_INSTALL_DIR} ) -########### install files ############### +kcoreaddons_desktop_to_json(kcm_kwindecoration "kwindecoration.desktop" SERVICE_TYPES kcmodule.desktop) + +# This desktop file is installed only for retrocompatibility with sycoca +install(FILES kwindecoration.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) +install(FILES window-decorations.knsrc DESTINATION ${KDE_INSTALL_CONFDIR}) +install(TARGETS kcm_kwindecoration DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms) -install( FILES kwindecoration.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) -install( FILES - qml/main.qml - qml/Buttons.qml - qml/ButtonGroup.qml - qml/Previews.qml - DESTINATION ${DATA_INSTALL_DIR}/kwin/kcm_kwindecoration) +kpackage_install_package(package kcm_kwindecoration kcms) diff --git a/kcmkwin/kwindecoration/Messages.sh b/kcmkwin/kwindecoration/Messages.sh old mode 100644 new mode 100755 index 3f9d8a3d8..3ea44fad0 --- a/kcmkwin/kwindecoration/Messages.sh +++ b/kcmkwin/kwindecoration/Messages.sh @@ -1,4 +1,4 @@ -#!bin/sh -$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp -$XGETTEXT `find . -name \*.qml -o -name \*.cpp -o -name \*.h` -o $podir/kcmkwindecoration.pot +#! /usr/bin/env bash +$EXTRACTRC `find . -name "*.ui"` >> rc.cpp || exit 11 +$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcmkwindecoration.pot rm -f rc.cpp diff --git a/kcmkwin/kwindecoration/declarative-plugin/buttonsmodel.cpp b/kcmkwin/kwindecoration/declarative-plugin/buttonsmodel.cpp index b41752504..b4d9fef4d 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/buttonsmodel.cpp +++ b/kcmkwin/kwindecoration/declarative-plugin/buttonsmodel.cpp @@ -1,183 +1,201 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "buttonsmodel.h" #include #include namespace KDecoration2 { namespace Preview { ButtonsModel::ButtonsModel(const QVector< DecorationButtonType > &buttons, QObject *parent) : QAbstractListModel(parent) , m_buttons(buttons) { } ButtonsModel::ButtonsModel(QObject* parent) : ButtonsModel(QVector({ DecorationButtonType::Menu, DecorationButtonType::ApplicationMenu, DecorationButtonType::OnAllDesktops, DecorationButtonType::Minimize, DecorationButtonType::Maximize, DecorationButtonType::Close, DecorationButtonType::ContextHelp, DecorationButtonType::Shade, DecorationButtonType::KeepBelow, DecorationButtonType::KeepAbove }), 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("Menu"); 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"); case DecorationButtonType::KeepAbove: return i18n("Keep above"); 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 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 + 1, index+1); - m_buttons.insert(index+1, KDecoration2::DecorationButtonType(type)); + beginInsertRows(QModelIndex(), index, index); + m_buttons.insert(index, KDecoration2::DecorationButtonType(type)); endInsertRows(); } void ButtonsModel::move(int sourceIndex, int targetIndex) { if (sourceIndex == qMax(0, targetIndex)) { return; } /* When moving an item down, the destination index needs to be incremented by one, as explained in the documentation: http://doc.qt.nokia.com/qabstractitemmodel.html#beginMoveRows */ if (targetIndex > sourceIndex) { // Row will be moved down beginMoveRows(QModelIndex(), sourceIndex, sourceIndex, QModelIndex(), targetIndex + 1); } else { beginMoveRows(QModelIndex(), sourceIndex, sourceIndex, QModelIndex(), qMax(0, targetIndex)); } m_buttons.move(sourceIndex, qMax(0, targetIndex)); endMoveRows(); } +void ButtonsModel::clear() +{ + beginResetModel(); + m_buttons.clear(); + endResetModel(); +} + +void ButtonsModel::replace(const QVector< DecorationButtonType > &buttons) +{ + if (buttons.isEmpty()) { + return; + } + + beginResetModel(); + m_buttons = buttons; + endResetModel(); +} + } } diff --git a/kcmkwin/kwindecoration/declarative-plugin/buttonsmodel.h b/kcmkwin/kwindecoration/declarative-plugin/buttonsmodel.h index 13f628dd6..0c09119c9 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/buttonsmodel.h +++ b/kcmkwin/kwindecoration/declarative-plugin/buttonsmodel.h @@ -1,64 +1,66 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KDECOARTIONS_PREVIEW_BUTTONS_MODEL_H #define KDECOARTIONS_PREVIEW_BUTTONS_MODEL_H #include #include namespace KDecoration2 { namespace Preview { class PreviewBridge; class ButtonsModel : public QAbstractListModel { Q_OBJECT public: explicit ButtonsModel(const QVector< DecorationButtonType > &buttons, QObject *parent = 0); explicit ButtonsModel(QObject *parent = nullptr); virtual ~ButtonsModel(); 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; QVector< 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 QVector< DecorationButtonType > &buttons); void add(DecorationButtonType type); Q_INVOKABLE void add(int index, int type); private: QVector< DecorationButtonType > m_buttons; }; } } #endif diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewbridge.cpp b/kcmkwin/kwindecoration/declarative-plugin/previewbridge.cpp index 7a7407728..bf52a7be5 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewbridge.cpp +++ b/kcmkwin/kwindecoration/declarative-plugin/previewbridge.cpp @@ -1,255 +1,247 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "previewbridge.h" #include "previewclient.h" #include "previewitem.h" #include "previewsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KDecoration2 { namespace Preview { static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2"); 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 PreviewBridge::createClient(DecoratedClient *client, Decoration *decoration) { auto ptr = std::unique_ptr(new PreviewClient(client, decoration)); m_lastCreatedClient = ptr.get(); return std::move(ptr); } void PreviewBridge::update(Decoration *decoration, const QRect &geometry) { Q_UNUSED(geometry) auto it = std::find_if(m_previewItems.constBegin(), m_previewItems.constEnd(), [decoration](PreviewItem *item) { return item->decoration() == decoration; }); if (it != m_previewItems.constEnd()) { (*it)->update(); } } std::unique_ptr PreviewBridge::settings(DecorationSettings *parent) { auto ptr = std::unique_ptr(new PreviewSettings(parent)); m_lastCreatedSettings = ptr.get(); return std::move(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; - qDebug() << "Plugin changed to: " << m_plugin; emit pluginChanged(); } QString PreviewBridge::theme() const { return m_theme; } void PreviewBridge::setTheme(const QString &theme) { if (m_theme == theme) { return; } m_theme = theme; emit themeChanged(); } QString PreviewBridge::plugin() const { return m_plugin; } void PreviewBridge::createFactory() { m_factory.clear(); + if (m_plugin.isNull()) { setValid(false); - qDebug() <<"Plugin not set"; + qWarning() << "Plugin not set"; return; } - const auto offers = KPluginTrader::self()->query(s_pluginName, - s_pluginName, - QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(m_plugin)); - if (offers.isEmpty()) { - setValid(false); - qDebug() << "no offers"; - return; + + const auto offers = KPluginTrader::self()->query(s_pluginName, s_pluginName); + auto item = std::find_if(offers.constBegin(), offers.constEnd(), [this](const auto &plugin) { return plugin.pluginName() == m_plugin; }); + if (item != offers.constEnd()) { + KPluginLoader loader(item->libraryPath()); + m_factory = loader.factory(); } - KPluginLoader loader(offers.first().libraryPath()); - m_factory = loader.factory(); - qDebug() << "Factory: " << !m_factory.isNull(); + setValid(!m_factory.isNull()); } bool PreviewBridge::isValid() const { return m_valid; } void PreviewBridge::setValid(bool valid) { if (m_valid == valid) { return; } m_valid = valid; 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(parent, QVariantList({args})); } DecorationButton *PreviewBridge::createButton(KDecoration2::Decoration *decoration, KDecoration2::DecorationButtonType type, QObject *parent) { if (!m_valid) { return nullptr; } return m_factory->create(QStringLiteral("button"), parent, QVariantList({QVariant::fromValue(type), QVariant::fromValue(decoration)})); } void PreviewBridge::configure() { if (!m_valid) { return; } //setup the UI QDialog dialog; if (m_lastCreatedClient) { dialog.setWindowTitle(m_lastCreatedClient->caption()); } // create the KCModule through the plugintrader QVariantMap args; if (!m_theme.isNull()) { args.insert(QStringLiteral("theme"), m_theme); } KCModule *kcm = m_factory->create(QStringLiteral("kcmodule"), &dialog, QVariantList({args})); if (!kcm) { return; } auto save = [this,kcm] { kcm->save(); if (m_lastCreatedSettings) { 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); }; connect(&dialog, &QDialog::accepted, this, save); QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | - QDialogButtonBox::Apply | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Reset, &dialog); - QPushButton *apply = buttons->button(QDialogButtonBox::Apply); QPushButton *reset = buttons->button(QDialogButtonBox::Reset); - apply->setEnabled(false); reset->setEnabled(false); // Here we connect our buttons with the dialog connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); - connect(apply, &QPushButton::clicked, this, save); connect(reset, &QPushButton::clicked, kcm, &KCModule::load); auto changedSignal = static_cast(&KCModule::changed); - connect(kcm, changedSignal, apply, &QPushButton::setEnabled); connect(kcm, changedSignal, reset, &QPushButton::setEnabled); connect(buttons->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, kcm, &KCModule::defaults); QVBoxLayout *layout = new QVBoxLayout(&dialog); layout->addWidget(kcm); layout->addWidget(buttons); dialog.exec(); } 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); } BridgeItem::~BridgeItem() { m_bridge->deleteLater(); } } } diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewbutton.cpp b/kcmkwin/kwindecoration/declarative-plugin/previewbutton.cpp index 2a5d34288..fda7d83fc 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewbutton.cpp +++ b/kcmkwin/kwindecoration/declarative-plugin/previewbutton.cpp @@ -1,139 +1,149 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "previewbutton.h" #include "previewbridge.h" #include "previewclient.h" #include "previewsettings.h" #include -#include +#include namespace KDecoration2 { namespace Preview { PreviewButtonItem::PreviewButtonItem(QQuickItem* parent) : QQuickPaintedItem(parent) { } PreviewButtonItem::~PreviewButtonItem() = default; void PreviewButtonItem::setType(int type) { setType(KDecoration2::DecorationButtonType(type)); } void PreviewButtonItem::setType(KDecoration2::DecorationButtonType type) { if (m_type == type) { return; } m_type = type; emit typeChanged(); } KDecoration2::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; emit bridgeChanged(); } Settings *PreviewButtonItem::settings() const { return m_settings.data(); } void PreviewButtonItem::setSettings(Settings *settings) { if (m_settings == settings) { return; } m_settings = settings; emit settingsChanged(); } int PreviewButtonItem::typeAsInt() const { return int(m_type); } void PreviewButtonItem::componentComplete() { QQuickPaintedItem::componentComplete(); createButton(); } void PreviewButtonItem::createButton() { if (m_type == KDecoration2::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->init(); 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; } - m_button->paint(painter, QRect(0, 0, width(), height())); + QRect size { 0, 0, (int)width(), (int)height() }; + m_button->paint(painter, size); + painter->setCompositionMode(QPainter::CompositionMode_SourceAtop); + painter->fillRect(size, m_color); +} + +void PreviewButtonItem::setColor(const QColor color) +{ + m_color = color; + m_color.setAlpha(127); + update(); } } } diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewbutton.h b/kcmkwin/kwindecoration/declarative-plugin/previewbutton.h index 0afdf301b..a2cee4c21 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewbutton.h +++ b/kcmkwin/kwindecoration/declarative-plugin/previewbutton.h @@ -1,81 +1,87 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KDECOARTIONS_PREVIEW_BUTTON_ITEM_H #define KDECOARTIONS_PREVIEW_BUTTON_ITEM_H #include +#include #include #include namespace KDecoration2 { class Decoration; namespace Preview { class PreviewBridge; class Settings; class PreviewButtonItem : public QQuickPaintedItem { Q_OBJECT Q_PROPERTY(KDecoration2::Preview::PreviewBridge *bridge READ bridge WRITE setBridge NOTIFY bridgeChanged) Q_PROPERTY(KDecoration2::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); virtual ~PreviewButtonItem(); void paint(QPainter *painter) override; PreviewBridge *bridge() const; void setBridge(PreviewBridge *bridge); Settings *settings() const; void setSettings(Settings *settings); KDecoration2::DecorationButtonType type() const; int typeAsInt() const; void setType(KDecoration2::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 m_bridge; QPointer m_settings; KDecoration2::Decoration *m_decoration = nullptr; KDecoration2::DecorationButton *m_button = nullptr; KDecoration2::DecorationButtonType m_type = KDecoration2::DecorationButtonType::Custom; }; } // Preview } // KDecoration2 #endif diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp b/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp index c5856ebd5..852d326d0 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp +++ b/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp @@ -1,465 +1,460 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "previewclient.h" #include #include #include #include #include #include namespace KDecoration2 { namespace Preview { PreviewClient::PreviewClient(DecoratedClient *c, Decoration *decoration) : QObject(decoration) , ApplicationMenuEnabledDecoratedClientPrivate(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_desktop(1) , m_width(0) , m_height(0) , m_bordersTopEdge(false) , m_bordersLeftEdge(false) , m_bordersRightEdge(false) , m_bordersBottomEdge(false) { connect(this, &PreviewClient::captionChanged, c, &DecoratedClient::captionChanged); connect(this, &PreviewClient::activeChanged, c, &DecoratedClient::activeChanged); connect(this, &PreviewClient::closeableChanged, c, &DecoratedClient::closeableChanged); connect(this, &PreviewClient::keepAboveChanged, c, &DecoratedClient::keepAboveChanged); connect(this, &PreviewClient::keepBelowChanged, c, &DecoratedClient::keepBelowChanged); connect(this, &PreviewClient::maximizableChanged, c, &DecoratedClient::maximizeableChanged); connect(this, &PreviewClient::maximizedChanged, c, &DecoratedClient::maximizedChanged); connect(this, &PreviewClient::maximizedVerticallyChanged, c, &DecoratedClient::maximizedVerticallyChanged); connect(this, &PreviewClient::maximizedHorizontallyChanged, c, &DecoratedClient::maximizedHorizontallyChanged); connect(this, &PreviewClient::minimizableChanged, c, &DecoratedClient::minimizeableChanged); -// connect(this, &PreviewClient::modalChanged, c, &DecoratedClient::modalChanged); connect(this, &PreviewClient::movableChanged, c, &DecoratedClient::moveableChanged); connect(this, &PreviewClient::onAllDesktopsChanged, c, &DecoratedClient::onAllDesktopsChanged); connect(this, &PreviewClient::resizableChanged, c, &DecoratedClient::resizeableChanged); connect(this, &PreviewClient::shadeableChanged, c, &DecoratedClient::shadeableChanged); connect(this, &PreviewClient::shadedChanged, c, &DecoratedClient::shadedChanged); connect(this, &PreviewClient::providesContextHelpChanged, c, &DecoratedClient::providesContextHelpChanged); connect(this, &PreviewClient::onAllDesktopsChanged, c, &DecoratedClient::onAllDesktopsChanged); connect(this, &PreviewClient::widthChanged, c, &DecoratedClient::widthChanged); connect(this, &PreviewClient::heightChanged, c, &DecoratedClient::heightChanged); connect(this, &PreviewClient::iconChanged, c, &DecoratedClient::iconChanged); connect(this, &PreviewClient::paletteChanged, c, &DecoratedClient::paletteChanged); -// connect(this, &PreviewClient::, c, &DecoratedClient::); connect(this, &PreviewClient::maximizedVerticallyChanged, this, [this]() { emit maximizedChanged(isMaximized()); } ); connect(this, &PreviewClient::maximizedHorizontallyChanged, this, [this]() { emit maximizedChanged(isMaximized()); } ); connect(this, &PreviewClient::iconNameChanged, this, [this]() { m_icon = QIcon::fromTheme(m_iconName); emit iconChanged(m_icon); } ); connect(this, &PreviewClient::desktopChanged, this, [this]() { emit onAllDesktopsChanged(isOnAllDesktops()); } ); connect(&m_palette, &KWin::Decoration::DecorationPalette::changed, [this]() { emit paletteChanged(m_palette.palette()); }); auto emitEdgesChanged = [this, c]() { 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); qApp->installEventFilter(this); } PreviewClient::~PreviewClient() = default; void PreviewClient::setIcon(const QIcon &pixmap) { m_icon = pixmap; emit iconChanged(m_icon); } int PreviewClient::width() const { return m_width; } int PreviewClient::height() const { return m_height; } QString PreviewClient::caption() const { return m_caption; } WId PreviewClient::decorationId() const { return 0; } int PreviewClient::desktop() const { return m_desktop; } void PreviewClient::setDesktop(int desktop) { if (desktop == 0) { desktop = 1; } if (m_desktop == desktop) { return; } m_desktop = desktop; emit desktopChanged(m_desktop); } 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 desktop() == -1; } 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; } WId PreviewClient::windowId() const { return 0; } 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; } 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; emit bordersBottomEdgeChanged(enabled); } void PreviewClient::setBordersLeftEdge(bool enabled) { if (m_bordersLeftEdge == enabled) { return; } m_bordersLeftEdge = enabled; emit bordersLeftEdgeChanged(enabled); } void PreviewClient::setBordersRightEdge(bool enabled) { if (m_bordersRightEdge == enabled) { return; } m_bordersRightEdge = enabled; emit bordersRightEdgeChanged(enabled); } void PreviewClient::setBordersTopEdge(bool enabled) { if (m_bordersTopEdge == enabled) { return; } m_bordersTopEdge = enabled; emit bordersTopEdgeChanged(enabled); } void PreviewClient::requestShowToolTip(const QString &text) { - qDebug() << "tooltip show requested with text:" << text; + Q_UNUSED(text); } void PreviewClient::requestHideToolTip() { - qDebug() << "tooltip hide requested"; } void PreviewClient::requestClose() { emit closeRequested(); } void PreviewClient::requestContextHelp() { - qDebug() << "context help requested"; } 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() { emit minimizeRequested(); } void PreviewClient::requestToggleKeepAbove() { setKeepAbove(!isKeepAbove()); } void PreviewClient::requestToggleKeepBelow() { setKeepBelow(!isKeepBelow()); } void PreviewClient::requestShowWindowMenu() { emit showWindowMenuRequested(); } void PreviewClient::requestShowApplicationMenu(const QRect &rect, int actionId) { Q_UNUSED(rect); Q_UNUSED(actionId); } void PreviewClient::showApplicationMenu(int actionId) { Q_UNUSED(actionId) } void PreviewClient::requestToggleOnAllDesktops() { setDesktop(isOnAllDesktops() ? 1 : -1); } void PreviewClient::requestToggleShade() { setShaded(!isShaded()); } #define SETTER(type, name, variable) \ void PreviewClient::name(type variable) \ { \ if (m_##variable == variable) { \ return; \ } \ - qDebug() << "Setting " << #variable << ":" << variable;\ m_##variable = variable; \ 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 KDecoration2 diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewitem.cpp b/kcmkwin/kwindecoration/declarative-plugin/previewitem.cpp index 534f6e17c..5153db977 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewitem.cpp +++ b/kcmkwin/kwindecoration/declarative-plugin/previewitem.cpp @@ -1,500 +1,468 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "previewitem.h" #include "previewbridge.h" #include "previewsettings.h" #include "previewclient.h" #include #include #include #include #include #include #include #include #include #include #include namespace KDecoration2 { namespace Preview { PreviewItem::PreviewItem(QQuickItem *parent) : QQuickPaintedItem(parent) , m_decoration(nullptr) , m_windowColor(QPalette().background().color()) { setAcceptHoverEvents(true); setFiltersChildMouseEvents(true); setAcceptedMouseButtons(Qt::MouseButtons(~Qt::NoButton)); 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() { 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->init(); syncSize(); } } void PreviewItem::createDecoration() { if (m_bridge.isNull() || m_settings.isNull() || m_decoration) { return; } - m_decoration = m_bridge->createDecoration(0); - if (!m_decoration) { - return; - } - m_decoration->setProperty("visualParent", QVariant::fromValue(this)); + Decoration *decoration = m_bridge->createDecoration(0); m_client = m_bridge->lastCreatedClient(); - connect(m_decoration, &Decoration::bordersChanged, this, &PreviewItem::syncSize); - connect(m_decoration, &Decoration::shadowChanged, this, &PreviewItem::syncSize); - emit decorationChanged(m_decoration); + setDecoration(decoration); } Decoration *PreviewItem::decoration() const { return m_decoration; } void PreviewItem::setDecoration(Decoration *deco) { - if (m_decoration == deco) { + if (!deco || m_decoration == deco) { return; } - auto updateSlot = static_cast(&QQuickItem::update); - if (m_decoration) { - disconnect(m_decoration, &Decoration::bordersChanged, this, updateSlot); - } + m_decoration = deco; m_decoration->setProperty("visualParent", QVariant::fromValue(this)); - connect(m_decoration, &Decoration::bordersChanged, this, updateSlot); - connect(m_decoration, &Decoration::sectionUnderMouseChanged, this, - [this](Qt::WindowFrameSection section) { - switch (section) { - case Qt::TopRightSection: - case Qt::BottomLeftSection: - setCursor(Qt::SizeBDiagCursor); - return; - case Qt::TopLeftSection: - case Qt::BottomRightSection: - setCursor(Qt::SizeFDiagCursor); - return; - case Qt::TopSection: - case Qt::BottomSection: - setCursor(Qt::SizeVerCursor); - return; - case Qt::LeftSection: - case Qt::RightSection: - setCursor(Qt::SizeHorCursor); - return; - default: - setCursor(Qt::ArrowCursor); - } - } - ); - connect(m_decoration, &KDecoration2::Decoration::shadowChanged, this, &PreviewItem::shadowChanged); + connect(m_decoration, &Decoration::bordersChanged, this, &PreviewItem::syncSize); + connect(m_decoration, &Decoration::shadowChanged, this, &PreviewItem::syncSize); + connect(m_decoration, &Decoration::shadowChanged, this, &PreviewItem::shadowChanged); 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; 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 = ((const Decoration*)(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 QSize topLeftSize(shadow->topLeftGeometry().size()); QRect topLeftTarget( QPoint(outerRect.x(), outerRect.y()), topLeftSize); const QSize topRightSize(shadow->topRightGeometry().size()); QRect topRightTarget( QPoint(outerRect.x() + outerRect.width() - topRightSize.width(), outerRect.y()), topRightSize); const QSize bottomRightSize(shadow->bottomRightGeometry().size()); QRect bottomRightTarget( QPoint(outerRect.x() + outerRect.width() - bottomRightSize.width(), outerRect.y() + outerRect.height() - bottomRightSize.height()), bottomRightSize); const QSize bottomLeftSize(shadow->bottomLeftGeometry().size()); QRect bottomLeftTarget( QPoint(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 = qAbs(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 = qAbs(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 = qAbs(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 = qAbs(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, QRect(QPoint(0, 0), topLeftTarget.size())); painter->drawImage(topRightTarget, shadowPixmap, QRect(QPoint(shadowRect.width() - topRightTarget.width(), 0), topRightTarget.size())); painter->drawImage(bottomRightTarget, shadowPixmap, QRect(QPoint(shadowRect.width() - bottomRightTarget.width(), shadowRect.height() - bottomRightTarget.height()), bottomRightTarget.size())); painter->drawImage(bottomLeftTarget, shadowPixmap, QRect(QPoint(0, shadowRect.height() - bottomLeftTarget.height()), bottomLeftTarget.size())); if (drawTop) { QRect topTarget(topLeftTarget.x() + topLeftTarget.width(), topLeftTarget.y(), topRightTarget.x() - topLeftTarget.x() - topLeftTarget.width(), topRightTarget.height()); QRect topSource(shadow->topGeometry()); topSource.setHeight(topTarget.height()); topSource.moveTop(shadowRect.top()); painter->drawImage(topTarget, shadowPixmap, topSource); } if (drawRight) { QRect rightTarget(topRightTarget.x(), topRightTarget.y() + topRightTarget.height(), topRightTarget.width(), bottomRightTarget.y() - topRightTarget.y() - topRightTarget.height()); QRect rightSource(shadow->rightGeometry()); rightSource.setWidth(rightTarget.width()); rightSource.moveRight(shadowRect.right()); painter->drawImage(rightTarget, shadowPixmap, rightSource); } if (drawBottom) { QRect bottomTarget(bottomLeftTarget.x() + bottomLeftTarget.width(), bottomLeftTarget.y(), bottomRightTarget.x() - bottomLeftTarget.x() - bottomLeftTarget.width(), bottomRightTarget.height()); QRect bottomSource(shadow->bottomGeometry()); bottomSource.setHeight(bottomTarget.height()); bottomSource.moveBottom(shadowRect.bottom()); painter->drawImage(bottomTarget, shadowPixmap, bottomSource); } if (drawLeft) { QRect leftTarget(topLeftTarget.x(), topLeftTarget.y() + topLeftTarget.height(), topLeftTarget.width(), bottomLeftTarget.y() - topLeftTarget.y() - topLeftTarget.height()); QRect leftSource(shadow->leftGeometry()); leftSource.setWidth(leftTarget.width()); leftSource.moveLeft(shadowRect.left()); painter->drawImage(leftTarget, shadowPixmap, leftSource); } } void PreviewItem::mouseDoubleClickEvent(QMouseEvent *event) { const auto &shadow = m_decoration->shadow(); if (shadow) { QMouseEvent e(event->type(), event->localPos() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->button(), event->buttons(), event->modifiers()); QCoreApplication::instance()->sendEvent(decoration(), &e); } else { QCoreApplication::instance()->sendEvent(decoration(), event); } } void PreviewItem::mousePressEvent(QMouseEvent *event) { const auto &shadow = m_decoration->shadow(); if (shadow) { QMouseEvent e(event->type(), event->localPos() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->button(), event->buttons(), event->modifiers()); QCoreApplication::instance()->sendEvent(decoration(), &e); } else { QCoreApplication::instance()->sendEvent(decoration(), event); } } void PreviewItem::mouseReleaseEvent(QMouseEvent *event) { const auto &shadow = m_decoration->shadow(); if (shadow) { QMouseEvent e(event->type(), event->localPos() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->button(), event->buttons(), event->modifiers()); QCoreApplication::instance()->sendEvent(decoration(), &e); } else { QCoreApplication::instance()->sendEvent(decoration(), event); } } void PreviewItem::mouseMoveEvent(QMouseEvent *event) { const auto &shadow = m_decoration->shadow(); if (shadow) { QMouseEvent e(event->type(), event->localPos() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->button(), event->buttons(), event->modifiers()); QCoreApplication::instance()->sendEvent(decoration(), &e); } else { QCoreApplication::instance()->sendEvent(decoration(), event); } } void PreviewItem::hoverEnterEvent(QHoverEvent *event) { const auto &shadow = m_decoration->shadow(); if (shadow) { QHoverEvent e(event->type(), event->posF() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->oldPosF() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->modifiers()); QCoreApplication::instance()->sendEvent(decoration(), &e); } else { QCoreApplication::instance()->sendEvent(decoration(), event); } } void PreviewItem::hoverLeaveEvent(QHoverEvent *event) { const auto &shadow = m_decoration->shadow(); if (shadow) { QHoverEvent e(event->type(), event->posF() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->oldPosF() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->modifiers()); QCoreApplication::instance()->sendEvent(decoration(), &e); } else { QCoreApplication::instance()->sendEvent(decoration(), event); } } void PreviewItem::hoverMoveEvent(QHoverEvent *event) { const auto &shadow = m_decoration->shadow(); if (shadow) { QHoverEvent e(event->type(), event->posF() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->oldPosF() - QPointF(shadow->paddingLeft(), shadow->paddingTop()), event->modifiers()); QCoreApplication::instance()->sendEvent(decoration(), &e); } else { QCoreApplication::instance()->sendEvent(decoration(), event); } } bool PreviewItem::isDrawingBackground() const { return m_drawBackground; } void PreviewItem::setDrawingBackground(bool set) { if (m_drawBackground == set) { return; } m_drawBackground = set; 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); } emit bridgeChanged(); } Settings *PreviewItem::settings() const { return m_settings.data(); } void PreviewItem::setSettings(Settings *settings) { if (m_settings == settings) { return; } m_settings = settings; 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; } const auto &s = m_decoration->shadow(); if (!s) { return nullptr; } return s.data(); } } } diff --git a/kcmkwin/kwindecoration/decorationmodel.cpp b/kcmkwin/kwindecoration/decorationmodel.cpp index 2bd173590..7568bdd36 100644 --- a/kcmkwin/kwindecoration/decorationmodel.cpp +++ b/kcmkwin/kwindecoration/decorationmodel.cpp @@ -1,196 +1,196 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "decorationmodel.h" // KDecoration2 #include #include // KDE #include #include #include #include // Qt #include namespace KDecoration2 { namespace Configuration { static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2"); 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 Data &d = m_plugins.at(index.row()); switch (role) { case Qt::DisplayRole: return d.visibleName; - case Qt::UserRole +4: + case PluginNameRole: return d.pluginName; - case Qt::UserRole +5: + case ThemeNameRole: return d.themeName; - case Qt::UserRole +6: + case ConfigurationRole: return d.configuration; } - return QVariant(); } QHash< int, QByteArray > DecorationsModel::roleNames() const { QHash roles({ {Qt::DisplayRole, QByteArrayLiteral("display")}, - {Qt::UserRole + 4, QByteArrayLiteral("plugin")}, - {Qt::UserRole + 5, QByteArrayLiteral("theme")}, - {Qt::UserRole +6, QByteArrayLiteral("configureable")} + {PluginNameRole, QByteArrayLiteral("plugin")}, + {ThemeNameRole, QByteArrayLiteral("theme")}, + {ConfigurationRole, QByteArrayLiteral("configureable")} }); 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 bool isConfigureable(const QVariantMap &decoSettingsMap) { auto it = decoSettingsMap.find(QStringLiteral("kcmodule")); if (it == decoSettingsMap.end()) { return false; } return it.value().toBool(); } 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 = KPluginTrader::self()->query(s_pluginName, s_pluginName); for (const auto &info : plugins) { KPluginLoader loader(info.libraryPath()); KPluginFactory *factory = loader.factory(); if (!factory) { continue; } auto metadata = loader.metaData().value(QStringLiteral("MetaData")).toObject().value(s_pluginName); bool config = false; if (!metadata.isUndefined()) { const auto decoSettingsMap = metadata.toObject().toVariantMap(); const QString &kns = findKNewStuff(decoSettingsMap); - if (!kns.isEmpty()) { - m_knsProvides.insert(kns, info.name().isEmpty() ? info.pluginName() : info.name()); + 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; } QScopedPointer themeFinder(factory->create(keyword)); if (themeFinder.isNull()) { continue; } QVariant themes = themeFinder->property("themes"); if (!themes.isValid()) { continue; } const auto themesMap = themes.toMap(); for (auto it = themesMap.begin(); it != themesMap.end(); ++it) { Data d; d.pluginName = info.pluginName(); d.themeName = it.value().toString(); d.visibleName = it.key(); QMetaObject::invokeMethod(themeFinder.data(), "hasConfiguration", Q_RETURN_ARG(bool, d.configuration), Q_ARG(QString, d.themeName)); m_plugins.emplace_back(std::move(d)); } // it's a theme engine, we don't want to show this entry continue; } config = isConfigureable(decoSettingsMap); } Data data; data.pluginName = info.pluginName(); data.visibleName = info.name().isEmpty() ? info.pluginName() : info.name(); + data.themeName = data.visibleName; data.configuration = config; 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 Data &d) { return d.pluginName == pluginName && d.themeName == themeName; } ); if (it == m_plugins.cend()) { return QModelIndex(); } const auto distance = std::distance(m_plugins.cbegin(), it); return createIndex(distance, 0); } } } diff --git a/kcmkwin/kwindecoration/decorationmodel.h b/kcmkwin/kwindecoration/decorationmodel.h index 41af88d3e..bd68fdf69 100644 --- a/kcmkwin/kwindecoration/decorationmodel.h +++ b/kcmkwin/kwindecoration/decorationmodel.h @@ -1,65 +1,72 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KDECORATION_DECORATION_MODEL_H #define KDECORATION_DECORATION_MODEL_H #include namespace KDecoration2 { namespace Configuration { class DecorationsModel : public QAbstractListModel { Q_OBJECT +public: + enum DecorationRole { + PluginNameRole = Qt::UserRole + 1, + ThemeNameRole, + ConfigurationRole, + }; + public: explicit DecorationsModel(QObject *parent = nullptr); virtual ~DecorationsModel(); 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; - QMap knsProviders() const { - return m_knsProvides; + QStringList knsProviders() const { + return m_knsProviders; } public Q_SLOTS: void init(); private: struct Data { QString pluginName; QString themeName; QString visibleName; bool configuration = false; }; std::vector m_plugins; - QMap m_knsProvides; + QStringList m_knsProviders; }; } } #endif diff --git a/kcmkwin/kwindecoration/kcm.cpp b/kcmkwin/kwindecoration/kcm.cpp index b0a6f0022..64255d8ce 100644 --- a/kcmkwin/kwindecoration/kcm.cpp +++ b/kcmkwin/kwindecoration/kcm.cpp @@ -1,432 +1,314 @@ /* - * Copyright 2014 Martin Gräßlin + * Copyright (c) 2019 Valerio Pilo * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. */ + #include "kcm.h" #include "decorationmodel.h" #include "declarative-plugin/buttonsmodel.h" #include -// KDE +#include #include +#include #include -#include -#include -#include -#include -// Qt +#include + #include #include -#include -#include -#include -#include +#include #include -#include +#include #include -#include -#include -K_PLUGIN_FACTORY(KDecorationFactory, - registerPlugin(); - ) +#include + + +K_PLUGIN_FACTORY_WITH_JSON(KCMKWinDecorationFactory, "kwindecoration.json", registerPlugin();) Q_DECLARE_METATYPE(KDecoration2::BorderSize) -namespace KDecoration2 -{ -namespace Configuration +namespace { -static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2"); +const QString s_configFile { QStringLiteral("kwinrc") }; +const QString s_configGroup { QStringLiteral("org.kde.kdecoration2") }; +const QString s_configPlugin { QStringLiteral("library") }; +const QString s_configTheme { QStringLiteral("theme") }; +const QString s_configBorderSize { QStringLiteral("BorderSize") }; +const QString s_configCloseOnDoubleClickOnMenu { QStringLiteral("CloseOnDoubleClickOnMenu") }; +const QString s_configDecoButtonsOnLeft { QStringLiteral("ButtonsOnLeft") }; +const QString s_configDecoButtonsOnRight { QStringLiteral("ButtonsOnRight") }; + +const KDecoration2::BorderSize s_defaultBorderSize = KDecoration2::BorderSize::Normal; +const bool s_defaultCloseOnDoubleClickOnMenu = false; + +const DecorationButtonsList s_defaultDecoButtonsOnLeft { + KDecoration2::DecorationButtonType::Menu, + KDecoration2::DecorationButtonType::OnAllDesktops +}; +const DecorationButtonsList s_defaultDecoButtonsOnRight { + KDecoration2::DecorationButtonType::ContextHelp, + KDecoration2::DecorationButtonType::Minimize, + KDecoration2::DecorationButtonType::Maximize, + KDecoration2::DecorationButtonType::Close +}; + #if HAVE_BREEZE_DECO -static const QString s_defaultPlugin = QStringLiteral(BREEZE_KDECORATION_PLUGIN_ID); -static const QString s_defaultTheme; +const QString s_defaultPlugin { QStringLiteral(BREEZE_KDECORATION_PLUGIN_ID) }; +const QString s_defaultTheme { QStringLiteral("Breeze") }; #else -static const QString s_defaultPlugin = QStringLiteral("org.kde.kwin.aurorae"); -static const QString s_defaultTheme = QStringLiteral("kwin4_decoration_qml_plastik"); +const QString s_defaultPlugin { QStringLiteral("org.kde.kwin.aurorae") }; +const QString s_defaultTheme { QStringLiteral("kwin4_decoration_qml_plastik") }; #endif -static const QString s_borderSizeNormal = QStringLiteral("Normal"); -static const QString s_ghnsIcon = QStringLiteral("get-hot-new-stuff"); +} -ConfigurationForm::ConfigurationForm(QWidget *parent) - : QWidget(parent) +KCMKWinDecoration::KCMKWinDecoration(QObject *parent, const QVariantList &arguments) + : KQuickAddons::ConfigModule(parent, arguments) + , m_themesModel(new KDecoration2::Configuration::DecorationsModel(this)) + , m_proxyThemesModel(new QSortFilterProxyModel(this)) + , m_leftButtonsModel(new KDecoration2::Preview::ButtonsModel(DecorationButtonsList(), this)) + , m_rightButtonsModel(new KDecoration2::Preview::ButtonsModel(DecorationButtonsList(), this)) + , m_availableButtonsModel(new KDecoration2::Preview::ButtonsModel(this)) + , m_savedSettings{ s_defaultBorderSize, -2 /* for setTheme() */, false, s_defaultDecoButtonsOnLeft, s_defaultDecoButtonsOnRight } + , m_currentSettings(m_savedSettings) { - setupUi(this); + auto about = new KAboutData(QStringLiteral("kcm_kwindecoration"), + i18n("Configure window titlebars and borders"), + QStringLiteral("1.0"), + QString(), + KAboutLicense::GPL); + about->addAuthor(i18n("Valerio Pilo"), + i18n("Author"), + QStringLiteral("vpilo@coldshock.net")); + setAboutData(about); + + qmlRegisterType(); + qmlRegisterType(); + + m_proxyThemesModel->setSourceModel(m_themesModel); + m_proxyThemesModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_proxyThemesModel->setSortCaseSensitivity(Qt::CaseInsensitive); + m_proxyThemesModel->sort(0); + + connect(m_leftButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::updateNeedsSave); + connect(m_leftButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::updateNeedsSave); + connect(m_leftButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::updateNeedsSave); + connect(m_leftButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::updateNeedsSave); + connect(m_rightButtonsModel, &QAbstractItemModel::rowsInserted, this, &KCMKWinDecoration::updateNeedsSave); + connect(m_rightButtonsModel, &QAbstractItemModel::rowsMoved, this, &KCMKWinDecoration::updateNeedsSave); + connect(m_rightButtonsModel, &QAbstractItemModel::rowsRemoved, this, &KCMKWinDecoration::updateNeedsSave); + connect(m_rightButtonsModel, &QAbstractItemModel::modelReset, this, &KCMKWinDecoration::updateNeedsSave); + + // 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, "init", Qt::QueuedConnection); } -static bool s_loading = false; +void KCMKWinDecoration::reloadKWinSettings() +{ + QMetaObject::invokeMethod(m_themesModel, "init", Qt::QueuedConnection); +} -ConfigurationModule::ConfigurationModule(QWidget *parent, const QVariantList &args) - : KCModule(parent, args) - , m_model(new DecorationsModel(this)) - , m_proxyModel(new QSortFilterProxyModel(this)) - , m_ui(new ConfigurationForm(this)) - , m_leftButtons(new Preview::ButtonsModel(QVector(), this)) - , m_rightButtons(new Preview::ButtonsModel(QVector(), this)) - , m_availableButtons(new Preview::ButtonsModel(this)) +void KCMKWinDecoration::getNewStuff(QQuickItem *context) { - m_proxyModel->setSourceModel(m_model); - m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); - m_proxyModel->sort(0); - connect(m_ui->filter, &QLineEdit::textChanged, m_proxyModel, &QSortFilterProxyModel::setFilterFixedString); - - m_quickView = new QQuickView(0); - KDeclarative::KDeclarative kdeclarative; - kdeclarative.setDeclarativeEngine(m_quickView->engine()); - kdeclarative.setTranslationDomain(QStringLiteral(TRANSLATION_DOMAIN)); - kdeclarative.setupContext(); - kdeclarative.setupEngine(m_quickView->engine()); - - qmlRegisterType(); - QWidget *widget = QWidget::createWindowContainer(m_quickView, this); - QVBoxLayout* layout = new QVBoxLayout(m_ui->view); - layout->setContentsMargins(0,0,0,0); - layout->addWidget(widget); - - m_quickView->rootContext()->setContextProperty(QStringLiteral("decorationsModel"), m_proxyModel); - updateColors(); - m_quickView->rootContext()->setContextProperty("_borderSizesIndex", 3); // 3 is normal - m_quickView->rootContext()->setContextProperty("leftButtons", m_leftButtons); - m_quickView->rootContext()->setContextProperty("rightButtons", m_rightButtons); - m_quickView->rootContext()->setContextProperty("availableButtons", m_availableButtons); - m_quickView->rootContext()->setContextProperty("initialThemeIndex", -1); - - m_quickView->rootContext()->setContextProperty("titleFont", QFontDatabase::systemFont(QFontDatabase::TitleFont)); - m_quickView->setResizeMode(QQuickView::SizeRootObjectToView); - m_quickView->setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/kcm_kwindecoration/main.qml")))); - if (m_quickView->status() == QQuickView::Ready) { - auto listView = m_quickView->rootObject()->findChild("listView"); - if (listView) { - connect(listView, SIGNAL(userChangedSelection()), this, SLOT(changed())); - } + if (!m_newStuffDialog) { + m_newStuffDialog = new KNS3::DownloadDialog(QStringLiteral("window-decorations.knsrc")); + m_newStuffDialog->setWindowTitle(i18n("Download New Window Decorations")); + m_newStuffDialog->setWindowModality(Qt::WindowModal); + connect(m_newStuffDialog, &KNS3::DownloadDialog::accepted, this, &KCMKWinDecoration::load); } - m_ui->tabWidget->tabBar()->disconnect(); - auto setCurrentTab = [this](int index) { - if (index == 0) - m_ui->doubleClickMessage->hide(); - m_ui->filter->setVisible(index == 0); - m_ui->knsButton->setVisible(index == 0); - if (auto themeList = m_quickView->rootObject()->findChild("themeList")) { - themeList->setVisible(index == 0); - } - m_ui->borderSizesLabel->setVisible(index == 0); - m_ui->borderSizesCombo->setVisible(index == 0); + if (context && context->window()) { + m_newStuffDialog->winId(); // so it creates the windowHandle() + m_newStuffDialog->windowHandle()->setTransientParent(context->window()); + } - m_ui->closeWindowsDoubleClick->setVisible(index == 1); - if (auto buttonLayout = m_quickView->rootObject()->findChild("buttonLayout")) { - buttonLayout->setVisible(index == 1); - } - }; - connect(m_ui->tabWidget->tabBar(), &QTabBar::currentChanged, this, setCurrentTab); - setCurrentTab(0); - - m_ui->doubleClickMessage->setVisible(false); - m_ui->doubleClickMessage->setText(i18n("Close by double clicking:\n To open the menu, keep the button pressed until it appears.")); - m_ui->doubleClickMessage->setCloseButtonVisible(true); - m_ui->borderSizesCombo->setItemData(0, QVariant::fromValue(BorderSize::None)); - m_ui->borderSizesCombo->setItemData(1, QVariant::fromValue(BorderSize::NoSides)); - m_ui->borderSizesCombo->setItemData(2, QVariant::fromValue(BorderSize::Tiny)); - m_ui->borderSizesCombo->setItemData(3, QVariant::fromValue(BorderSize::Normal)); - m_ui->borderSizesCombo->setItemData(4, QVariant::fromValue(BorderSize::Large)); - m_ui->borderSizesCombo->setItemData(5, QVariant::fromValue(BorderSize::VeryLarge)); - m_ui->borderSizesCombo->setItemData(6, QVariant::fromValue(BorderSize::Huge)); - m_ui->borderSizesCombo->setItemData(7, QVariant::fromValue(BorderSize::VeryHuge)); - m_ui->borderSizesCombo->setItemData(8, QVariant::fromValue(BorderSize::Oversized)); - m_ui->knsButton->setIcon(QIcon::fromTheme(s_ghnsIcon)); - - auto changedSlot = static_cast(&ConfigurationModule::changed); - connect(m_ui->closeWindowsDoubleClick, &QCheckBox::stateChanged, this, changedSlot); - connect(m_ui->closeWindowsDoubleClick, &QCheckBox::toggled, this, - [this] (bool toggled) { - if (s_loading) { - return; - } - if (toggled) - m_ui->doubleClickMessage->animatedShow(); - else - m_ui->doubleClickMessage->animatedHide(); - } - ); - connect(m_ui->borderSizesCombo, static_cast(&QComboBox::currentIndexChanged), - this, [this] (int index) { - auto listView = m_quickView->rootObject()->findChild("listView"); - if (listView) { - listView->setProperty("borderSizesIndex", index); - } - changed(); - } - ); - connect(m_model, &QAbstractItemModel::modelReset, this, - [this] { - const auto &kns = m_model->knsProviders(); - m_ui->knsButton->setEnabled(!kns.isEmpty()); - if (kns.isEmpty()) { - return; - } - if (kns.count() > 1) { - QMenu *menu = new QMenu(m_ui->knsButton); - for (auto it = kns.begin(); it != kns.end(); ++it) { - QAction *action = menu->addAction(QIcon::fromTheme(s_ghnsIcon), it.value()); - action->setData(it.key()); - connect(action, &QAction::triggered, this, [this, action] { showKNS(action->data().toString());}); - } - m_ui->knsButton->setMenu(menu); - } - } - ); - connect(m_ui->knsButton, &QPushButton::clicked, this, - [this] { - const auto &kns = m_model->knsProviders(); - if (kns.isEmpty()) { - return; - } - showKNS(kns.firstKey()); - } - ); - connect(m_leftButtons, &QAbstractItemModel::rowsInserted, this, changedSlot); - connect(m_leftButtons, &QAbstractItemModel::rowsMoved, this, changedSlot); - connect(m_leftButtons, &QAbstractItemModel::rowsRemoved, this, changedSlot); - connect(m_rightButtons, &QAbstractItemModel::rowsInserted, this, changedSlot); - connect(m_rightButtons, &QAbstractItemModel::rowsMoved, this, changedSlot); - connect(m_rightButtons, &QAbstractItemModel::rowsRemoved, this, changedSlot); - - QVBoxLayout *l = new QVBoxLayout(this); - l->addWidget(m_ui); - QMetaObject::invokeMethod(m_model, "init", Qt::QueuedConnection); - - m_ui->installEventFilter(this); + m_newStuffDialog->show(); } -ConfigurationModule::~ConfigurationModule() = default; +void KCMKWinDecoration::load() +{ + const KConfigGroup config = KSharedConfig::openConfig(s_configFile)->group(s_configGroup); + + const QString plugin = config.readEntry(s_configPlugin, s_defaultPlugin); + const QString theme = config.readEntry(s_configTheme, s_defaultTheme); + int themeIndex = m_proxyThemesModel->mapFromSource(m_themesModel->findDecoration(plugin, theme)).row(); + if (themeIndex < 0) { + qWarning() << "Plugin" << plugin << "and theme" << theme << "not found"; + } else { + qDebug() << "Current theme: plugin" << plugin << "and theme" << theme; + } + setTheme(themeIndex); + + setCloseOnDoubleClickOnMenu(config.readEntry(s_configCloseOnDoubleClickOnMenu, s_defaultCloseOnDoubleClickOnMenu)); + + const QString defaultSizeName = Utils::borderSizeToString(s_defaultBorderSize); + setBorderSize(Utils::stringToBorderSize(config.readEntry(s_configBorderSize, defaultSizeName))); + + m_leftButtonsModel->replace(Utils::readDecorationButtons(config, s_configDecoButtonsOnLeft, s_defaultDecoButtonsOnLeft)); + m_rightButtonsModel->replace(Utils::readDecorationButtons(config, s_configDecoButtonsOnRight, s_defaultDecoButtonsOnRight)); + m_currentSettings.buttonsOnLeft = m_leftButtonsModel->buttons(); + m_currentSettings.buttonsOnRight = m_rightButtonsModel->buttons(); -void ConfigurationModule::showEvent(QShowEvent *ev) + m_savedSettings = m_currentSettings; + + updateNeedsSave(); +} + +void KCMKWinDecoration::save() { - KCModule::showEvent(ev); + KConfigGroup config = KSharedConfig::openConfig(s_configFile)->group(s_configGroup); + + if (m_currentSettings.themeIndex >= 0) { + const QModelIndex index = m_proxyThemesModel->index(m_currentSettings.themeIndex, 0); + if (index.isValid()) { + const QString plugin = index.data(KDecoration2::Configuration::DecorationsModel::PluginNameRole).toString(); + const QString theme = index.data(KDecoration2::Configuration::DecorationsModel::ThemeNameRole).toString(); + config.writeEntry(s_configPlugin, plugin); + config.writeEntry(s_configTheme, theme); + qDebug() << "Saved theme: plugin" << plugin << "and theme" << theme; + } else { + qWarning() << "Cannot match theme index" << m_currentSettings.themeIndex << "in model"; + } + } + + config.writeEntry(s_configCloseOnDoubleClickOnMenu, m_currentSettings.closeOnDoubleClickOnMenu); + config.writeEntry(s_configBorderSize, Utils::borderSizeToString(m_currentSettings.borderSize)); + config.writeEntry(s_configDecoButtonsOnLeft, Utils::buttonsToString(m_currentSettings.buttonsOnLeft)); + config.writeEntry(s_configDecoButtonsOnRight, Utils::buttonsToString(m_currentSettings.buttonsOnRight)); + config.sync(); + + m_savedSettings = m_currentSettings; + + // Send a signal to all kwin instances + QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), + QStringLiteral("org.kde.KWin"), + QStringLiteral("reloadConfig")); + QDBusConnection::sessionBus().send(message); + + updateNeedsSave(); } -static const QMap s_sizes = QMap({ - {QStringLiteral("None"), BorderSize::None}, - {QStringLiteral("NoSides"), BorderSize::NoSides}, - {QStringLiteral("Tiny"), BorderSize::Tiny}, - {s_borderSizeNormal, BorderSize::Normal}, - {QStringLiteral("Large"), BorderSize::Large}, - {QStringLiteral("VeryLarge"), BorderSize::VeryLarge}, - {QStringLiteral("Huge"), BorderSize::Huge}, - {QStringLiteral("VeryHuge"), BorderSize::VeryHuge}, - {QStringLiteral("Oversized"), BorderSize::Oversized} -}); - -static BorderSize stringToSize(const QString &name) +void KCMKWinDecoration::defaults() { - auto it = s_sizes.constFind(name); - if (it == s_sizes.constEnd()) { - // non sense values are interpreted just like normal - return BorderSize::Normal; + int themeIndex = m_proxyThemesModel->mapFromSource(m_themesModel->findDecoration(s_defaultPlugin, s_defaultTheme)).row(); + if (themeIndex < 0) { + qWarning() << "Default plugin" << s_defaultPlugin << "and theme" << s_defaultTheme << "not found"; } - return it.value(); + setTheme(themeIndex); + setBorderSize(s_defaultBorderSize); + setCloseOnDoubleClickOnMenu(s_defaultCloseOnDoubleClickOnMenu); + + m_leftButtonsModel->replace(s_defaultDecoButtonsOnLeft); + m_rightButtonsModel->replace(s_defaultDecoButtonsOnRight); + + updateNeedsSave(); } -static QString sizeToString(BorderSize size) +void KCMKWinDecoration::updateNeedsSave() { - return s_sizes.key(size, s_borderSizeNormal); + m_currentSettings.buttonsOnLeft = m_leftButtonsModel->buttons(); + m_currentSettings.buttonsOnRight = m_rightButtonsModel->buttons(); + + setNeedsSave(m_savedSettings.closeOnDoubleClickOnMenu != m_currentSettings.closeOnDoubleClickOnMenu + || m_savedSettings.borderSize != m_currentSettings.borderSize + || m_savedSettings.themeIndex != m_currentSettings.themeIndex + || m_savedSettings.buttonsOnLeft != m_currentSettings.buttonsOnLeft + || m_savedSettings.buttonsOnRight != m_currentSettings.buttonsOnRight); } -static QHash s_buttonNames; -static void initButtons() +QSortFilterProxyModel *KCMKWinDecoration::themesModel() const { - if (!s_buttonNames.isEmpty()) { - return; - } - s_buttonNames[KDecoration2::DecorationButtonType::Menu] = QChar('M'); - s_buttonNames[KDecoration2::DecorationButtonType::ApplicationMenu] = QChar('N'); - s_buttonNames[KDecoration2::DecorationButtonType::OnAllDesktops] = QChar('S'); - s_buttonNames[KDecoration2::DecorationButtonType::ContextHelp] = QChar('H'); - s_buttonNames[KDecoration2::DecorationButtonType::Minimize] = QChar('I'); - s_buttonNames[KDecoration2::DecorationButtonType::Maximize] = QChar('A'); - s_buttonNames[KDecoration2::DecorationButtonType::Close] = QChar('X'); - s_buttonNames[KDecoration2::DecorationButtonType::KeepAbove] = QChar('F'); - s_buttonNames[KDecoration2::DecorationButtonType::KeepBelow] = QChar('B'); - s_buttonNames[KDecoration2::DecorationButtonType::Shade] = QChar('L'); + return m_proxyThemesModel; } -static QString buttonsToString(const QVector &buttons) +QAbstractListModel *KCMKWinDecoration::leftButtonsModel() { - auto buttonToString = [](KDecoration2::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; + return m_leftButtonsModel; } -static -QVector< KDecoration2::DecorationButtonType > readDecorationButtons(const KConfigGroup &config, - const char *key, - const QVector< KDecoration2::DecorationButtonType > &defaultValue) +QAbstractListModel *KCMKWinDecoration::rightButtonsModel() { - initButtons(); - auto buttonsFromString = [](const QString &buttons) -> QVector { - QVector 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; - }; - return buttonsFromString(config.readEntry(key, buttonsToString(defaultValue))); + return m_rightButtonsModel; } -void ConfigurationModule::load() +QAbstractListModel *KCMKWinDecoration::availableButtonsModel() const { - s_loading = true; - const KConfigGroup config = KSharedConfig::openConfig("kwinrc")->group(s_pluginName); - const QString plugin = config.readEntry("library", s_defaultPlugin); - const QString theme = config.readEntry("theme", s_defaultTheme); - m_ui->closeWindowsDoubleClick->setChecked(config.readEntry("CloseOnDoubleClickOnMenu", false)); - const QVariant border = QVariant::fromValue(stringToSize(config.readEntry("BorderSize", s_borderSizeNormal))); - m_ui->borderSizesCombo->setCurrentIndex(m_ui->borderSizesCombo->findData(border)); - - int themeIndex = m_proxyModel->mapFromSource(m_model->findDecoration(plugin, theme)).row(); - m_quickView->rootContext()->setContextProperty("initialThemeIndex", themeIndex); - - // buttons - const auto &left = readDecorationButtons(config, "ButtonsOnLeft", QVector{ - KDecoration2::DecorationButtonType::Menu, - KDecoration2::DecorationButtonType::OnAllDesktops - }); - while (m_leftButtons->rowCount() > 0) { - m_leftButtons->remove(0); - } - for (auto it = left.begin(); it != left.end(); ++it) { - m_leftButtons->add(*it); - } - const auto &right = readDecorationButtons(config, "ButtonsOnRight", QVector{ - KDecoration2::DecorationButtonType::ContextHelp, - KDecoration2::DecorationButtonType::Minimize, - KDecoration2::DecorationButtonType::Maximize, - KDecoration2::DecorationButtonType::Close - }); - while (m_rightButtons->rowCount() > 0) { - m_rightButtons->remove(0); - } - for (auto it = right.begin(); it != right.end(); ++it) { - m_rightButtons->add(*it); - } + return m_availableButtonsModel; +} - KCModule::load(); - s_loading = false; +QStringList KCMKWinDecoration::borderSizesModel() const +{ + return Utils::getBorderSizeNames().values(); } -void ConfigurationModule::save() +int KCMKWinDecoration::borderSize() const { - KConfigGroup config = KSharedConfig::openConfig("kwinrc")->group(s_pluginName); - config.writeEntry("CloseOnDoubleClickOnMenu", m_ui->closeWindowsDoubleClick->isChecked()); - config.writeEntry("BorderSize", sizeToString(m_ui->borderSizesCombo->currentData().value())); - if (auto listView = m_quickView->rootObject()->findChild("listView")) { - const int currentIndex = listView->property("currentIndex").toInt(); - if (currentIndex != -1) { - const QModelIndex index = m_proxyModel->index(currentIndex, 0); - if (index.isValid()) { - config.writeEntry("library", index.data(Qt::UserRole + 4).toString()); - const QString theme = index.data(Qt::UserRole +5).toString(); - config.writeEntry("theme", theme); - } - } - } - config.writeEntry("ButtonsOnLeft", buttonsToString(m_leftButtons->buttons())); - config.writeEntry("ButtonsOnRight", buttonsToString(m_rightButtons->buttons())); - config.sync(); - KCModule::save(); - // Send signal to all kwin instances - QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"), - QStringLiteral("org.kde.KWin"), - QStringLiteral("reloadConfig")); - QDBusConnection::sessionBus().send(message); + return Utils::getBorderSizeNames().keys().indexOf(m_currentSettings.borderSize); } -void ConfigurationModule::defaults() +int KCMKWinDecoration::theme() const { - if (auto listView = m_quickView->rootObject()->findChild("listView")) { - const QModelIndex index = m_proxyModel->mapFromSource(m_model->findDecoration(s_defaultPlugin)); - listView->setProperty("currentIndex", index.isValid() ? index.row() : -1); - } - m_ui->borderSizesCombo->setCurrentIndex(m_ui->borderSizesCombo->findData(QVariant::fromValue(stringToSize(s_borderSizeNormal)))); - m_ui->closeWindowsDoubleClick->setChecked(false); - KCModule::defaults(); + return m_currentSettings.themeIndex; } -void ConfigurationModule::showKNS(const QString &config) +bool KCMKWinDecoration::closeOnDoubleClickOnMenu() const { - QPointer downloadDialog = new KNS3::DownloadDialog(config, this); - if (downloadDialog->exec() == QDialog::Accepted && !downloadDialog->changedEntries().isEmpty()) { - auto listView = m_quickView->rootObject()->findChild("listView"); - QString selectedPluginName; - QString selectedThemeName; - if (listView) { - const QModelIndex index = m_proxyModel->index(listView->property("currentIndex").toInt(), 0); - if (index.isValid()) { - selectedPluginName = index.data(Qt::UserRole + 4).toString(); - selectedThemeName = index.data(Qt::UserRole + 5).toString(); - } - } - m_model->init(); - if (!selectedPluginName.isEmpty()) { - const QModelIndex index = m_model->findDecoration(selectedPluginName, selectedThemeName); - const QModelIndex proxyIndex = m_proxyModel->mapFromSource(index); - if (listView) { - listView->setProperty("currentIndex", proxyIndex.isValid() ? proxyIndex.row() : -1); - } - } - } - delete downloadDialog; + return m_currentSettings.closeOnDoubleClickOnMenu; } -bool ConfigurationModule::eventFilter(QObject *watched, QEvent *e) +void KCMKWinDecoration::setBorderSize(int index) { - if (watched != m_ui) { - return false; - } - if (e->type() == QEvent::PaletteChange) { - updateColors(); - } - return false; + setBorderSize(Utils::getBorderSizeNames().keys().at(index)); } -void ConfigurationModule::updateColors() +void KCMKWinDecoration::setBorderSize(KDecoration2::BorderSize size) { - m_quickView->rootContext()->setContextProperty("backgroundColor", m_ui->palette().color(QPalette::Active, QPalette::Window)); - m_quickView->rootContext()->setContextProperty("highlightColor", m_ui->palette().color(QPalette::Active, QPalette::Shadow)); - m_quickView->rootContext()->setContextProperty("baseColor", m_ui->palette().color(QPalette::Active, QPalette::Base)); + if (m_currentSettings.borderSize == size) { + return; + } + m_currentSettings.borderSize = size; + emit borderSizeChanged(); + updateNeedsSave(); } +void KCMKWinDecoration::setTheme(int index) +{ + // The initial themeIndex is set to -2 to always initially apply a theme, any theme + if (m_currentSettings.themeIndex == index) { + return; + } + m_currentSettings.themeIndex = index; + emit themeChanged(); + updateNeedsSave(); } + +void KCMKWinDecoration::setCloseOnDoubleClickOnMenu(bool enable) +{ + if (m_currentSettings.closeOnDoubleClickOnMenu == enable) { + return; + } + m_currentSettings.closeOnDoubleClickOnMenu = enable; + emit closeOnDoubleClickOnMenuChanged(); + updateNeedsSave(); } #include "kcm.moc" diff --git a/kcmkwin/kwindecoration/kcm.h b/kcmkwin/kwindecoration/kcm.h index 99fa43114..4da9cec82 100644 --- a/kcmkwin/kwindecoration/kcm.h +++ b/kcmkwin/kwindecoration/kcm.h @@ -1,80 +1,116 @@ /* - * Copyright 2014 Martin Gräßlin + * Copyright (c) 2019 Valerio Pilo * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. */ -#ifndef KDECORATIONS_KCM_H -#define KDECORATIONS_KCM_H -#include -#include -#include +#pragma once +#include "utils.h" + +#include + + +class QAbstractItemModel; class QSortFilterProxyModel; -class QQuickView; +class QQuickItem; + +namespace KNS3 +{ +class DownloadDialog; +} namespace KDecoration2 { +enum class BorderSize; + namespace Preview { -class PreviewBridge; class ButtonsModel; } namespace Configuration { class DecorationsModel; +} +} -class ConfigurationForm : public QWidget, public Ui::KCMForm -{ -public: - explicit ConfigurationForm(QWidget* parent); -}; - -class ConfigurationModule : public KCModule +class KCMKWinDecoration : public KQuickAddons::ConfigModule { Q_OBJECT + Q_PROPERTY(QSortFilterProxyModel *themesModel READ themesModel CONSTANT) + Q_PROPERTY(QStringList borderSizesModel READ borderSizesModel CONSTANT) + Q_PROPERTY(int borderSize READ borderSize WRITE setBorderSize NOTIFY borderSizeChanged) + 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) + Q_PROPERTY(bool closeOnDoubleClickOnMenu READ closeOnDoubleClickOnMenu WRITE setCloseOnDoubleClickOnMenu NOTIFY closeOnDoubleClickOnMenuChanged) + public: - explicit ConfigurationModule(QWidget *parent = nullptr, const QVariantList &args = QVariantList()); - virtual ~ConfigurationModule(); + KCMKWinDecoration(QObject *parent, const QVariantList &arguments); + + QSortFilterProxyModel *themesModel() const; + QAbstractListModel *leftButtonsModel(); + QAbstractListModel *rightButtonsModel(); + QAbstractListModel *availableButtonsModel() const; + QStringList borderSizesModel() const; + int borderSize() const; + int theme() const; + bool closeOnDoubleClickOnMenu() const; - bool eventFilter(QObject *watched, QEvent *e) override; + void setBorderSize(int index); + void setBorderSize(KDecoration2::BorderSize size); + void setTheme(int index); + void setCloseOnDoubleClickOnMenu(bool enable); + + Q_INVOKABLE void getNewStuff(QQuickItem *context); + +Q_SIGNALS: + void themeChanged(); + void buttonsChanged(); + void borderSizeChanged(); + void closeOnDoubleClickOnMenuChanged(); public Q_SLOTS: - void defaults() override; void load() override; void save() override; + void defaults() override; -protected: - void showEvent(QShowEvent *ev) override; +private Q_SLOTS: + void updateNeedsSave(); + void reloadKWinSettings(); private: - void showKNS(const QString &config); - void updateColors(); - DecorationsModel *m_model; - QSortFilterProxyModel *m_proxyModel; - ConfigurationForm *m_ui; - QQuickView *m_quickView; - Preview::ButtonsModel *m_leftButtons; - Preview::ButtonsModel *m_rightButtons; - Preview::ButtonsModel *m_availableButtons; -}; + KDecoration2::Configuration::DecorationsModel *m_themesModel; + QSortFilterProxyModel *m_proxyThemesModel; -} + KDecoration2::Preview::ButtonsModel *m_leftButtonsModel; + KDecoration2::Preview::ButtonsModel *m_rightButtonsModel; + KDecoration2::Preview::ButtonsModel *m_availableButtonsModel; -} + QPointer m_newStuffDialog; + + struct Settings + { + KDecoration2::BorderSize borderSize; + int themeIndex; + bool closeOnDoubleClickOnMenu; + DecorationButtonsList buttonsOnLeft; + DecorationButtonsList buttonsOnRight; + }; -#endif + Settings m_savedSettings; + Settings m_currentSettings; +}; diff --git a/kcmkwin/kwindecoration/kcm.ui b/kcmkwin/kwindecoration/kcm.ui deleted file mode 100644 index 57abceeb3..000000000 --- a/kcmkwin/kwindecoration/kcm.ui +++ /dev/null @@ -1,182 +0,0 @@ - - - KCMForm - - - - 0 - 0 - 386 - 272 - - - - - - - 0 - - - - Theme - - - - - - - - Search... - - - true - - - - - - - - - - - - Close windows by double clicking &the menu button - - - - - - - - - - - 0 - 0 - - - - - 0 - 100 - - - - - - - - - - Border si&ze: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - borderSizesCombo - - - - - - - - No Borders - - - - - No Side Borders - - - - - Tiny - - - - - Normal - - - - - Large - - - - - Very Large - - - - - Huge - - - - - Very Huge - - - - - Oversized - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - Get New Window Decorations... - - - - - - - - - - Buttons - - - - - - - - - KComboBox - QComboBox -
kcombobox.h
-
- - KMessageWidget - QFrame -
kmessagewidget.h
- 1 -
-
- - -
diff --git a/kcmkwin/kwindecoration/kwindecoration.desktop b/kcmkwin/kwindecoration/kwindecoration.desktop index 162f05596..7789b6bce 100644 --- a/kcmkwin/kwindecoration/kwindecoration.desktop +++ b/kcmkwin/kwindecoration/kwindecoration.desktop @@ -1,165 +1,119 @@ [Desktop Entry] -Exec=kcmshell5 kwindecoration Icon=preferences-system-windows-action +Exec=kcmshell5 kwindecoration + +Categories=Qt;KDE;X-KDE-settings-looknfeel; Type=Service X-KDE-ServiceTypes=KCModule -X-DocPath=kcontrol/kwindecoration/index.html - X-KDE-Library=kcm_kwindecoration X-KDE-ParentApp=kcontrol - X-KDE-System-Settings-Parent-Category=applicationstyle X-KDE-Weight=40 +X-DocPath=kcontrol/kwindecoration/index.html Name=Window Decorations Name[ar]=زخارف النوافذ 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]=Decoración de 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]=Lango 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]=視窗裝飾 -Comment=Look and Feel of Window Titles -Comment[bs]=Izgled i osjećaj naslova prozora -Comment[ca]=Aspecte i comportament dels títols de les finestres -Comment[ca@valencia]=Aspecte i comportament dels títols de les finestres -Comment[cs]=Vzhled a dekorace titulků oken -Comment[da]=Udseendet af vinduestitler -Comment[de]=Erscheinungsbild von Fenstertiteln -Comment[el]=Διαμόρφωση της εμφάνισης και αίσθησης του τίτλου των παραθύρων -Comment[en_GB]=Look and Feel of Window Titles -Comment[es]=Aspecto visual de los títulos de las ventanas -Comment[et]=Akna tiitliribade välimus ja tunnetus -Comment[eu]=Leiho-tituluen itxura eta izaera -Comment[fi]=Ikkunoiden kehysten ulkoasu -Comment[fr]=Apparence des titres de fenêtre -Comment[gl]=Aparencia e o comportamento dos títulos das xanelas -Comment[he]=הגדרת המראה והתחושה של מסגרות החלונות -Comment[hu]=Az ablakok címsorának megjelenése -Comment[ia]=Semblantia de titulos de fenestra -Comment[id]=Look and Feel pada Judul Window -Comment[it]=Aspetto dei titoli delle finestre -Comment[ja]=ウィンドウタイトルの外観を設定 -Comment[ko]=창 제목 표시줄의 모습과 느낌 설정 -Comment[lt]=Langų antraščių išvaizda ir elgsena -Comment[nb]=Utseende og virkemåte for vindustitlene -Comment[nds]=Dat Utsehn vun de Finstertiteln instellen -Comment[nl]=Uiterlijk en gedrag van venstertitels -Comment[nn]=Utsjånad og åtferd for vindaugstitlar -Comment[pa]=ਵਿੰਡੋ ਟਾਇਟਲਾਂ ਦੇ ਰੰਗ-ਰੂਪ ਦੀ ਸੰਰਚਨਾ -Comment[pl]=Tytuły okien - wrażenia wzrokowe i dotykowe -Comment[pt]=Aparência e Comportamento dos Títulos das Janelas -Comment[pt_BR]=Aparência do título das janelas -Comment[ru]=Настройка внешнего вида заголовков окон -Comment[sk]=Nastavenie vzhľadu titulkov okien -Comment[sl]=Videz in občutek naslovnih vrstic okna -Comment[sr]=Изглед и осећај за наслове прозора -Comment[sr@ijekavian]=Изглед и осјећај за наслове прозора -Comment[sr@ijekavianlatin]=Izgled i osjećaj za naslove prozora -Comment[sr@latin]=Izgled i osećaj za naslove prozora -Comment[sv]=Namnlisternas utseende och känsla -Comment[tr]=Pencere Başlıklarının Görünüm ve Davranışlarını Yapılandır -Comment[uk]=Вигляд і поведінка смужок заголовків вікон -Comment[x-test]=xxLook and Feel of Window Titlesxx -Comment[zh_CN]=窗口标题的观感 -Comment[zh_TW]=視窗標題列的外觀與感覺 +Comment=Configure window titlebars and borders X-KDE-Keywords=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration X-KDE-Keywords[bs]=kwin,prozor,upravitelj,granica,stil,tema,izgled,osjećati,izgled,dugme,držati,ivica,kwm,dekoracija X-KDE-Keywords[ca]=kwin,finestra,gestor,vora,estil,tema,aspecte,comportament,disposició,botó,gestió,vora,kwm,decoració X-KDE-Keywords[ca@valencia]=kwin,finestra,gestor,vora,estil,tema,aspecte,comportament,disposició,botó,gestió,vora,kwm,decoració X-KDE-Keywords[cs]=kwin,okna,správce,okraj,styl,motiv,vzhled,pocit,rozvržení,tlačítko,madlo,okraj,kwm,dekorace X-KDE-Keywords[da]=kwin,vindueshåndtering,window,manager,kant,stil,tema,udseende,layout,knap,håndtag,kant,kwm,dekoration X-KDE-Keywords[de]=KWin,Kwm,Fenster,Manager,Rahmen,Design,Stile,Themes,Optik,Erscheinungsbild,Layout,Knöpfe,Ränder,Dekorationen X-KDE-Keywords[el]=kwin,παράθυρο,διαχειριστής,περίγραμμα,στιλ,θέμα,εμφάνιση,αίσθηση,διάταξη,κουμπί,χειρισμός,άκρη,kwm,διακόσμηση X-KDE-Keywords[en_GB]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration X-KDE-Keywords[es]=kwin,ventana,gestor,borde,estilo,tema,aspecto,sensación,disposición,botón,asa,borde,kwm,decoración X-KDE-Keywords[et]=kwin,aken,haldur,piire,stiil,teema,välimus,paigutus,nupp,pide,serv,kwm,dekoratsioon X-KDE-Keywords[eu]=kwin,leiho,kudeatzaile,ertz,estilo,gai, itxura,izaera,diseinu,botoi,helduleku,kwm,dekorazio,apaindura,apainketa X-KDE-Keywords[fi]=kwin,ikkuna,hallinta,ikkunointiohjelma,kehys,reunus,tyyli,teema,ulkoasu,toiminta,asettelu,painike,kahva,kulma,reuna,kwm,koriste X-KDE-Keywords[fr]=kwin, fenêtre, gestionnaire, composition, bordure, style, thème, apparence, comportement, disposition, bouton, prise en main, bord, kwm, décoration X-KDE-Keywords[ga]=kwin,fuinneog,bainisteoir,imlíne,stíl,téama,cuma,brath,leagan amach,cnaipe,hanla,ciumhais,kwm,maisiúchán X-KDE-Keywords[gl]=kwin,xanela,xestor,estilo,tema,aparencia,comportamento,aspecto,disposición, botón,asa,bordo,kwm,decoración X-KDE-Keywords[hu]=kwin,ablak,kezelő,szegély,stílus,téma,kinézet,megjelenés,elrendezés,gomb,kezel,szél,kwm,dekoráció X-KDE-Keywords[ia]=kwin,fenestra,gerente,margine,stilo,thema,aspecto,sentir,disposition,button,maneator,bordo,kwm,decoration X-KDE-Keywords[id]=kwin,window,pengelola,batas,gaya,tema,tampilan,rasa,tata letak,tombol,pegangan,tepi,kwm,dekorasi X-KDE-Keywords[it]=kwin,gestore,finestre,bordo,stile,tema,aspetto,disposizione,pulsante,gestore,kwm,decorazione X-KDE-Keywords[kk]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration X-KDE-Keywords[km]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration X-KDE-Keywords[ko]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,창,관리자,테두리,스타일,테마,단추,핸들,경계 X-KDE-Keywords[nb]=kwin,vindu,behandler,ramme,stil,tema,lås,utforming,knapp,håndtak,kant,kwm X-KDE-Keywords[nds]=KWin,Finster,Pleger,Rahmen,Stil,Muster,Utsehn,Bedenen,Knoop,Greep,Kant,kwm,Dekoratschoon X-KDE-Keywords[nl]=kwin,venster,beheerder,grens,stijl,thema,look,feel,indeling,knop,handel,rand,kwm,decoratie X-KDE-Keywords[nn]=kwin,vindauge,handsamar,ramme,kantlinje,stil,tema,lås,utforming,knapp,handtak,kant,kwm,dekorasjon,pynt X-KDE-Keywords[pl]=kwin,okno,menadżer,obramowanie,styl,motyw,wygląd,odczucie,układ,przycisk, uchwyt,krawędź,kwm,dekoracja X-KDE-Keywords[pt]=kwin,gestor,janela,contorno,estilo,tema,aparência,comportamento,disposição,botão,pega,extremo,kwm,decoração X-KDE-Keywords[pt_BR]=kwin,gerenciador,janela,borda,estilo,tema,aparência,comportamento,layout,botão,canto,extremo,kwm,decoração X-KDE-Keywords[ru]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,окно,диспетчер,граница,стиль,тема,внешний вид,оформление,разметка,шаблон,кнопка,управление,край X-KDE-Keywords[sk]=kwin,okno,správca,rám,štýl,téma,vzhľad,cítenie,rozloženie,tlačidlo,spracovanie,okraj,kwm,dekorácia X-KDE-Keywords[sl]=kwin,okna,okenski upravljalnik,upravljalnik oken,rob,obroba,slog,tema,videz,obnašanje,občutek,razpored,gumbi,ročica,okraski,kwm X-KDE-Keywords[sr]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,К‑вин,прозор,менаџер,ивица,стила,тема,изглед,осећај,распоред,дугме,ручка,КВМ,декорација X-KDE-Keywords[sr@ijekavian]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,К‑вин,прозор,менаџер,ивица,стила,тема,изглед,осећај,распоред,дугме,ручка,КВМ,декорација X-KDE-Keywords[sr@ijekavianlatin]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,KWin,prozor,menadžer,ivica,stila,tema,izgled,osećaj,raspored,dugme,ručka,KWM,dekoracija X-KDE-Keywords[sr@latin]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,KWin,prozor,menadžer,ivica,stila,tema,izgled,osećaj,raspored,dugme,ručka,KWM,dekoracija X-KDE-Keywords[sv]=kwin,fönster,hantering,kant,stil,tema,utseende,känsla,layout,knapp,grepp,kant,kwm,dekoration X-KDE-Keywords[tr]=kwin,pencere,yönetici,kenarlık,biçim,tema,görünüm,şekil,düzen,düğme,kullanım,kenar,kwm,dekorasyon X-KDE-Keywords[uk]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,вікно,вікна,керування,менеджер,рамка,межа,стиль,тема,вигляд,поведінка,компонування,кнопка,елемент,край,декорації,обрамлення X-KDE-Keywords[x-test]=xxkwinxx,xxwindowxx,xxmanagerxx,xxborderxx,xxstylexx,xxthemexx,xxlookxx,xxfeelxx,xxlayoutxx,xxbuttonxx,xxhandlexx,xxedgexx,xxkwmxx,xxdecorationxx X-KDE-Keywords[zh_CN]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration,窗口,管理,边框,样式,主题,外怪,布局,按钮,边界,装饰 X-KDE-Keywords[zh_TW]=kwin,window,manager,border,style,theme,look,feel,layout,button,handle,edge,kwm,decoration - -Categories=Qt;KDE;X-KDE-settings-looknfeel; - diff --git a/kcmkwin/kwindecoration/qml/ButtonGroup.qml b/kcmkwin/kwindecoration/package/contents/ui/ButtonGroup.qml similarity index 88% rename from kcmkwin/kwindecoration/qml/ButtonGroup.qml rename to kcmkwin/kwindecoration/package/contents/ui/ButtonGroup.qml index 37da84da7..fcff634e3 100644 --- a/kcmkwin/kwindecoration/qml/ButtonGroup.qml +++ b/kcmkwin/kwindecoration/package/contents/ui/ButtonGroup.qml @@ -1,75 +1,76 @@ /* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -import QtQuick 2.1 -import QtQuick.Controls 1.2 -import QtQuick.Layouts 1.1 +import QtQuick 2.7 import org.kde.kwin.private.kdecoration 1.0 as KDecoration -import org.kde.plasma.core 2.0 as PlasmaCore; ListView { id: view property string key property bool dragging: false + property int iconSize: units.iconSizes.small orientation: ListView.Horizontal interactive: false spacing: units.smallSpacing - implicitHeight: units.iconSizes.small - implicitWidth: count * (units.iconSizes.small + units.smallSpacing) - Math.min(1, count) * units.smallSpacing + implicitHeight: iconSize + implicitWidth: count * (iconSize + units.smallSpacing) - Math.min(1, count) * units.smallSpacing delegate: Item { - width: units.iconSizes.small - height: units.iconSizes.small + width: iconSize + height: 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: iconSize + height: iconSize anchors.fill: Drag.active ? undefined : parent Drag.keys: [ "decoButtonRemove", view.key ] Drag.active: dragArea.drag.active Drag.onActiveChanged: view.dragging = Drag.active + color: palette.windowText } MouseArea { id: dragArea cursorShape: Qt.SizeAllCursor 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: units.longDuration/2 } NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: units.longDuration/2 } } move: Transition { NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: units.longDuration/2 } NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: units.longDuration/2 } } displaced: Transition { NumberAnimation { properties: "x,y"; duration: units.longDuration; easing.type: Easing.OutBounce } } } diff --git a/kcmkwin/kwindecoration/qml/Buttons.qml b/kcmkwin/kwindecoration/package/contents/ui/Buttons.qml similarity index 59% rename from kcmkwin/kwindecoration/qml/Buttons.qml rename to kcmkwin/kwindecoration/package/contents/ui/Buttons.qml index 5a09a79c6..f6f69447f 100644 --- a/kcmkwin/kwindecoration/qml/Buttons.qml +++ b/kcmkwin/kwindecoration/package/contents/ui/Buttons.qml @@ -1,231 +1,255 @@ /* * Copyright 2014 Martin Gräßlin + * Copyright (c) 2019 Valerio Pilo * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Controls 2.0 as QQC2 -import QtQuick.Layouts 1.1 +import QtQuick 2.7 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.4 as Controls +import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.kwin.private.kdecoration 1.0 as KDecoration -import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons; -Item { - objectName: "buttonLayout" - Layout.preferredHeight: layout.height +ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + property int buttonIconSize: units.iconSizes.medium + property int titleBarSpacing: units.iconSizes.smallMedium + KDecoration.Bridge { id: bridgeItem plugin: "org.kde.breeze" } KDecoration.Settings { id: settingsItem bridge: bridgeItem.bridge } + Rectangle { - anchors.fill: parent - border.width: Math.ceil(units.gridUnit / 16.0) - border.color: highlightColor - color: baseColor + Layout.fillWidth: true + color: palette.base + radius: units.smallSpacing + height: fakeWindow.height + Layout.margins: units.smallSpacing + ColumnLayout { - id: layout + id: fakeWindow width: parent.width - height: titlebarRect.height + availableGrid.height + dragHint.height + 5*layout.spacing + Rectangle { - id: titlebarRect - height: buttonPreviewRow.height + units.smallSpacing - border.width: Math.ceil(units.gridUnit / 16.0) - border.color: highlightColor - color: backgroundColor + id: titleBar Layout.fillWidth: true - Layout.topMargin: -border.width // prevent a double top border + height: buttonPreviewRow.height + 2 * titleBarSpacing + radius: units.smallSpacing + gradient: Gradient { + GradientStop { position: 0.0; color: palette.midlight } + GradientStop { position: 1.0; color: palette.window } + } + RowLayout { id: buttonPreviewRow - anchors.top: parent.top; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.margins: units.smallSpacing / 2 - height: Math.max(units.iconSizes.small, titlebar.implicitHeight) + units.smallSpacing/2 + anchors { + margins: titleBarSpacing + left: parent.left + right: parent.right + top: parent.top + } + ButtonGroup { id: leftButtonsView - height: buttonPreviewRow.height - model: leftButtons + iconSize: buttonIconSize + model: kcm.leftButtonsModel key: "decoButtonLeft" } - QQC2.Label { - id: titlebar + Controls.Label { + id: titleBarLabel Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter - font: titleFont + font.bold: true text: i18n("Titlebar") } - ButtonGroup { id: rightButtonsView - height: buttonPreviewRow.height - model: rightButtons + iconSize: buttonIconSize + model: kcm.rightButtonsModel key: "decoButtonRight" } } DropArea { + id: titleBarDropArea anchors { - fill: titlebarRect - leftMargin: -units.iconSizes.small - topMargin: -units.iconSizes.small - rightMargin: +units.iconSizes.small - bottomMargin: +units.iconSizes.small + fill: parent + margins: -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)) { view = leftButtonsView; } else { view = rightButtonsView; } if (!view) { return; } var point = mapToItem(view, drag.x, drag.y); - var index = view.indexAt(point.x, point.y); - if (index == -1 && (view.x + view.width <= drag.x)) { - index = view.count - 1; + 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: availableGrid + id: availableButtonsGrid Layout.fillWidth: true - model: availableButtons + Layout.minimumHeight: availableButtonsGrid.cellHeight * 2 + Layout.margins: units.largeSpacing + model: kcm.availableButtonsModel interactive: false - height: Math.ceil(cellHeight * 3) delegate: Item { id: availableDelegate - Layout.margins: units.gridUnit - width: availableGrid.cellWidth - height: availableGrid.cellHeight + Layout.margins: units.largeSpacing + width: availableButtonsGrid.cellWidth + height: availableButtonsGrid.cellHeight opacity: (leftButtonsView.dragging || rightButtonsView.dragging) ? 0.25 : 1.0 - KDecoration.Button { - id: availableButton - anchors.centerIn: Drag.active ? undefined : parent - bridge: bridgeItem.bridge - settings: settingsItem - type: model["button"] - width: units.iconSizes.small - height: units.iconSizes.small - Drag.keys: [ "decoButtonAdd" ] - Drag.active: dragArea.drag.active + Rectangle { + id: availableButtonFrame + anchors.horizontalCenter: parent.horizontalCenter + color: palette.window + radius: units.smallSpacing + width: buttonIconSize + units.largeSpacing + height: buttonIconSize + units.largeSpacing + + KDecoration.Button { + id: availableButton + anchors.centerIn: Drag.active ? undefined : availableButtonFrame + bridge: bridgeItem.bridge + settings: settingsItem + type: model["button"] + width: buttonIconSize + height: buttonIconSize + Drag.keys: [ "decoButtonAdd" ] + Drag.active: dragArea.drag.active + color: palette.windowText + } + MouseArea { + id: dragArea + anchors.fill: availableButton + drag.target: availableButton + cursorShape: Qt.SizeAllCursor + onReleased: { + if (availableButton.Drag.target) { + availableButton.Drag.drop(); + } else { + availableButton.Drag.cancel(); + } + } + } } - QQC2.Label { + Controls.Label { id: iconLabel text: model["display"] horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignTop - anchors.bottom: parent.bottom + anchors.top: availableButtonFrame.bottom + anchors.topMargin: units.smallSpacing anchors.left: parent.left anchors.right: parent.right elide: Text.ElideRight wrapMode: Text.Wrap - height: 2 * dragHint.implicitHeight + lineHeight - } - MouseArea { - id: dragArea - anchors.fill: availableButton - drag.target: availableButton - cursorShape: Qt.SizeAllCursor - onReleased: { - if (availableButton.Drag.target) { - availableButton.Drag.drop(); - } else { - availableButton.Drag.cancel(); - } - } + height: 2 * implicitHeight + lineHeight } } DropArea { anchors.fill: parent keys: [ "decoButtonRemove" ] onEntered: { drag.accept(); } onDropped: { drag.source.buttonsModel.remove(drag.source.itemIndex); } ColumnLayout { anchors.centerIn: parent opacity: (leftButtonsView.dragging || rightButtonsView.dragging) ? 1.0 : 0.0 - QQC2.Label { + Controls.Label { text: i18n("Drop here to remove button") font.weight: Font.Bold Layout.bottomMargin: units.smallSpacing } - KQuickControlsAddons.QIconItem { + PlasmaCore.IconItem { id: icon width: units.iconSizes.smallMedium height: units.iconSizes.smallMedium - icon: "emblem-remove" Layout.alignment: Qt.AlignHCenter + source: "emblem-remove" } Item { Layout.fillHeight: true } } } } Text { id: dragHint - opacity: (leftButtonsView.dragging || rightButtonsView.dragging || availableGrid.dragging) ? 0.0 : 0.50 + color: palette.windowText + opacity: (leftButtonsView.dragging || rightButtonsView.dragging || availableButtonsGrid.dragging) ? 0.0 : 1.0 Layout.fillWidth: true - Layout.bottomMargin: units.smallSpacing + Layout.topMargin: titleBarSpacing + Layout.bottomMargin: titleBarSpacing horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignTop wrapMode: Text.NoWrap text: i18n("Drag buttons between here and the titlebar") } } } } diff --git a/kcmkwin/kwindecoration/package/contents/ui/Themes.qml b/kcmkwin/kwindecoration/package/contents/ui/Themes.qml new file mode 100644 index 000000000..c2c2ba43c --- /dev/null +++ b/kcmkwin/kwindecoration/package/contents/ui/Themes.qml @@ -0,0 +1,126 @@ +/* + * Copyright 2014 Martin Gräßlin + * Copyright (c) 2019 Valerio Pilo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import QtQuick 2.7 +import org.kde.kcm 1.1 as KCM +import org.kde.kirigami 2.2 as Kirigami +import org.kde.kwin.private.kdecoration 1.0 as KDecoration + +KCM.GridView { + property int cellSpacing: 2 * units.largeSpacing + property int previewWidth: 18 * units.gridUnit + property int previewHeight: previewWidth / 1.7 + + function updateDecoration(item, marginTopLeft, marginBottomRight) { + var mainMargin = units.largeSpacing + var 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.onCurrentIndexChanged: kcm.theme = view.currentIndex + view.onContentHeightChanged: view.positionViewAtIndex(view.currentIndex, GridView.Visible) + + view.cellWidth: previewWidth + cellSpacing + view.cellHeight: previewHeight + cellSpacing + + view.delegate: KCM.GridDelegate { + text: model.display + + thumbnailAvailable: true + thumbnail: Rectangle { + anchors.fill: parent + width: previewWidth + height: previewHeight + color: palette.base + clip: true + + // Workaround: the thumbnail size can't be otherwise changed + Component.onCompleted: { + parent.parent.width = previewWidth + parent.parent.height = previewHeight + } + + KDecoration.Bridge { + id: bridgeItem + plugin: model.plugin + theme: model.theme + } + KDecoration.Settings { + id: settingsItem + bridge: bridgeItem.bridge + } + 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: view.currentIndex = index + } + Connections { + target: kcm + onBorderSizeChanged: settingsItem.borderSizesIndex = kcm.borderSize + } + } + actions: [ + Kirigami.Action { + iconName: "edit-entry" + tooltip: i18n("Edit %1 Theme", model.display) + enabled: model.configureable + onTriggered: { + view.currentIndex = index + bridgeItem.bridge.configure() + } + } + ] + + onClicked: view.currentIndex = index + } + Connections { + target: kcm + onThemeChanged: view.currentIndex = kcm.theme + } +} + diff --git a/kcmkwin/kwindecoration/package/contents/ui/main.qml b/kcmkwin/kwindecoration/package/contents/ui/main.qml new file mode 100644 index 000000000..cfdf30bd2 --- /dev/null +++ b/kcmkwin/kwindecoration/package/contents/ui/main.qml @@ -0,0 +1,127 @@ +/* + Copyright (c) 2019 Valerio Pilo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +import QtQuick 2.7 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.4 as Controls +import org.kde.kcm 1.1 as KCM +import org.kde.kconfig 1.0 // for KAuthorized +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.Page { + KCM.ConfigModule.quickHelp: i18n("This module lets you configure the window decorations.") + KCM.ConfigModule.buttons: KCM.ConfigModule.Help | KCM.ConfigModule.Default | KCM.ConfigModule.Apply + title: kcm.name + + SystemPalette { + id: palette + colorGroup: SystemPalette.Active + } + + // To match SimpleKCM's borders of Page + headerParent/footerParent (also specified in raw pixels) + leftPadding: Kirigami.Settings.isMobile ? 0 : 8 + topPadding: leftPadding + rightPadding: leftPadding + bottomPadding: leftPadding + + ColumnLayout { + id: tabLayout + anchors.fill: parent + spacing: 0 + Controls.TabBar { + id: tabBar + Layout.fillWidth: true + + Controls.TabButton { + text: i18nc("tab label", "Theme") + } + + Controls.TabButton { + text: i18nc("tab label", "Titlebar Buttons") + } + } + Controls.Frame { + Layout.fillWidth: true + Layout.fillHeight: true + + StackLayout { + anchors.fill: parent + + currentIndex: tabBar.currentIndex + + ColumnLayout { + Themes { + Layout.fillWidth: true + Layout.fillHeight: true + } + + RowLayout { + Controls.Label { + Layout.alignment: Qt.AlignRight + text: i18nc("combobox label", "Window border size:") + } + + Controls.ComboBox { + id: borderSizeComboBox + model: kcm.borderSizesModel + currentIndex: kcm.borderSize + onActivated: { + kcm.borderSize = currentIndex + } + } + Item { + Layout.fillWidth: true + } + Controls.Button { + text: i18nc("button text", "Get New Window Decorations...") + icon.name: "get-hot-new-stuff" + onClicked: kcm.getNewStuff(this) + visible: KAuthorized.authorize("ghns") + } + } + } + + ColumnLayout { + Buttons { + Layout.fillWidth: true + Layout.fillHeight: true + } + + Controls.CheckBox { + id: closeOnDoubleClickOnMenuCheckBox + text: i18nc("checkbox label", "Close windows by double clicking the menu button") + checked: kcm.closeOnDoubleClickOnMenu + onToggled: { + kcm.closeOnDoubleClickOnMenu = checked + infoLabel.visible = checked + } + } + + Kirigami.InlineMessage { + Layout.fillWidth: true + id: infoLabel + type: Kirigami.MessageType.Information + text: i18nc("popup tip", "Close by double clicking: Keep the window's Menu button pressed until it appears.") + showCloseButton: true + visible: false + } + } + } + } + } +} diff --git a/kcmkwin/kwindecoration/package/metadata.desktop b/kcmkwin/kwindecoration/package/metadata.desktop new file mode 100644 index 000000000..3fe1bea4b --- /dev/null +++ b/kcmkwin/kwindecoration/package/metadata.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Icon=preferences-system-windows-action +Type=Service +Keywords= +X-KDE-ParentApp= +X-KDE-System-Settings-Parent-Category=applicationstyle +X-KDE-PluginInfo-Author=Valerio Pilo +X-KDE-PluginInfo-Email=vpilo@coldshock.net +X-KDE-PluginInfo-License=GPL-2.0+ +X-KDE-PluginInfo-Name=kcm_kwindecoration +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website=https://www.kde.org/plasma-desktop +X-KDE-ServiceTypes=Plasma/Generic +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml + +Name=Window Decorations +Name[ar]=زخارف النوافذ +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]=Decoración de 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]=Lango 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]=視窗裝飾 +Comment=Configure window titlebars and borders diff --git a/kcmkwin/kwindecoration/qml/Previews.qml b/kcmkwin/kwindecoration/qml/Previews.qml deleted file mode 100644 index 9a04f8749..000000000 --- a/kcmkwin/kwindecoration/qml/Previews.qml +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2014 Martin Gräßlin - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -import QtQuick 2.1 -import QtQuick.Controls 1.2 -import QtQuick.Layouts 1.1 -import org.kde.kwin.private.kdecoration 1.0 as KDecoration - -ScrollView { - objectName: "themeList" - frameVisible: true - GridView { - id: gridView - objectName: "listView" - signal userChangedSelection() - model: decorationsModel - cellWidth: 20 * units.gridUnit - cellHeight: cellWidth / 1.6 - highlightFollowsCurrentItem: true - onContentHeightChanged: { - if (gridView.currentIndex == -1 && initialThemeIndex != -1) { - gridView.currentIndex = initialThemeIndex - } - gridView.positionViewAtIndex(gridView.currentIndex, GridView.Visible) - } - Rectangle { - z: -1 - anchors.fill: parent - color: baseColor - } - highlight: Rectangle { - color: highlightColor - opacity: 0.6 - } - highlightMoveDuration: units.longDuration - boundsBehavior: Flickable.StopAtBounds - property int borderSizesIndex: 3 // 3 == Normal - delegate: Item { - width: gridView.cellWidth - height: gridView.cellHeight - KDecoration.Bridge { - id: bridgeItem - plugin: model["plugin"] - theme: model["theme"] - } - KDecoration.Settings { - id: settingsItem - bridge: bridgeItem.bridge - borderSizesIndex: gridView.borderSizesIndex - } - Component.onCompleted: { - if (gridView.currentIndex == -1 && initialThemeIndex != -1) { - gridView.currentIndex = initialThemeIndex - } - } - MouseArea { - hoverEnabled: false - anchors.fill: parent - onClicked: { - gridView.currentIndex = index - gridView.userChangedSelection() - } - } - ColumnLayout { - id: decorationPreviews - property string themeName: model["display"] - anchors.fill: parent - Item { - KDecoration.Decoration { - id: inactivePreview - bridge: bridgeItem.bridge - settings: settingsItem - anchors.fill: parent - Component.onCompleted: { - client.caption = decorationPreviews.themeName - client.active = false; - anchors.leftMargin = Qt.binding(function() { return 40 - (inactivePreview.shadow ? inactivePreview.shadow.paddingLeft : 0);}); - anchors.rightMargin = Qt.binding(function() { return 10 - (inactivePreview.shadow ? inactivePreview.shadow.paddingRight : 0);}); - anchors.topMargin = Qt.binding(function() { return 10 - (inactivePreview.shadow ? inactivePreview.shadow.paddingTop : 0);}); - anchors.bottomMargin = Qt.binding(function() { return 40 - (inactivePreview.shadow ? inactivePreview.shadow.paddingBottom : 0);}); - } - } - KDecoration.Decoration { - id: activePreview - bridge: bridgeItem.bridge - settings: settingsItem - anchors.fill: parent - Component.onCompleted: { - client.caption = decorationPreviews.themeName - client.active = true; - anchors.leftMargin = Qt.binding(function() { return 10 - (activePreview.shadow ? activePreview.shadow.paddingLeft : 0);}); - anchors.rightMargin = Qt.binding(function() { return 40 - (activePreview.shadow ? activePreview.shadow.paddingRight : 0);}); - anchors.topMargin = Qt.binding(function() { return 40 - (activePreview.shadow ? activePreview.shadow.paddingTop : 0);}); - anchors.bottomMargin = Qt.binding(function() { return 10 - (activePreview.shadow ? activePreview.shadow.paddingBottom : 0);}); - } - } - MouseArea { - hoverEnabled: false - anchors.fill: parent - onClicked: { - gridView.currentIndex = index - gridView.userChangedSelection() - } - } - Layout.fillWidth: true - Layout.fillHeight: true - /* Create an invisible rectangle that's the same size as the inner content rect - of the foreground window preview so that we can center the button within it. - We have to center rather than using anchors because the button width varies - with different localizations */ - Item { - anchors { - left: parent.left - leftMargin: 10 - right: parent.right - rightMargin: 40 - top: parent.top - topMargin: 68 - bottom: parent.bottom - bottomMargin: 10 - } - Button { - id: configureButton - anchors { - horizontalCenter: parent.horizontalCenter - verticalCenter: parent.verticalCenter - } - enabled: model["configureable"] - iconName: "configure" - text: i18n("Configure %1...", decorationPreviews.themeName) - onClicked: { - gridView.currentIndex = index - gridView.userChangedSelection() - bridgeItem.bridge.configure() - } - } - } - } - } - } - } - Layout.preferredHeight: 20 * units.gridUnit -} - diff --git a/kcmkwin/kwindecoration/qml/main.qml b/kcmkwin/kwindecoration/qml/main.qml deleted file mode 100644 index 75a754ea4..000000000 --- a/kcmkwin/kwindecoration/qml/main.qml +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 Martin Gräßlin - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -import QtQuick 2.1 -import QtQuick.Controls 1.2 -import QtQuick.Layouts 1.1 - -Rectangle { - color: backgroundColor - ColumnLayout { - anchors.fill: parent - Previews { - Layout.fillWidth: true - Layout.fillHeight: true - } - Buttons { - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - } - } -} diff --git a/kcmkwin/kwindecoration/utils.cpp b/kcmkwin/kwindecoration/utils.cpp new file mode 100644 index 000000000..b26b698bf --- /dev/null +++ b/kcmkwin/kwindecoration/utils.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2019 Valerio Pilo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "utils.h" + +#include +#include + +namespace +{ +const QMap s_borderSizes { + { QStringLiteral("None"), KDecoration2::BorderSize::None }, + { QStringLiteral("NoSides"), KDecoration2::BorderSize::NoSides }, + { QStringLiteral("Tiny"), KDecoration2::BorderSize::Tiny }, + { QStringLiteral("Normal"), KDecoration2::BorderSize::Normal }, + { QStringLiteral("Large"), KDecoration2::BorderSize::Large }, + { QStringLiteral("VeryLarge"), KDecoration2::BorderSize::VeryLarge }, + { QStringLiteral("Huge"), KDecoration2::BorderSize::Huge }, + { QStringLiteral("VeryHuge"), KDecoration2::BorderSize::VeryHuge }, + { QStringLiteral("Oversized"), KDecoration2::BorderSize::Oversized } +}; +const QMap s_borderSizeNames { + { KDecoration2::BorderSize::None, i18n("No Borders") }, + { KDecoration2::BorderSize::NoSides, i18n("No Side Borders") }, + { KDecoration2::BorderSize::Tiny, i18n("Tiny") }, + { KDecoration2::BorderSize::Normal, i18n("Normal") }, + { KDecoration2::BorderSize::Large, i18n("Large") }, + { KDecoration2::BorderSize::VeryLarge, i18n("Very Large") }, + { KDecoration2::BorderSize::Huge, i18n("Huge") }, + { KDecoration2::BorderSize::VeryHuge, i18n("Very Huge") }, + { KDecoration2::BorderSize::Oversized, i18n("Oversized") } +}; + +const QHash s_buttonNames { + {KDecoration2::DecorationButtonType::Menu, QChar('M') }, + {KDecoration2::DecorationButtonType::ApplicationMenu, QChar('N') }, + {KDecoration2::DecorationButtonType::OnAllDesktops, QChar('S') }, + {KDecoration2::DecorationButtonType::ContextHelp, QChar('H') }, + {KDecoration2::DecorationButtonType::Minimize, QChar('I') }, + {KDecoration2::DecorationButtonType::Maximize, QChar('A') }, + {KDecoration2::DecorationButtonType::Close, QChar('X') }, + {KDecoration2::DecorationButtonType::KeepAbove, QChar('F') }, + {KDecoration2::DecorationButtonType::KeepBelow, QChar('B') }, + {KDecoration2::DecorationButtonType::Shade, QChar('L') } +}; +} + + +namespace Utils +{ + +QString buttonsToString(const DecorationButtonsList &buttons) +{ + auto buttonToString = [](KDecoration2::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 readDecorationButtons(const KConfigGroup &config, const QString &key, const DecorationButtonsList &defaultValue) +{ + auto buttonsFromString = [](const QString &buttons) -> DecorationButtonsList { + 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; + }; + return buttonsFromString(config.readEntry(key, buttonsToString(defaultValue))); +} + +KDecoration2::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 KDecoration2::BorderSize::Normal; + } + return it.value(); +} + +QString borderSizeToString(KDecoration2::BorderSize size) +{ + return s_borderSizes.key(size); +} + +const QMap &getBorderSizeNames() +{ + return s_borderSizeNames; +} + +} // namespace Utils diff --git a/kcmkwin/kwindecoration/utils.h b/kcmkwin/kwindecoration/utils.h new file mode 100644 index 000000000..1df5b3efb --- /dev/null +++ b/kcmkwin/kwindecoration/utils.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Valerio Pilo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include +#include + +#include + + +using DecorationButtonsList = QVector; + +namespace Utils +{ + +QString buttonsToString(const DecorationButtonsList &buttons); +DecorationButtonsList readDecorationButtons(const KConfigGroup &config, const QString &key, const DecorationButtonsList &defaultValue); + +KDecoration2::BorderSize stringToBorderSize(const QString &name); +QString borderSizeToString(KDecoration2::BorderSize size); + +const QMap &getBorderSizeNames(); + +} diff --git a/kcmkwin/kwindecoration/window-decorations.knsrc b/kcmkwin/kwindecoration/window-decorations.knsrc new file mode 100644 index 000000000..fe8381cd7 --- /dev/null +++ b/kcmkwin/kwindecoration/window-decorations.knsrc @@ -0,0 +1,67 @@ +[KNewStuff3] +Name=Window Decorations +Name[ar]=زخارف النوافذ +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]=Decoración de 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]=Lango 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 +Categories=Various Plasma Styles,Aurorae Themes +TargetDir=themes +StandardResource=tmp +Uncompress=archive