Initial port of Aurorae to KDecoration2

The port to KDecoration2 means quite some changes in the way how Aurorae
works. First of all: the theme to load is passed to the Deocoration ctor
and not searched for by Aurorae itself.

The rendering mechanismn didn't change significantly yet. It's still
rendering to an FBO and passing the image on. This needs some further
work as KDecoration2 does not support the padding any more. So all
themes using shadow are currently broken.

Another big change is the way how the rendering scene is constructed
and used. KDecoration2 doesn't want the the Decoration to be a native
window. But for being able to render a QtQuick scene at all we need a
QQuickWindow. Thus it creates a window parented to the decoration id,
but not accepting any input event. Input is nowadays controlled from
the outside: events are passed into the Decoration, so we don't want
the QtQuick window intercepting events.

In case of non-composited the normal FBO mechanism doesn't work and
Aurorae just renders to the QQuickWindow directly. This could use
some optimization in the decoration renderer in KWin core to not even
try to perform the normal rendering. On the other hand it's probably
too much a hassle for the use case.

The rendering architecture might hopefully be improved with Qt 5.4
and the new QQuickRenderControl class.

The QQuickWindow also exposes a problem for preview in the
kdecoration-viewer and the future KCM: we don't want a different
window, but best would be to get to the QML scene directly. A small
hack is added to have the previewers set a "visualParent" which Aurorae
uses to parent the QML scene to without the need to create a
QQuickWindow.
This commit is contained in:
Martin Gräßlin 2014-10-24 13:48:31 +02:00
parent 6a580d2b90
commit 5c3cd6f4bc
18 changed files with 626 additions and 886 deletions

View file

@ -5,26 +5,23 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
set(kwin3_aurorae_PART_SRCS
set(kwin5_aurorae_PART_SRCS
aurorae.cpp
decorationoptions.cpp
lib/auroraetheme.cpp
lib/themeconfig.cpp
)
add_library(kwin3_aurorae MODULE ${kwin3_aurorae_PART_SRCS})
add_library(kwin5_aurorae MODULE ${kwin5_aurorae_PART_SRCS})
target_link_libraries(kwin3_aurorae
KF5::ConfigCore
target_link_libraries(kwin5_aurorae
KDecoration2::KDecoration
KF5::Service
KF5::WindowSystem
Qt5::Quick
Qt5::Widgets
kdecorations
)
kservice_desktop_to_json(kwin3_aurorae aurorae.desktop)
install(TARGETS kwin3_aurorae DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/kdecorations )
install(TARGETS kwin5_aurorae DESTINATION ${PLUGIN_INSTALL_DIR}/org.kde.kdecoration2)
set(decoration_plugin_SRCS
decorationplugin.cpp
@ -35,9 +32,8 @@ set(decoration_plugin_SRCS
add_library(decorationplugin SHARED ${decoration_plugin_SRCS})
target_link_libraries(decorationplugin
Qt5::Quick
kdecorations
KDecoration2::KDecoration
KF5::ConfigWidgets
KF5::Plasma
)
install(TARGETS decorationplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/kwin/decoration)

View file

@ -20,54 +20,161 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config-kwin.h"
// qml imports
#include "decorationoptions.h"
#include <QApplication>
// KDecoration2
#include <KDecoration2/DecoratedClient>
#include <KDecoration2/DecorationSettings>
// KDE
#include <KConfigGroup>
#include <KPluginFactory>
#include <KSharedConfig>
#include <KService>
#include <KServiceTypeTrader>
// Qt
#include <QDebug>
#include <QDirIterator>
#include <QFileInfo>
#include <QMutex>
#include <QOpenGLFramebufferObject>
#include <QPainter>
#include <QQuickItem>
#include <QQuickWindow>
#include <QQmlComponent>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickItem>
#include <QQuickWindow>
#include <QStandardPaths>
#include <QWidget>
#include <KConfig>
#include <KConfigGroup>
#include <KSharedConfig>
#include <KPluginInfo>
#include <KServiceTypeTrader>
K_PLUGIN_FACTORY_WITH_JSON(AuroraePluginFactory,
K_PLUGIN_FACTORY_WITH_JSON(AuroraeDecoFactory,
"aurorae.json",
registerPlugin<Aurorae::AuroraeFactory>(QString(), &Aurorae::AuroraeFactory::createInstance);)
K_EXPORT_PLUGIN_VERSION(KWIN_DECORATION_API_VERSION)
registerPlugin<Aurorae::Decoration>();)
namespace Aurorae
{
AuroraeFactory::AuroraeFactory(QObject *parent)
: KDecorationFactory(parent)
, m_theme(new AuroraeTheme(this))
, m_engine(new QQmlEngine(this))
, m_component(new QQmlComponent(m_engine, this))
, m_engineType(AuroraeEngine)
, m_mutex(new QMutex(QMutex::Recursive))
class Helper
{
init();
connect(options(), &KDecorationOptions::buttonsChanged, this, &AuroraeFactory::buttonsChanged);
connect(options(), &KDecorationOptions::fontsChanged, this, &AuroraeFactory::titleFontChanged);
connect(options(), &KDecorationOptions::configChanged, this, &AuroraeFactory::updateConfiguration);
public:
void ref();
void unref();
QQmlComponent *component(const QString &theme);
QQmlContext *rootContext();
QQmlComponent *svgComponent() {
return m_svgComponent.data();
}
static Helper &instance();
private:
Helper() = default;
void init();
QQmlComponent *loadComponent(const QString &themeName);
int m_refCount = 0;
QScopedPointer<QQmlEngine> m_engine;
QHash<QString, QQmlComponent*> m_components;
QScopedPointer<QQmlComponent> m_svgComponent;
};
Helper &Helper::instance()
{
static Helper s_helper;
return s_helper;
}
void AuroraeFactory::init()
void Helper::ref()
{
qRegisterMetaType<uint>("Qt::MouseButtons");
m_refCount++;
if (m_refCount == 1) {
m_engine.reset(new QQmlEngine);
init();
}
}
void Helper::unref()
{
m_refCount--;
if (m_refCount == 0) {
// cleanup
m_svgComponent.reset();
m_engine.reset();
m_components.clear();
}
}
static const QString s_defaultTheme = QStringLiteral("kwin4_decoration_qml_plastik");
QQmlComponent *Helper::component(const QString &themeName)
{
// maybe it's an SVG theme?
if (themeName.startsWith(QLatin1Literal("__aurorae__svg__"))) {
if (m_svgComponent.isNull()) {
/* use logic from KDeclarative::setupBindings():
"addImportPath adds the path at the beginning, so to honour user's
paths we need to traverse the list in reverse order" */
QStringListIterator paths(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("module/imports"), QStandardPaths::LocateDirectory));
paths.toBack();
while (paths.hasPrevious()) {
m_engine->addImportPath(paths.previous());
}
m_svgComponent.reset(new QQmlComponent(m_engine.data()));
m_svgComponent->loadUrl(QUrl(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/aurorae/aurorae.qml"))));
}
return m_svgComponent.data();
}
// try finding the QML package
auto it = m_components.constFind(themeName);
if (it != m_components.constEnd()) {
return it.value();
}
auto component = loadComponent(themeName);
if (component) {
m_components.insert(themeName, component);
return component;
}
// try loading default component
if (themeName != s_defaultTheme) {
return loadComponent(s_defaultTheme);
}
return nullptr;
}
QQmlComponent *Helper::loadComponent(const QString &themeName)
{
qCDebug(AURORAE) << "Trying to load QML Decoration " << themeName;
const QString internalname = themeName.toLower();
QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(internalname);
KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("KWin/Decoration"), constraint);
if (offers.isEmpty()) {
qCCritical(AURORAE) << "Couldn't find QML Decoration " << themeName << endl;
// TODO: what to do in error case?
return nullptr;
}
KService::Ptr service = offers.first();
const QString pluginName = service->property(QStringLiteral("X-KDE-PluginInfo-Name")).toString();
const QString scriptName = service->property(QStringLiteral("X-Plasma-MainScript")).toString();
const QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral(KWIN_NAME) + QStringLiteral("/decorations/") + pluginName + QStringLiteral("/contents/") + scriptName);
if (file.isNull()) {
qCDebug(AURORAE) << "Could not find script file for " << pluginName;
// TODO: what to do in error case?
return nullptr;
}
// setup the QML engine
/* use logic from KDeclarative::setupBindings():
"addImportPath adds the path at the beginning, so to honour user's
paths we need to traverse the list in reverse order" */
QStringListIterator paths(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("module/imports"), QStandardPaths::LocateDirectory));
paths.toBack();
while (paths.hasPrevious()) {
m_engine->addImportPath(paths.previous());
}
QQmlComponent *component = new QQmlComponent(m_engine.data(), m_engine.data());
component->loadUrl(QUrl::fromLocalFile(file));
return component;
}
QQmlContext *Helper::rootContext()
{
return m_engine->rootContext();
}
void Helper::init()
{
// we need to first load our decoration plugin
// once it's loaded we can provide the Borders and access them from C++ side
// so let's try to locate our plugin:
@ -95,224 +202,80 @@ void AuroraeFactory::init()
m_engine->importPlugin(pluginPath, "org.kde.kwin.decoration", nullptr);
qmlRegisterType<KWin::Borders>("org.kde.kwin.decoration", 0, 1, "Borders");
KConfig conf(QStringLiteral("auroraerc"));
KConfigGroup group(&conf, "Engine");
if (!group.hasKey("EngineType") && !group.hasKey("ThemeName")) {
// neither engine type and theme name are configured, use the only available theme
initQML(group);
} else if (group.hasKey("EngineType")) {
const QString engineType = group.readEntry("EngineType", "aurorae").toLower();
if (engineType == QStringLiteral("qml")) {
initQML(group);
} else {
// fallback to classic Aurorae Themes
initAurorae(conf, group);
}
} else {
// fallback to classic Aurorae Themes
initAurorae(conf, group);
}
qmlRegisterType<KDecoration2::Decoration>();
qmlRegisterType<KDecoration2::DecoratedClient>();
}
void AuroraeFactory::initAurorae(KConfig &conf, KConfigGroup &group)
{
m_engineType = AuroraeEngine;
const QString themeName = group.readEntry("ThemeName");
if (themeName.isEmpty()) {
// no theme configured, fall back to Plastik QML theme
initQML(group);
return;
}
KConfig config(QStringLiteral("aurorae/themes/") + themeName + QStringLiteral("/") + themeName + QStringLiteral("rc"),
KConfig::FullConfig, QStandardPaths::GenericDataLocation);
KConfigGroup themeGroup(&conf, themeName);
m_theme->loadTheme(themeName, config);
m_theme->setBorderSize((KDecorationDefines::BorderSize)themeGroup.readEntry<int>("BorderSize", KDecorationDefines::BorderNormal));
m_theme->setButtonSize((KDecorationDefines::BorderSize)themeGroup.readEntry<int>("ButtonSize", KDecorationDefines::BorderNormal));
m_theme->setTabDragMimeType(tabDragMimeType());
// setup the QML engine
/* use logic from KDeclarative::setupBindings():
"addImportPath adds the path at the beginning, so to honour user's
paths we need to traverse the list in reverse order" */
QStringListIterator paths(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("module/imports"), QStandardPaths::LocateDirectory));
paths.toBack();
while (paths.hasPrevious()) {
m_engine->addImportPath(paths.previous());
}
m_component->loadUrl(QUrl(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/aurorae/aurorae.qml"))));
m_engine->rootContext()->setContextProperty(QStringLiteral("auroraeTheme"), m_theme);
m_themeName = themeName;
}
void AuroraeFactory::initQML(const KConfigGroup &group)
{
// try finding the QML package
const QString themeName = group.readEntry("ThemeName", "kwin4_decoration_qml_plastik");
qCDebug(AURORAE) << "Trying to load QML Decoration " << themeName;
const QString internalname = themeName.toLower();
QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(internalname);
KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("KWin/Decoration"), constraint);
if (offers.isEmpty()) {
qCCritical(AURORAE) << "Couldn't find QML Decoration " << themeName << endl;
// TODO: what to do in error case?
return;
}
KService::Ptr service = offers.first();
const QString pluginName = service->property(QStringLiteral("X-KDE-PluginInfo-Name")).toString();
const QString scriptName = service->property(QStringLiteral("X-Plasma-MainScript")).toString();
const QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral(KWIN_NAME) + QStringLiteral("/decorations/") + pluginName + QStringLiteral("/contents/") + scriptName);
if (file.isNull()) {
qCDebug(AURORAE) << "Could not find script file for " << pluginName;
// TODO: what to do in error case?
return;
}
m_engineType = QMLEngine;
// setup the QML engine
/* use logic from KDeclarative::setupBindings():
"addImportPath adds the path at the beginning, so to honour user's
paths we need to traverse the list in reverse order" */
QStringListIterator paths(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("module/imports"), QStandardPaths::LocateDirectory));
paths.toBack();
while (paths.hasPrevious()) {
m_engine->addImportPath(paths.previous());
}
m_component->loadUrl(QUrl::fromLocalFile(file));
m_themeName = themeName;
}
AuroraeFactory::~AuroraeFactory()
{
s_instance = nullptr;
}
AuroraeFactory *AuroraeFactory::instance()
{
if (!s_instance) {
s_instance = new AuroraeFactory;
}
return s_instance;
}
QObject *AuroraeFactory::createInstance(QWidget*, QObject*, const QList< QVariant >&)
{
return instance();
}
void AuroraeFactory::updateConfiguration()
{
const KConfig conf(QStringLiteral("auroraerc"));
const KConfigGroup group(&conf, "Engine");
const QString themeName = group.readEntry("ThemeName", "example-deco");
const KConfig config(QStringLiteral("aurorae/themes/") + themeName + QStringLiteral("/") + themeName + QStringLiteral("rc"),
KConfig::FullConfig, QStandardPaths::GenericDataLocation);
const KConfigGroup themeGroup(&conf, themeName);
if (themeName != m_themeName) {
m_engine->clearComponentCache();
init();
emit recreateDecorations();
}
if (m_engineType == AuroraeEngine) {
m_theme->setBorderSize((KDecorationDefines::BorderSize)themeGroup.readEntry<int>("BorderSize", KDecorationDefines::BorderNormal));
m_theme->setButtonSize((KDecorationDefines::BorderSize)themeGroup.readEntry<int>("ButtonSize", KDecorationDefines::BorderNormal));
} else {
// we don't know how the settings change -> recreate
emit recreateDecorations();
}
emit configChanged();
}
bool AuroraeFactory::supports(Ability ability) const
{
switch (ability) {
case AbilityAnnounceButtons:
case AbilityUsesAlphaChannel:
case AbilityAnnounceAlphaChannel:
case AbilityButtonMenu:
case AbilityButtonSpacer:
case AbilityExtendIntoClientArea:
case AbilityButtonMinimize:
case AbilityButtonMaximize:
case AbilityButtonClose:
case AbilityButtonAboveOthers:
case AbilityButtonBelowOthers:
case AbilityButtonShade:
case AbilityButtonOnAllDesktops:
case AbilityButtonHelp:
case AbilityButtonApplicationMenu:
case AbilityProvidesShadow:
return true; // TODO: correct value from theme
case AbilityTabbing:
return false;
case AbilityUsesBlurBehind:
return true;
default:
return false;
}
}
KDecoration *AuroraeFactory::createDecoration(KDecorationBridge *bridge)
{
AuroraeClient *client = new AuroraeClient(bridge, this);
return client;
}
QList< KDecorationDefines::BorderSize > AuroraeFactory::borderSizes() const
{
return QList< BorderSize >() << BorderTiny << BorderNormal <<
BorderLarge << BorderVeryLarge << BorderHuge <<
BorderVeryHuge << BorderOversized;
}
QQuickItem *AuroraeFactory::createQmlDecoration(Aurorae::AuroraeClient *client)
{
QQmlContext *context = new QQmlContext(m_engine->rootContext(), this);
context->setContextProperty(QStringLiteral("decoration"), client);
return qobject_cast< QQuickItem* >(m_component->create(context));
}
AuroraeFactory *AuroraeFactory::s_instance = nullptr;
/*******************************************************
* Client
*******************************************************/
AuroraeClient::AuroraeClient(KDecorationBridge *bridge, KDecorationFactory *factory)
: KDecoration(bridge, factory)
, m_view(nullptr)
, m_item(AuroraeFactory::instance()->createQmlDecoration(this))
Decoration::Decoration(QObject *parent, const QVariantList &args)
: KDecoration2::Decoration(parent)
, m_item(nullptr)
, m_borders(nullptr)
, m_maximizedBorders(nullptr)
, m_extendedBorders(nullptr)
, m_padding(nullptr)
, m_themeName(s_defaultTheme)
, m_mutex(QMutex::Recursive)
{
connect(AuroraeFactory::instance(), SIGNAL(buttonsChanged()), SIGNAL(buttonsChanged()));
connect(AuroraeFactory::instance(), SIGNAL(configChanged()), SIGNAL(configChanged()));
connect(AuroraeFactory::instance(), SIGNAL(titleFontChanged()), SIGNAL(fontChanged()));
connect(m_item, SIGNAL(alphaChanged()), SLOT(slotAlphaChanged()));
connect(this, SIGNAL(appMenuAvailable()), SIGNAL(appMenuAvailableChanged()));
connect(this, SIGNAL(appMenuUnavailable()), SIGNAL(appMenuAvailableChanged()));
if (!args.isEmpty()) {
const auto map = args.first().toMap();
auto it = map.constFind(QStringLiteral("theme"));
if (it != map.constEnd()) {
m_themeName = it.value().toString();
}
}
Helper::instance().ref();
}
AuroraeClient::~AuroraeClient()
Decoration::~Decoration()
{
QMutexLocker locker(AuroraeFactory::instance()->mutex());
Helper::instance().unref();
}
void AuroraeClient::init()
void Decoration::init()
{
m_view = new QQuickWindow();
m_view->setFlags(initialWFlags());
m_view->setColor(Qt::transparent);
setMainWindow(m_view);
if (compositingActive()) {
connect(m_view, &QQuickWindow::beforeRendering, [this]() {
int left, right, top, bottom;
left = right = top = bottom = 0;
padding(left, right, top, bottom);
if (m_fbo.isNull() || m_fbo->size() != QSize(width() + left + right, height() + top + bottom)) {
m_fbo.reset(new QOpenGLFramebufferObject(QSize(width() + left + right, height() + top + bottom),
QOpenGLFramebufferObject::CombinedDepthStencil));
KDecoration2::Decoration::init();
QQmlContext *context = new QQmlContext(Helper::instance().rootContext(), this);
context->setContextProperty(QStringLiteral("decoration"), this);
auto component = Helper::instance().component(m_themeName);
if (!component) {
return;
}
if (component == Helper::instance().svgComponent()) {
// load SVG theme
const QString themeName = m_themeName.mid(16);
KConfig config(QStringLiteral("aurorae/themes/") + themeName + QStringLiteral("/") + themeName + QStringLiteral("rc"),
KConfig::FullConfig, QStandardPaths::GenericDataLocation);
// KConfigGroup themeGroup(&conf, themeName);
AuroraeTheme *theme = new AuroraeTheme(this);
theme->loadTheme(themeName, config);
// m_theme->setBorderSize((KDecorationDefines::BorderSize)themeGroup.readEntry<int>("BorderSize", KDecorationDefines::BorderNormal));
// m_theme->setButtonSize((KDecorationDefines::BorderSize)themeGroup.readEntry<int>("ButtonSize", KDecorationDefines::BorderNormal));
// m_theme->setTabDragMimeType(tabDragMimeType());
context->setContextProperty(QStringLiteral("auroraeTheme"), theme);
}
m_item = qobject_cast< QQuickItem* >(component->create(context));
if (!m_item) {
return;
}
m_item->setParent(this);
QVariant visualParent = property("visualParent");
if (visualParent.isValid()) {
m_item->setParentItem(visualParent.value<QQuickItem*>());
} else {
// we need a QQuickWindow till we depend on Qt 5.4
m_decorationWindow.reset(QWindow::fromWinId(client()->decorationId()));
m_view.reset(new QQuickWindow(m_decorationWindow.data()));
m_view->setFlags(Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput);
m_view->setColor(Qt::transparent);
connect(m_view.data(), &QQuickWindow::beforeRendering, [this]() {
if (!KDecoration2::DecorationSettings::self()->isAlphaChannelSupported()) {
// directly render to QQuickWindow
return;
}
if (m_fbo.isNull() || m_fbo->size() != size()) {
m_fbo.reset(new QOpenGLFramebufferObject(size(), QOpenGLFramebufferObject::CombinedDepthStencil));
if (!m_fbo->isValid()) {
qCWarning(AURORAE) << "Creating FBO as render target failed";
m_fbo.reset();
@ -321,315 +284,150 @@ void AuroraeClient::init()
}
m_view->setRenderTarget(m_fbo.data());
});
connect(m_view, &QQuickWindow::afterRendering, [this]{
QMutexLocker locker(AuroraeFactory::instance()->mutex());
connect(m_view.data(), &QQuickWindow::afterRendering, [this] {
if (!m_fbo) {
return;
}
QMutexLocker locker(&m_mutex);
m_buffer = m_fbo->toImage();
});
connect(m_view, &QQuickWindow::afterRendering, this,
static_cast<void (KDecoration::*)(void)>(&KDecoration::update), Qt::QueuedConnection);
}
if (m_item) {
connect(KDecoration2::DecorationSettings::self(), &KDecoration2::DecorationSettings::alphaChannelSupportedChanged,
m_view.data(), &QQuickWindow::update);
connect(m_view.data(), &QQuickWindow::afterRendering, this, [this] { update(); }, Qt::QueuedConnection);
m_item->setParentItem(m_view->contentItem());
m_item->setParent(m_view);
setupBorders();
}
slotAlphaChanged();
AuroraeFactory::instance()->theme()->setCompositingActive(compositingActive());
}
bool AuroraeClient::eventFilter(QObject *object, QEvent *event)
{
// we need to filter the wheel events on the decoration
// QML does not yet provide a way to accept wheel events, this will change with Qt 5
// TODO: remove in KDE5
// see BUG: 304248
if (object != widget() || event->type() != QEvent::Wheel) {
return KDecoration::eventFilter(object, event);
setupBorders(m_item);
if (m_extendedBorders) {
auto updateExtendedBorders = [this] {
setExtendedBorders(m_extendedBorders->left(), m_extendedBorders->right(), m_extendedBorders->top(), m_extendedBorders->bottom());
};
updateExtendedBorders();
connect(m_extendedBorders, &KWin::Borders::leftChanged, this, updateExtendedBorders);
connect(m_extendedBorders, &KWin::Borders::rightChanged, this, updateExtendedBorders);
connect(m_extendedBorders, &KWin::Borders::topChanged, this, updateExtendedBorders);
connect(m_extendedBorders, &KWin::Borders::bottomChanged, this, updateExtendedBorders);
}
QWheelEvent *wheel = static_cast<QWheelEvent*>(event);
if (mousePosition(wheel->pos()) == PositionCenter) {
titlebarMouseWheelOperation(wheel->delta());
return true;
connect(client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateBorders, Qt::QueuedConnection);
updateBorders();
if (!m_view.isNull()) {
m_view->setVisible(true);
m_view->lower();
m_view->resize(m_item->width(), m_item->height());
auto resizeWindow = [this] {
m_view->resize(m_item->width(), m_item->height());
m_view->lower();
m_view->update();
};
connect(m_item, &QQuickItem::widthChanged, this, resizeWindow);
connect(m_item, &QQuickItem::heightChanged, this, resizeWindow);
resizeWindow();
}
return false;
}
void AuroraeClient::resize(const QSize &s)
{
if (m_item) {
m_item->setWidth(s.width());
m_item->setHeight(s.height());
}
m_view->resize(s);
}
void AuroraeClient::borders(int &left, int &right, int &top, int &bottom) const
{
if (!m_item) {
left = right = top = bottom = 0;
return;
}
KWin::Borders *borders = nullptr;
if (maximizeMode() == MaximizeFull) {
borders = m_maximizedBorders;
} else {
borders = m_borders;
}
sizesFromBorders(borders, left, right, top, bottom);
}
void AuroraeClient::padding(int &left, int &right, int &top, int &bottom) const
{
if (!m_padding) {
left = right = top = bottom = 0;
return;
}
if (maximizeMode() == MaximizeFull) {
left = right = top = bottom = 0;
return;
}
sizesFromBorders(m_padding, left, right, top, bottom);
}
void AuroraeClient::sizesFromBorders(const KWin::Borders *borders, int &left, int &right, int &top, int &bottom) const
{
if (!borders) {
left = right = top = bottom = 0;
return;
}
left = borders->left();
right = borders->right();
top = borders->top();
bottom = borders->bottom();
}
QSize AuroraeClient::minimumSize() const
{
return m_view->minimumSize();
}
KDecorationDefines::Position AuroraeClient::mousePosition(const QPoint &point) const
{
// based on the code from deKorator
int pos = PositionCenter;
if (isShade() || isMaximized()) {
return Position(pos);
}
int borderLeft, borderTop, borderRight, borderBottom;
borders(borderLeft, borderRight, borderTop, borderBottom);
int paddingLeft, paddingTop, paddingRight, paddingBottom;
padding(paddingLeft, paddingRight, paddingTop, paddingBottom);
int titleEdgeLeft, titleEdgeRight, titleEdgeTop, titleEdgeBottom;
AuroraeFactory::instance()->theme()->titleEdges(titleEdgeLeft, titleEdgeTop, titleEdgeRight, titleEdgeBottom, false);
switch (AuroraeFactory::instance()->theme()->decorationPosition()) {
case DecorationTop:
borderTop = titleEdgeTop;
break;
case DecorationLeft:
borderLeft = titleEdgeLeft;
break;
case DecorationRight:
borderRight = titleEdgeRight;
break;
case DecorationBottom:
borderBottom = titleEdgeBottom;
break;
default:
break; // nothing
}
if (point.x() >= (m_view->width() - borderRight - paddingRight)) {
pos |= PositionRight;
} else if (point.x() <= borderLeft + paddingLeft) {
pos |= PositionLeft;
}
if (point.y() >= m_view->height() - borderBottom - paddingBottom) {
pos |= PositionBottom;
} else if (point.y() <= borderTop + paddingTop ) {
pos |= PositionTop;
}
return Position(pos);
}
void AuroraeClient::menuClicked()
{
showWindowMenu(QCursor::pos());
}
void AuroraeClient::appMenuClicked()
{
showApplicationMenu(QCursor::pos());
}
void AuroraeClient::toggleShade()
{
setShade(!isShade());
}
void AuroraeClient::toggleKeepAbove()
{
setKeepAbove(!keepAbove());
}
void AuroraeClient::toggleKeepBelow()
{
setKeepBelow(!keepBelow());
}
void AuroraeClient::titlePressed(int button, int buttons)
{
titlePressed(static_cast<Qt::MouseButton>(button), static_cast<Qt::MouseButtons>(buttons));
}
void AuroraeClient::titlePressed(Qt::MouseButton button, Qt::MouseButtons buttons)
{
const QPoint cursor = QCursor::pos();
QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, cursor - geometry().topLeft() + (m_padding ? QPoint(m_padding->left(), m_padding->top()) : QPoint(0, 0)),
cursor, button, buttons, Qt::NoModifier);
processMousePressEvent(event);
delete event;
event = nullptr;
}
void AuroraeClient::themeChanged()
{
m_item->deleteLater();
m_item = AuroraeFactory::instance()->createQmlDecoration(this);
if (!m_item) {
m_borders = nullptr;
m_extendedBorders = nullptr;
m_maximizedBorders = nullptr;
m_padding = nullptr;
return;
}
m_item->setParentItem(m_view->contentItem());
m_item->setParent(m_view);
setupBorders();
connect(m_item, SIGNAL(alphaChanged()), SLOT(slotAlphaChanged()));
slotAlphaChanged();
}
int AuroraeClient::doubleClickInterval() const
{
return QApplication::doubleClickInterval();
}
void AuroraeClient::closeWindow()
{
QMetaObject::invokeMethod(qobject_cast< KDecoration* >(this), "doCloseWindow", Qt::QueuedConnection);
}
void AuroraeClient::doCloseWindow()
{
KDecoration::closeWindow();
}
void AuroraeClient::maximize(int button)
{
// a maximized window does not need to have a window decoration
// in that case we need to delay handling by one cycle
// BUG: 304870
QMetaObject::invokeMethod(qobject_cast< KDecoration* >(this),
"doMaximzie",
Qt::QueuedConnection,
Q_ARG(int, button));
}
void AuroraeClient::doMaximzie(int button)
{
KDecoration::maximize(static_cast<Qt::MouseButton>(button));
}
void AuroraeClient::titlebarDblClickOperation()
{
// the double click operation can result in a window being maximized
// see maximize
QMetaObject::invokeMethod(qobject_cast< KDecoration* >(this), "doTitlebarDblClickOperation", Qt::QueuedConnection);
}
void AuroraeClient::doTitlebarDblClickOperation()
{
KDecoration::titlebarDblClickOperation();
}
QVariant AuroraeClient::readConfig(const QString &key, const QVariant &defaultValue)
QVariant Decoration::readConfig(const QString &key, const QVariant &defaultValue)
{
KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("auroraerc"));
return config->group(AuroraeFactory::instance()->currentThemeName()).readEntry(key, defaultValue);
return config->group(QStringLiteral("Plastik")).readEntry(key, defaultValue);
}
void AuroraeClient::slotAlphaChanged()
void Decoration::setupBorders(QQuickItem *item)
{
if (!m_item) {
setAlphaEnabled(false);
m_borders = item->findChild<KWin::Borders*>(QStringLiteral("borders"));
m_maximizedBorders = item->findChild<KWin::Borders*>(QStringLiteral("maximizedBorders"));
m_extendedBorders = item->findChild<KWin::Borders*>(QStringLiteral("extendedBorders"));
m_padding = item->findChild<KWin::Borders*>(QStringLiteral("padding"));
}
void Decoration::updateBorders()
{
KWin::Borders *b = m_borders;
if (client()->isMaximized() && m_maximizedBorders) {
b = m_maximizedBorders;
}
if (!b) {
return;
}
QVariant alphaProperty = m_item->property("alpha");
if (alphaProperty.isValid() && alphaProperty.canConvert<bool>()) {
setAlphaEnabled(alphaProperty.toBool());
} else {
// by default all Aurorae themes use the alpha channel
setAlphaEnabled(true);
}
setBorders(b->left(), b->right(), b->top(), b->bottom());
}
QRegion AuroraeClient::region(KDecorationDefines::Region r)
void Decoration::paint(QPainter *painter)
{
if (r != ExtendedBorderRegion) {
return QRegion();
}
if (!m_item) {
return QRegion();
}
if (isMaximized()) {
// empty region for maximized windows
return QRegion();
}
int left, right, top, bottom;
left = right = top = bottom = 0;
sizesFromBorders(m_extendedBorders, left, right, top, bottom);
if (top == 0 && right == 0 && bottom == 0 && left == 0) {
// no extended borders
return QRegion();
}
int paddingLeft, paddingRight, paddingTop, paddingBottom;
paddingLeft = paddingRight = paddingTop = paddingBottom = 0;
padding(paddingLeft, paddingRight, paddingTop, paddingBottom);
QRect rect = this->rect().adjusted(paddingLeft, paddingTop, -paddingRight, -paddingBottom);
rect.translate(-paddingLeft, -paddingTop);
return QRegion(rect.adjusted(-left, -top, right, bottom)).subtract(rect);
QMutexLocker locker(&m_mutex);
painter->fillRect(rect(), Qt::transparent);
// TODO: remove Shadow
painter->drawImage(rect(), m_buffer);
}
bool AuroraeClient::animationsSupported() const
void Decoration::hoverEnterEvent(QHoverEvent *event)
{
return compositingActive();
}
void AuroraeClient::render(QPaintDevice *device, const QRegion &sourceRegion)
{
QMutexLocker locker(AuroraeFactory::instance()->mutex());
QPainter painter(device);
painter.setClipRegion(sourceRegion);
painter.drawImage(QPoint(0, 0), m_buffer);
}
void AuroraeClient::setupBorders()
{
if (!m_item) {
return;
if (m_view) {
event->setAccepted(false);
QCoreApplication::sendEvent(m_view.data(), event);
}
m_borders = m_item->findChild<KWin::Borders*>(QStringLiteral("borders"));
m_maximizedBorders = m_item->findChild<KWin::Borders*>(QStringLiteral("maximizedBorders"));
m_extendedBorders = m_item->findChild<KWin::Borders*>(QStringLiteral("extendedBorders"));
m_padding = m_item->findChild<KWin::Borders*>(QStringLiteral("padding"));
KDecoration2::Decoration::hoverEnterEvent(event);
}
} // namespace Aurorae
void Decoration::hoverLeaveEvent(QHoverEvent *event)
{
if (m_view) {
event->setAccepted(false);
QCoreApplication::sendEvent(m_view.data(), event);
}
KDecoration2::Decoration::hoverLeaveEvent(event);
}
void Decoration::hoverMoveEvent(QHoverEvent *event)
{
if (m_view) {
QMouseEvent ev(QEvent::MouseMove, event->posF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
QCoreApplication::sendEvent(m_view.data(), &ev);
}
KDecoration2::Decoration::hoverMoveEvent(event);
}
void Decoration::mouseMoveEvent(QMouseEvent *event)
{
if (m_view) {
event->setAccepted(false);
QCoreApplication::sendEvent(m_view.data(), event);
}
KDecoration2::Decoration::mouseMoveEvent(event);
}
void Decoration::mousePressEvent(QMouseEvent *event)
{
if (m_view) {
event->setAccepted(false);
QCoreApplication::sendEvent(m_view.data(), event);
}
KDecoration2::Decoration::mousePressEvent(event);
}
void Decoration::mouseReleaseEvent(QMouseEvent *event)
{
if (m_view) {
event->setAccepted(false);
QCoreApplication::sendEvent(m_view.data(), event);
}
KDecoration2::Decoration::mouseReleaseEvent(event);
}
void Decoration::installTitleItem(QQuickItem *item)
{
auto update = [this, item] {
QRect rect = item->mapRectToScene(item->childrenRect()).toRect();
if (rect.isNull()) {
rect = item->parentItem()->mapRectToScene(QRectF(item->x(), item->y(), item->width(), item->height())).toRect();
}
setTitleRect(rect);
};
update();
connect(item, &QQuickItem::widthChanged, this, update);
connect(item, &QQuickItem::heightChanged, this, update);
connect(item, &QQuickItem::xChanged, this, update);
connect(item, &QQuickItem::yChanged, this, update);
}
}
#include "aurorae.moc"

View file

@ -1,68 +0,0 @@
[Desktop Entry]
Name=Aurorae Decoration Theme Engine
Name[ar]=محرك شفق لسمات التزيين
Name[ast]=Motor de temes de decoración Aurorae
Name[bg]=Теми за декорация на прозорци Aurorae
Name[bs]=Aurore, tematski motor dekoracija
Name[ca]=Motor del tema de decoració Aurorae
Name[ca@valencia]=Motor del tema de decoració Aurorae
Name[cs]=Stroj motivů dekorace Aurorae
Name[csb]=Mòtór dekòracëji wëzdrzatkù Aurorae
Name[da]=Temamotor til Aurorae-dekorationen
Name[de]=Aurorae-Dekorationsdesign-Engine
Name[el]=Μηχανισμός διακόσμησης θεμάτων Aurorae
Name[en_GB]=Auroræ Decoration Theme Engine
Name[eo]=Aurorae Ornamaĵ-etosa Modulo
Name[es]=Motor de temas de decoración Aurorae
Name[et]=Aurorae dekoratsioonide teema mootor
Name[eu]=Aurorae apainketa-gaiaren motorra
Name[fi]=Kehysten teemamoottori Aurorae
Name[fr]=Moteur de thèmes pour la décoration « Aurorae »
Name[fy]=Aurorae dekoraasje tema motor
Name[ga]=Inneall Téama Maisiúcháin Aurorae
Name[gl]=Motor de temas de decoración Aurorae
Name[he]=מנוע ערכת התצוגה Aurorae Decoration
Name[hr]=Tematski mehanizam za ukrase Aurorae
Name[hu]=Aurorae ablakdekorációs témamodul
Name[ia]=Motor de thema de decoration Aurorae
Name[id]=Mesin Tema Dekorasi Aurorae
Name[is]=Aurorae skjáskreytiþemavél
Name[it]=Motore dei temi decorativi Aurorae
Name[ja]=
Name[kk]=Aurorae безендіру нақыш теігі
Name[km]= Aurorae
Name[kn]= ಿ ಿ() ಿ
Name[ko]=Aurorae
Name[lt]=Aurorae dekoracijos temos variklis
Name[lv]=Aurorae dekorācijas tēmu dzinējs
Name[ml]= ിി ി
Name[mr]= ि
Name[nb]=Aurorae motor for dekorasjonstema
Name[nds]=Aurorae Dekoratschonen-Musterkarn
Name[nl]=Aurorae decoratiethema-engine
Name[nn]=Motor for pynting med temaet Aurorae
Name[pa]=
Name[pl]=Silnik zestawu ozdób Aurora
Name[pt]=Motor do Tema de Decoração Aurorae
Name[pt_BR]=Mecanismo do tema de decoração Aurorae
Name[ro]=Motor pentru tematici de decorare Aurorae
Name[ru]=Движок оформлений окон Aurorae
Name[si]=Aurorae
Name[sk]=Aurorae témy dekorácie
Name[sl]=Pogon Aurorae za teme okraskov
Name[sr]=Ауроре, тематски мотор декорација
Name[sr@ijekavian]=Ауроре, тематски мотор декорација
Name[sr@ijekavianlatin]=Aurore, tematski motor dekoracija
Name[sr@latin]=Aurore, tematski motor dekoracija
Name[sv]=Aurora dekorationstemagränssnitt
Name[tg]=Системаи мавзӯъҳои аврора
Name[th]= Aurorae
Name[tr]=Aurorae Dekorasyon Teması Motoru
Name[ug]=Aurorae زىننەتلەش ئۆرنەك ماتورى
Name[uk]=Рушій декорації тем Aurorae
Name[vi]=Cơ chế sc thái trang trí Aurorae
Name[wa]=Moteur di tinme di gåyotaedje Aurorae
Name[x-test]=xxAurorae Decoration Theme Enginexx
Name[zh_CN]=Aurorae
Name[zh_TW]=Aurorae
X-KDE-PluginInfo-Name=aurorae

View file

@ -18,19 +18,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef AURORAE_H
#define AURORAE_H
#include "themeconfig.h"
#include <KDecoration2/Decoration>
#include <QVariant>
#include <QMutex>
#include <kdecoration.h>
#include <kdecorationfactory.h>
class QMutex;
class QOpenGLFramebufferObject;
class QQmlComponent;
class QQmlEngine;
class QQuickItem;
class QQuickWindow;
class KConfig;
class KConfigGroup;
class QWindow;
namespace KWin
{
@ -39,144 +36,44 @@ class Borders;
namespace Aurorae
{
class AuroraeTheme;
class AuroraeClient;
class AuroraeFactory : public KDecorationFactory
class Decoration : public KDecoration2::Decoration
{
Q_OBJECT
public:
~AuroraeFactory();
explicit Decoration(QObject *parent = nullptr, const QVariantList &args = QVariantList());
virtual ~Decoration();
static AuroraeFactory* instance();
static QObject *createInstance(QWidget *, QObject *, const QList<QVariant> &);
KDecoration *createDecoration(KDecorationBridge*);
bool supports(Ability ability) const;
virtual QList< BorderSize > borderSizes() const;
AuroraeTheme *theme() const {
return m_theme;
}
QQuickItem *createQmlDecoration(AuroraeClient *client);
const QString &currentThemeName() const {
return m_themeName;
}
QMutex *mutex() {
return m_mutex.data();
}
private:
enum EngineType {
AuroraeEngine,
QMLEngine
};
explicit AuroraeFactory(QObject *parent = nullptr);
void init();
void initAurorae(KConfig &conf, KConfigGroup &group);
void initQML(const KConfigGroup& group);
Q_SIGNALS:
void buttonsChanged();
void titleFontChanged();
void configChanged();
private Q_SLOTS:
void updateConfiguration();
private:
static AuroraeFactory *s_instance;
AuroraeTheme *m_theme;
QQmlEngine *m_engine;
QQmlComponent *m_component;
EngineType m_engineType;
QString m_themeName;
QScopedPointer<QMutex> m_mutex;
};
class AuroraeClient : public KDecoration
{
Q_OBJECT
Q_PROPERTY(QRect geometry READ geometry)
Q_PROPERTY(int height READ height)
Q_PROPERTY(bool closeable READ isCloseable CONSTANT)
Q_PROPERTY(bool maximizeable READ isMaximizable CONSTANT)
Q_PROPERTY(bool minimizeable READ isMinimizable CONSTANT)
Q_PROPERTY(bool modal READ isModal)
Q_PROPERTY(bool moveable READ isMovable CONSTANT)
Q_PROPERTY(bool preview READ isPreview CONSTANT)
Q_PROPERTY(bool resizeable READ isResizable CONSTANT)
Q_PROPERTY(bool shadeable READ isShadeable)
Q_PROPERTY(bool providesContextHelp READ providesContextHelp)
Q_PROPERTY(bool appMenu READ menuAvailable NOTIFY appMenuAvailableChanged)
Q_PROPERTY(QRect transparentRect READ transparentRect)
Q_PROPERTY(int width READ width)
Q_PROPERTY(qulonglong windowId READ windowId CONSTANT)
Q_PROPERTY(int doubleClickInterval READ doubleClickInterval)
Q_PROPERTY(bool animationsSupported READ animationsSupported CONSTANT)
// TODO: window tabs - they suck for dynamic features
public:
AuroraeClient(KDecorationBridge* bridge, KDecorationFactory* factory);
virtual ~AuroraeClient();
virtual bool eventFilter(QObject *object, QEvent *event);
virtual void borders(int& left, int& right, int& top, int& bottom) const;
virtual void init();
virtual QSize minimumSize() const;
virtual Position mousePosition(const QPoint& p) const;
virtual void resize(const QSize& s);
// optional overrides
virtual void padding(int &left, int &right, int &top, int &bottom) const;
int doubleClickInterval() const;
bool animationsSupported() const;
void paint(QPainter *painter) override;
Q_INVOKABLE QVariant readConfig(const QString &key, const QVariant &defaultValue = QVariant());
virtual void render(QPaintDevice *device, const QRegion &sourceRegion);
Q_SIGNALS:
void buttonsChanged();
/**
* Signal emitted when the decoration's configuration might have changed.
* A decoration could reload it's configuration when this signal is emitted.
**/
void configChanged();
void fontChanged();
void appMenuAvailableChanged();
public Q_SLOTS:
void menuClicked();
void appMenuClicked();
void toggleShade();
void toggleKeepAbove();
void toggleKeepBelow();
void titlePressed(int button, int buttons);
void titlePressed(Qt::MouseButton button, Qt::MouseButtons buttons);
void closeWindow();
void titlebarDblClickOperation();
void maximize(int button);
void init() override;
void installTitleItem(QQuickItem *item);
QRegion region(KDecorationDefines::Region r);
private Q_SLOTS:
void themeChanged();
void doCloseWindow();
void doTitlebarDblClickOperation();
void doMaximzie(int button);
void slotAlphaChanged();
protected:
void hoverEnterEvent(QHoverEvent *event) override;
void hoverLeaveEvent(QHoverEvent *event) override;
void hoverMoveEvent(QHoverEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
private:
void sizesFromBorders(const KWin::Borders *borders, int &left, int &right, int &top, int &bottom) const;
void setupBorders();
QQuickWindow *m_view;
QQuickItem *m_item;
void setupBorders(QQuickItem *item);
void updateBorders();
QScopedPointer<QOpenGLFramebufferObject> m_fbo;
QImage m_buffer;
QScopedPointer<QWindow> m_decorationWindow;
QScopedPointer<QQuickWindow> m_view;
QQuickItem *m_item;
KWin::Borders *m_borders;
KWin::Borders *m_maximizedBorders;
KWin::Borders *m_extendedBorders;
KWin::Borders *m_padding;
QString m_themeName;
QMutex m_mutex;
};
}

View file

@ -0,0 +1,14 @@
{
"Type": "Service",
"X-KDE-Library": "kwin5_aurorae",
"X-KDE-PluginInfo-EnabledByDefault": true,
"X-KDE-PluginInfo-Name": "org.kde.kwin.aurorae",
"X-KDE-ServiceTypes": [
"org.kde.kdecoration2"
],
"org.kde.kdecoration2": {
"blur": true,
"themes": true,
"defaultTheme": "kwin4_decoration_qml_plastik"
}
}

View file

@ -15,19 +15,55 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "decorationoptions.h"
#include <kdecoration.h>
#include <KDecoration2/DecoratedClient>
#include <KDecoration2/DecorationSettings>
#include <KConfigGroup>
#include <KSharedConfig>
namespace KWin
{
ColorSettings::ColorSettings(const QPalette &pal)
{
init(pal);
}
void ColorSettings::update(const QPalette &pal)
{
init(pal);
}
void ColorSettings::init(const QPalette &pal)
{
m_palette = pal;
KConfigGroup wmConfig(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), QStringLiteral("WM"));
m_activeFrameColor = wmConfig.readEntry("frame", pal.color(QPalette::Active, QPalette::Background));
m_inactiveFrameColor = wmConfig.readEntry("inactiveFrame", m_activeFrameColor);
m_activeTitleBarColor = wmConfig.readEntry("activeBackground", pal.color(QPalette::Active, QPalette::Highlight));
m_inactiveTitleBarColor = wmConfig.readEntry("inactiveBackground", m_inactiveFrameColor);
m_activeTitleBarBlendColor = wmConfig.readEntry("activeBlend", m_activeTitleBarColor.dark(110));
m_inactiveTitleBarBlendColor = wmConfig.readEntry("inactiveBlend", m_inactiveTitleBarColor.dark(110));
m_activeFontColor = wmConfig.readEntry("activeForeground", pal.color(QPalette::Active, QPalette::HighlightedText));
m_inactiveFontColor = wmConfig.readEntry("inactiveForeground", m_activeFontColor.dark());
m_activeButtonColor = wmConfig.readEntry("activeTitleBtnBg", m_activeFrameColor.light(130));
m_inactiveButtonColor = wmConfig.readEntry("inactiveTitleBtnBg", m_inactiveFrameColor.light(130));
m_activeHandle = wmConfig.readEntry("handle", m_activeFrameColor);
m_inactiveHandle = wmConfig.readEntry("inactiveHandle", m_activeHandle);
}
DecorationOptions::DecorationOptions(QObject *parent)
: QObject(parent)
, m_active(true)
, m_decoration(nullptr)
, m_colors(ColorSettings(QPalette()))
{
connect(this, &DecorationOptions::decorationChanged, this, &DecorationOptions::slotActiveChanged);
connect(this, &DecorationOptions::decorationChanged, this, &DecorationOptions::colorsChanged);
connect(this, &DecorationOptions::decorationChanged, this, &DecorationOptions::fontChanged);
connect(KDecoration2::DecorationSettings::self(), &KDecoration2::DecorationSettings::fontChanged, this, &DecorationOptions::fontChanged);
connect(KDecoration2::DecorationSettings::self(), &KDecoration2::DecorationSettings::decorationButtonsLeftChanged, this, &DecorationOptions::titleButtonsChanged);
connect(KDecoration2::DecorationSettings::self(), &KDecoration2::DecorationSettings::decorationButtonsRightChanged, this, &DecorationOptions::titleButtonsChanged);
}
DecorationOptions::~DecorationOptions()
@ -36,89 +72,101 @@ DecorationOptions::~DecorationOptions()
QColor DecorationOptions::borderColor() const
{
return KDecoration::options()->color(KDecorationDefines::ColorFrame, m_active);
return m_active ? m_colors.activeFrame() : m_colors.inactiveFrame();
}
QColor DecorationOptions::buttonColor() const
{
return KDecoration::options()->color(KDecorationDefines::ColorButtonBg, m_active);
return m_active ? m_colors.activeButtonColor() : m_colors.inactiveButtonColor();
}
QColor DecorationOptions::fontColor() const
{
return KDecoration::options()->color(KDecorationDefines::ColorFont, m_active);
return m_active ? m_colors.activeFont() : m_colors.inactiveFont();
}
QColor DecorationOptions::resizeHandleColor() const
{
return KDecoration::options()->color(KDecorationDefines::ColorHandle, m_active);
return m_active ? m_colors.activeHandle() : m_colors.inactiveHandle();
}
QColor DecorationOptions::titleBarBlendColor() const
{
return KDecoration::options()->color(KDecorationDefines::ColorTitleBlend, m_active);
return m_active ? m_colors.activeTitleBarBlendColor() : m_colors.inactiveTitleBarBlendColor();
}
QColor DecorationOptions::titleBarColor() const
{
return KDecoration::options()->color(KDecorationDefines::ColorTitleBar, m_active);
return m_active ? m_colors.activeTitleBarColor() : m_colors.inactiveTitleBarColor();
}
QFont DecorationOptions::titleFont() const
{
return KDecoration::options()->font(m_active);
return KDecoration2::DecorationSettings::self()->font();
}
static int decorationButton(KDecoration2::DecorationButtonType type)
{
switch (type) {
case KDecoration2::DecorationButtonType::Menu:
return DecorationOptions::DecorationButtonMenu;
case KDecoration2::DecorationButtonType::ApplicationMenu:
return DecorationOptions::DecorationButtonApplicationMenu;
case KDecoration2::DecorationButtonType::OnAllDesktops:
return DecorationOptions::DecorationButtonOnAllDesktops;
case KDecoration2::DecorationButtonType::Minimize:
return DecorationOptions::DecorationButtonMinimize;
case KDecoration2::DecorationButtonType::Maximize:
return DecorationOptions::DecorationButtonMaximizeRestore;
case KDecoration2::DecorationButtonType::Close:
return DecorationOptions::DecorationButtonClose;
case KDecoration2::DecorationButtonType::QuickHelp:
return DecorationOptions::DecorationButtonQuickHelp;
case KDecoration2::DecorationButtonType::Shade:
return DecorationOptions::DecorationButtonShade;
case KDecoration2::DecorationButtonType::KeepBelow:
return DecorationOptions::DecorationButtonKeepBelow;
case KDecoration2::DecorationButtonType::KeepAbove:
return DecorationOptions::DecorationButtonKeepAbove;
default:
return DecorationOptions::DecorationButtonNone;
}
}
QList<int> DecorationOptions::titleButtonsLeft() const
{
QList<KDecorationDefines::DecorationButton> buttons;
if (KDecoration::options()->customButtonPositions()) {
buttons = KDecoration::options()->titleButtonsLeft();
} else {
buttons = KDecorationOptions::defaultTitleButtonsLeft();
}
QList<int> ret;
for (auto it : buttons) {
ret << static_cast<int>(it);
for (auto it : KDecoration2::DecorationSettings::self()->decorationButtonsLeft()) {
ret << decorationButton(it);
}
return ret;
}
QList<int> DecorationOptions::titleButtonsRight() const
{
QList<KDecorationDefines::DecorationButton> buttons;
if (KDecoration::options()->customButtonPositions()) {
buttons = KDecoration::options()->titleButtonsRight();
} else {
buttons = KDecorationOptions::defaultTitleButtonsRight();
}
QList<int> ret;
for (auto it : buttons) {
ret << static_cast<int>(it);
for (auto it : KDecoration2::DecorationSettings::self()->decorationButtonsRight()) {
ret << decorationButton(it);
}
return ret;
}
QObject *DecorationOptions::decoration() const
KDecoration2::Decoration *DecorationOptions::decoration() const
{
return m_decoration;
}
void DecorationOptions::setDecoration(QObject *decoration)
void DecorationOptions::setDecoration(KDecoration2::Decoration *decoration)
{
if (m_decoration == decoration) {
return;
}
if (m_decoration) {
// disconnect from existing decoration
disconnect(m_decoration, SIGNAL(activeChanged()), this, SLOT(slotActiveChanged()));
disconnect(m_decoration, SIGNAL(buttonsChanged()), this, SIGNAL(titleButtonsChanged()));
disconnect(m_decoration, SIGNAL(fontChanged()), this, SIGNAL(fontChanged()));
disconnect(m_decoration->client().data(), &KDecoration2::DecoratedClient::activeChanged, this, &DecorationOptions::slotActiveChanged);
}
m_decoration = decoration;
connect(m_decoration, SIGNAL(activeChanged()), SLOT(slotActiveChanged()));
connect(m_decoration, SIGNAL(buttonsChanged()), SIGNAL(titleButtonsChanged()));
connect(m_decoration, SIGNAL(fontChanged()), SIGNAL(fontChanged()));
connect(m_decoration->client().data(), &KDecoration2::DecoratedClient::activeChanged, this, &DecorationOptions::slotActiveChanged);
emit decorationChanged();
}
@ -127,10 +175,10 @@ void DecorationOptions::slotActiveChanged()
if (!m_decoration) {
return;
}
if (m_active == m_decoration->property("active").toBool()) {
if (m_active == m_decoration->client()->isActive()) {
return;
}
m_active = m_decoration->property("active").toBool();
m_active = m_decoration->client()->isActive();
emit colorsChanged();
emit fontChanged();
}

View file

@ -17,13 +17,89 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_DECORATION_OPTIONS_H
#define KWIN_DECORATION_OPTIONS_H
#include <KDecoration2/Decoration>
#include <QObject>
#include <QColor>
#include <QFont>
#include <QPalette>
namespace KWin
{
// TODO: move to deco API
class ColorSettings
{
public:
ColorSettings(const QPalette &pal);
void update(const QPalette &pal);
const QColor &titleBarColor(bool active) const {
return active ? m_activeTitleBarColor : m_inactiveTitleBarColor;
}
const QColor &activeTitleBarColor() const {
return m_activeTitleBarColor;
}
const QColor &inactiveTitleBarColor() const {
return m_inactiveTitleBarColor;
}
const QColor &activeTitleBarBlendColor() const {
return m_activeTitleBarBlendColor;
}
const QColor &inactiveTitleBarBlendColor() const {
return m_inactiveTitleBarBlendColor;
}
const QColor &frame(bool active) const {
return active ? m_activeFrameColor : m_inactiveFrameColor;
}
const QColor &activeFrame() const {
return m_activeFrameColor;
}
const QColor &inactiveFrame() const {
return m_inactiveFrameColor;
}
const QColor &font(bool active) const {
return active ? m_activeFontColor : m_inactiveFontColor;
}
const QColor &activeFont() const {
return m_activeFontColor;
}
const QColor &inactiveFont() const {
return m_inactiveFontColor;
}
const QColor &activeButtonColor() const {
return m_activeButtonColor;
}
const QColor &inactiveButtonColor() const {
return m_inactiveButtonColor;
}
const QColor &activeHandle() const {
return m_activeHandle;
}
const QColor &inactiveHandle() const {
return m_inactiveHandle;
}
const QPalette &palette() const {
return m_palette;
}
private:
void init(const QPalette &pal);
QColor m_activeTitleBarColor;
QColor m_inactiveTitleBarColor;
QColor m_activeTitleBarBlendColor;
QColor m_inactiveTitleBarBlendColor;
QColor m_activeFrameColor;
QColor m_inactiveFrameColor;
QColor m_activeFontColor;
QColor m_inactiveFontColor;
QColor m_activeButtonColor;
QColor m_inactiveButtonColor;
QColor m_activeHandle;
QColor m_inactiveHandle;
QPalette m_palette;
};
/**
* @short Common Window Decoration Options.
*
@ -60,7 +136,7 @@ class DecorationOptions : public QObject
*
* Best pass the decoration object available as a context property to this property.
**/
Q_PROPERTY(QObject *deco READ decoration WRITE setDecoration NOTIFY decorationChanged)
Q_PROPERTY(KDecoration2::Decoration *deco READ decoration WRITE setDecoration NOTIFY decorationChanged)
/**
* The color for the titlebar depending on the decoration's active state.
**/
@ -149,8 +225,8 @@ public:
QFont titleFont() const;
QList<int> titleButtonsLeft() const;
QList<int> titleButtonsRight() const;
QObject *decoration() const;
void setDecoration(QObject *decoration);
KDecoration2::Decoration *decoration() const;
void setDecoration(KDecoration2::Decoration *decoration);
Q_SIGNALS:
void colorsChanged();
@ -163,7 +239,8 @@ private Q_SLOTS:
private:
bool m_active;
QObject *m_decoration;
KDecoration2::Decoration *m_decoration;
ColorSettings m_colors;
};
class Borders : public QObject

View file

@ -21,9 +21,9 @@ import org.kde.kwin.decoration 0.1
DecorationButton {
id: appMenuButton
buttonType: DecorationOptions.DecorationButtonApplicationMenu
visible: decoration.appMenu
visible: false //decoration.appMenu
KQuickControlsAddons.QIconItem {
icon: decoration.icon
icon: decoration.client.icon
anchors.fill: parent
}
}

View file

@ -103,7 +103,7 @@ DecorationButton {
}
PlasmaCore.FrameSvgItem {
id: buttonActive
property bool shown: (decoration.active || !buttonSvg.supportsInactive) && ((!pressed && !toggled) || !buttonSvg.supportsPressed) && (!hovered || !buttonSvg.supportsHover) && (enabled || !buttonSvg.supportsDeactivated)
property bool shown: (decoration.client.active || !buttonSvg.supportsInactive) && ((!pressed && !toggled) || !buttonSvg.supportsPressed) && (!hovered || !buttonSvg.supportsHover) && (enabled || !buttonSvg.supportsDeactivated)
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "active"
@ -116,7 +116,7 @@ DecorationButton {
}
PlasmaCore.FrameSvgItem {
id: buttonActiveHover
property bool shown: hovered && !pressed && !toggled && buttonSvg.supportsHover && (decoration.active || !buttonSvg.supportsInactiveHover)
property bool shown: hovered && !pressed && !toggled && buttonSvg.supportsHover && (decoration.client.active || !buttonSvg.supportsInactiveHover)
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "hover"
@ -129,7 +129,7 @@ DecorationButton {
}
PlasmaCore.FrameSvgItem {
id: buttonActivePressed
property bool shown: (toggled || pressed) && buttonSvg.supportsPressed && (decoration.active || !buttonSvg.supportsInactivePressed)
property bool shown: (toggled || pressed) && buttonSvg.supportsPressed && (decoration.client.active || !buttonSvg.supportsInactivePressed)
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "pressed"
@ -142,7 +142,7 @@ DecorationButton {
}
PlasmaCore.FrameSvgItem {
id: buttonActiveDeactivated
property bool shown: !enabled && buttonSvg.supportsDeactivated && (decoration.active || !buttonSvg.supportsInactiveDeactivated)
property bool shown: !enabled && buttonSvg.supportsDeactivated && (decoration.client.active || !buttonSvg.supportsInactiveDeactivated)
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "deactivated"
@ -155,7 +155,7 @@ DecorationButton {
}
PlasmaCore.FrameSvgItem {
id: buttonInactive
property bool shown: !decoration.active && buttonSvg.supportsInactive && !hovered && !pressed && !toggled && enabled
property bool shown: !decoration.client.active && buttonSvg.supportsInactive && !hovered && !pressed && !toggled && enabled
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "inactive"
@ -168,7 +168,7 @@ DecorationButton {
}
PlasmaCore.FrameSvgItem {
id: buttonInactiveHover
property bool shown: !decoration.active && hovered && !pressed && !toggled && buttonSvg.supportsInactiveHover
property bool shown: !decoration.client.active && hovered && !pressed && !toggled && buttonSvg.supportsInactiveHover
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "hover-inactive"
@ -181,7 +181,7 @@ DecorationButton {
}
PlasmaCore.FrameSvgItem {
id: buttonInactivePressed
property bool shown: !decoration.active && (toggled || pressed) && buttonSvg.supportsInactivePressed
property bool shown: !decoration.client.active && (toggled || pressed) && buttonSvg.supportsInactivePressed
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "pressed-inactive"
@ -194,7 +194,7 @@ DecorationButton {
}
PlasmaCore.FrameSvgItem {
id: buttonInactiveDeactivated
property bool shown: !decoration.active && !enabled && buttonSvg.supportsInactiveDeactivated
property bool shown: !decoration.client.active && !enabled && buttonSvg.supportsInactiveDeactivated
anchors.fill: parent
imagePath: buttonSvg.imagePath
prefix: "deactivated-inactive"

View file

@ -55,6 +55,6 @@ Item {
}
anchors {
top: root.top
topMargin: (decoration.maximized ? auroraeTheme.titleEdgeTopMaximized : auroraeTheme.titleEdgeTop + root.padding.top) + auroraeTheme.buttonMarginTop
topMargin: (decoration.client.maximized ? auroraeTheme.titleEdgeTopMaximized : auroraeTheme.titleEdgeTop + root.padding.top) + auroraeTheme.buttonMarginTop
}
}

View file

@ -28,7 +28,7 @@ Item {
id: maximizeButton
anchors.fill: parent
buttonType: DecorationOptions.DecorationButtonMaximizeRestore
opacity: (!decoration.maximized || auroraeTheme.restoreButtonPath == "") ? 1 : 0
opacity: (!decoration.client.maximized || auroraeTheme.restoreButtonPath == "") ? 1 : 0
hovered: button.hovered
pressed: button.pressed
toggled: button.toggled
@ -42,7 +42,7 @@ Item {
id: restoreButton
anchors.fill: parent
buttonType: DecorationOptions.DecorationButtonMaximizeRestore + 100
opacity: (decoration.maximized && auroraeTheme.restoreButtonPath != "") ? 1 : 0
opacity: (decoration.client.maximized && auroraeTheme.restoreButtonPath != "") ? 1 : 0
hovered: button.hovered
pressed: button.pressed
toggled: button.toggled
@ -63,7 +63,7 @@ Item {
onPressed: button.pressed = true
onReleased: button.pressed = false
onClicked: {
decoration.maximize(mouse.button);
decoration.requestMaximize(mouse.button);
}
}
}

View file

@ -31,11 +31,6 @@ Item {
objectName: "padding"
}
property bool alpha: true
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPressed: decoration.titlePressed(mouse.button, mouse.buttons)
onDoubleClicked: decoration.titlebarDblClickOperation()
}
width: decoration.client.width + decoration.borderLeft + decoration.borderRight
height: decoration.client.height + decoration.borderTop + decoration.borderBottom
}

View file

@ -26,11 +26,11 @@ Item {
enabled: {
switch (button.buttonType) {
case DecorationOptions.DecorationButtonClose:
return decoration.closeable;
return decoration.client.closeable;
case DecorationOptions.DecorationButtonMaximizeRestore:
return decoration.maximizeable;
return decoration.client.maximizeable;
case DecorationOptions.DecorationButtonMinimize:
return decoration.minimizeable;
return decoration.client.minimizeable;
case DecorationOptions.DecorationButtonExplicitSpacer:
return false;
default:
@ -58,93 +58,93 @@ Item {
switch (button.buttonType) {
case DecorationOptions.DecorationButtonMenu:
// menu
decoration.menuClicked();
decoration.requestShowWindowMenu();
break;
case DecorationOptions.DecorationButtonApplicationMenu:
// app menu
decoration.appMenuClicked();
// decoration.appMenuClicked();
break;
case DecorationOptions.DecorationButtonOnAllDesktops:
// all desktops
decoration.toggleOnAllDesktops();
decoration.requestToggleOnAllDesktops();
break;
case DecorationOptions.DecorationButtonQuickHelp:
// help
decoration.showContextHelp();
decoration.requestContextHelp();
break;
case DecorationOptions.DecorationButtonMinimize:
// minimize
decoration.minimize();
decoration.requestMinimize();
break;
case DecorationOptions.DecorationButtonMaximizeRestore:
// maximize
decoration.maximize(mouse.button);
decoration.requestMaximize(mouse.button);
break;
case DecorationOptions.DecorationButtonClose:
// close
decoration.closeWindow();
decoration.requestClose();
break;
case DecorationOptions.DecorationButtonKeepAbove:
// keep above
decoration.toggleKeepAbove();
decoration.requestToggleKeepAbove();
break;
case DecorationOptions.DecorationButtonKeepBelow:
// keep below
decoration.toggleKeepBelow();
decoration.requestToggleKeepBelow();
break;
case DecorationOptions.DecorationButtonShade:
// shade
decoration.toggleShade();
decoration.requestToggleShade();
break;
}
}
onDoubleClicked: {
if (button.buttonType == DecorationOptions.DecorationButtonMenu) {
decoration.closeWindow();
decoration.requestClose();
}
}
Component.onCompleted: {
switch (button.buttonType) {
case DecorationOptions.DecorationButtonOnAllDesktops:
// all desktops
button.toggled = decoration.onAllDesktops;
button.toggled = decoration.client.onAllDesktops;
break;
case DecorationOptions.DecorationButtonKeepAbove:
button.toggled = decoration.keepAbove;
button.toggled = decoration.client.keepAbove;
break;
case DecorationOptions.DecorationButtonKeepBelow:
button.toggled = decoration.keepBelow;
button.toggled = decoration.client.keepBelow;
break;
case DecorationOptions.DecorationButtonShade:
button.toggled = decoration.shade;
button.toggled = decoration.client.shaded;
break;
}
}
Connections {
target: decoration
onShadeChanged: {
target: decoration.client
onShadedChanged: {
if (button.buttonType != DecorationOptions.DecorationButtonShade) {
return;
}
button.toggled = decoration.shade;
button.toggled = decoration.client.shaded;
}
onKeepBelowChanged: {
if (button.buttonType != DecorationOptions.DecorationButtonKeepBelow) {
return;
}
button.toggled = decoration.keepBelow;
button.toggled = decoration.client.keepBelow;
}
onKeepAboveChanged: {
if (button.buttonType != DecorationOptions.DecorationButtonKeepAbove) {
return;
}
button.toggled = decoration.keepAbove;
button.toggled = decoration.client.keepAbove;
}
onDesktopChanged: {
if (button.buttonType != DecorationOptions.DecorationButtonOnAllDesktops) {
return;
}
button.toggled = decoration.onAllDesktops;
button.toggled = decoration.client.onAllDesktops;
}
}
}

View file

@ -23,14 +23,14 @@ DecorationButton {
id: menuButton
buttonType: DecorationOptions.DecorationButtonMenu
KQuickControlsAddons.QIconItem {
icon: decoration.icon
icon: decoration.client.icon
anchors.fill: parent
}
Timer {
id: timer
interval: 150
repeat: false
onTriggered: decoration.menuClicked()
onTriggered: decoration.requestShowWindowMenu()
}
MouseArea {
anchors.fill: parent
@ -64,13 +64,13 @@ DecorationButton {
// for right clicks we show the menu instantly
// and if the option is disabled we always show menu directly
if (!menuButton.closeOnDoubleClick || mouse.button == Qt.RightButton) {
decoration.menuClicked();
decoration.requestShowWindowMenu();
timer.stop();
}
}
onDoubleClicked: {
if (menuButton.closeOnDoubleClick) {
decoration.closeWindow();
decoration.requestClose();
}
}
}

View file

@ -40,6 +40,16 @@ Decoration {
id: options
deco: decoration
}
Item {
id: titleRect
x: decoration.client.maximized ? maximizedBorders.left : borders.left
y: 0
width: decoration.client.width//parent.width - x - (decoration.client.maximized ? maximizedBorders.right : borders.right)
height: decoration.client.maximized ? maximizedBorders.top : borders.top
Component.onCompleted: {
decoration.installTitleItem(titleRect);
}
}
PlasmaCore.FrameSvg {
property bool supportsInactive: hasElementPrefix("decoration-inactive")
property bool supportsMaximized: hasElementPrefix("decoration-maximized")
@ -51,12 +61,12 @@ Decoration {
}
PlasmaCore.FrameSvgItem {
id: decorationActive
property bool shown: (!decoration.maxized || !backgroundSvg.supportsMaximized) && (decoration.active || !backgroundSvg.supportsInactive)
property bool shown: (!decoration.client.maxized || !backgroundSvg.supportsMaximized) && (decoration.client.active || !backgroundSvg.supportsInactive)
anchors.fill: parent
imagePath: backgroundSvg.imagePath
prefix: "decoration"
opacity: shown ? 1 : 0
enabledBorders: decoration.maximized ? PlasmaCore.FrameSvg.NoBorder : PlasmaCore.FrameSvg.TopBorder | PlasmaCore.FrameSvg.BottomBorder | PlasmaCore.FrameSvg.LeftBorder | PlasmaCore.FrameSvg.RightBorder
enabledBorders: decoration.client.maximized ? PlasmaCore.FrameSvg.NoBorder : PlasmaCore.FrameSvg.TopBorder | PlasmaCore.FrameSvg.BottomBorder | PlasmaCore.FrameSvg.LeftBorder | PlasmaCore.FrameSvg.RightBorder
Behavior on opacity {
enabled: root.animate
NumberAnimation {
@ -69,8 +79,8 @@ Decoration {
anchors.fill: parent
imagePath: backgroundSvg.imagePath
prefix: "decoration-inactive"
opacity: (!decoration.active && backgroundSvg.supportsInactive) ? 1 : 0
enabledBorders: decoration.maximized ? PlasmaCore.FrameSvg.NoBorder : PlasmaCore.FrameSvg.TopBorder | PlasmaCore.FrameSvg.BottomBorder | PlasmaCore.FrameSvg.LeftBorder | PlasmaCore.FrameSvg.RightBorder
opacity: (!decoration.client.active && backgroundSvg.supportsInactive) ? 1 : 0
enabledBorders: decoration.client.maximized ? PlasmaCore.FrameSvg.NoBorder : PlasmaCore.FrameSvg.TopBorder | PlasmaCore.FrameSvg.BottomBorder | PlasmaCore.FrameSvg.LeftBorder | PlasmaCore.FrameSvg.RightBorder
Behavior on opacity {
enabled: root.animate
NumberAnimation {
@ -80,7 +90,7 @@ Decoration {
}
PlasmaCore.FrameSvgItem {
id: decorationMaximized
property bool shown: decoration.maximized && backgroundSvg.supportsMaximized && (decoration.active || !backgroundSvg.supportsMaximizedInactive)
property bool shown: decoration.client.maximized && backgroundSvg.supportsMaximized && (decoration.client.active || !backgroundSvg.supportsMaximizedInactive)
anchors {
left: parent.left
right: parent.right
@ -114,7 +124,7 @@ Decoration {
imagePath: backgroundSvg.imagePath
prefix: "decoration-maximized-inactive"
height: parent.maximizedBorders.top
opacity: (!decoration.active && decoration.maximized && backgroundSvg.supportsMaximizedInactive) ? 1 : 0
opacity: (!decoration.client.active && decoration.client.maximized && backgroundSvg.supportsMaximizedInactive) ? 1 : 0
enabledBorders: PlasmaCore.FrameSvg.NoBorder
Behavior on opacity {
enabled: root.animate
@ -130,7 +140,7 @@ Decoration {
animate: root.animate
anchors {
left: root.left
leftMargin: decoration.maximized ? auroraeTheme.titleEdgeLeftMaximized : (auroraeTheme.titleEdgeLeft + root.padding.left)
leftMargin: decoration.client.maximized ? auroraeTheme.titleEdgeLeftMaximized : (auroraeTheme.titleEdgeLeft + root.padding.left)
}
}
AuroraeButtonGroup {
@ -140,40 +150,28 @@ Decoration {
animate: root.animate
anchors {
right: root.right
rightMargin: decoration.maximized ? auroraeTheme.titleEdgeRightMaximized : (auroraeTheme.titleEdgeRight + root.padding.right)
rightMargin: decoration.client.maximized ? auroraeTheme.titleEdgeRightMaximized : (auroraeTheme.titleEdgeRight + root.padding.right)
}
}
Text {
id: caption
text: decoration.caption
text: decoration.client.caption
textFormat: Text.PlainText
horizontalAlignment: auroraeTheme.horizontalAlignment
verticalAlignment: auroraeTheme.verticalAlignment
elide: Text.ElideRight
height: Math.max(auroraeTheme.titleHeight, auroraeTheme.buttonHeight * auroraeTheme.buttonSizeFactor)
color: decoration.active ? auroraeTheme.activeTextColor : auroraeTheme.inactiveTextColor
color: decoration.client.active ? auroraeTheme.activeTextColor : auroraeTheme.inactiveTextColor
font: options.titleFont
renderType: Text.NativeRendering
anchors {
left: leftButtonGroup.right
right: rightButtonGroup.left
top: root.top
topMargin: decoration.maximized ? auroraeTheme.titleEdgeTopMaximized : (auroraeTheme.titleEdgeTop + root.padding.top)
topMargin: decoration.client.maximized ? auroraeTheme.titleEdgeTopMaximized : (auroraeTheme.titleEdgeTop + root.padding.top)
leftMargin: auroraeTheme.titleBorderLeft
rightMargin: auroraeTheme.titleBorderRight
}
MouseArea {
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
anchors.fill: parent
onDoubleClicked: decoration.titlebarDblClickOperation()
onPressed: {
if (mouse.button == Qt.LeftButton) {
mouse.accepted = false;
} else {
decoration.titlePressed(mouse.button, mouse.buttons);
}
}
}
Behavior on color {
enabled: root.animate
ColorAnimation {
@ -192,7 +190,7 @@ Decoration {
}
imagePath: backgroundSvg.imagePath
prefix: "innerborder"
opacity: (decoration.active && !decoration.maximized && backgroundSvg.supportsInnerBorder) ? 1 : 0
opacity: (decoration.client.active && !decoration.client.maximized && backgroundSvg.supportsInnerBorder) ? 1 : 0
Behavior on opacity {
enabled: root.animate
NumberAnimation {
@ -211,7 +209,7 @@ Decoration {
}
imagePath: backgroundSvg.imagePath
prefix: "innerborder-inactive"
opacity: (!decoration.active && !decoration.maximized && backgroundSvg.supportsInnerBorderInactive) ? 1 : 0
opacity: (!decoration.client.active && !decoration.client.maximized && backgroundSvg.supportsInnerBorderInactive) ? 1 : 0
Behavior on opacity {
enabled: root.animate
NumberAnimation {

View file

@ -21,6 +21,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "plastikbutton.h"
#include <kdecoration.h>
#include <KColorScheme>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QPainter>
namespace KWin
@ -118,7 +120,8 @@ QPixmap PlastikButtonProvider::icon(ButtonIcon icon, int size, bool active, bool
QPixmap image(size, size);
image.fill(Qt::transparent);
QPainter p(&image);
const QColor color = KDecoration::options()->color(KDecoration::ColorFont, active);
KConfigGroup wmConfig(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), QStringLiteral("WM"));
const QColor color = wmConfig.readEntry("activeForeground", QPalette().color(QPalette::Active, QPalette::HighlightedText));
if (shadow) {
p.setPen(KColorScheme::shade(color, KColorScheme::ShadowShade));

View file

@ -24,7 +24,7 @@ DecorationButton {
var highlightColor = null;
if (button.pressed) {
if (button.buttonType == DecorationOptions.DecorationButtonClose) {
highlightColor = colorHelper.foreground(decoration.active, ColorHelper.NegativeText);
highlightColor = colorHelper.foreground(decoration.client.active, ColorHelper.NegativeText);
} else {
highlightColor = options.titleBarColor;
}
@ -32,7 +32,7 @@ DecorationButton {
highlightColor = colorHelper.multiplyAlpha(highlightColor, 0.3);
} else if (button.hovered) {
if (button.buttonType == DecorationOptions.DecorationButtonClose) {
highlightColor = colorHelper.foreground(decoration.active, ColorHelper.NegativeText);
highlightColor = colorHelper.foreground(decoration.client.active, ColorHelper.NegativeText);
} else {
highlightColor = options.titleBarColor;
}
@ -114,7 +114,7 @@ DecorationButton {
Item {
property int imageWidth: button.width > 14 ? button.width - 2 * Math.floor(button.width/3.5) : button.width - 6
property int imageHeight: button.height > 14 ? button.height - 2 * Math.floor(button.height/3.5) : button.height - 6
property string source: "image://plastik/" + button.buttonType + "/" + decoration.active + "/" + ((buttonType == "A") ? decoration.maximized : button.toggled)
property string source: "image://plastik/" + button.buttonType + "/" + decoration.client.active + "/" + ((buttonType == "A") ? decoration.client.maximized : button.toggled)
anchors.fill: parent
Image {
id: shadowImage
@ -141,22 +141,18 @@ DecorationButton {
Component.onCompleted: {
colorize();
if (buttonType == DecorationOptions.DecorationButtonQuickHelp) {
visible = decoration.providesContextHelp;
visible = Qt.binding(function() { return decoration.client.providesContextHelp});
}
if (buttonType == DecorationOptions.DecorationButtonApplicationMenu) {
visible = decoration.appMenu;
// visible = decoration.appMenu;
visible = false;
}
}
onHoveredChanged: colorize()
onPressedChanged: colorize()
Connections {
target: decoration
target: decoration.client
onActiveChanged: button.colorize()
onAppMenuChanged: {
if (buttonType == DecorationOptions.DecorationButtonApplicationMenu) {
visible = decoration.appMenu;
}
}
}
Connections {
target: options

View file

@ -107,7 +107,7 @@ Decoration {
fill: parent
}
border {
width: decoration.maximized ? 0 : 2
width: decoration.client.maximized ? 0 : 2
color: colorHelper.shade(root.titleBarColor, ColorHelper.DarkShade)
}
Rectangle {
@ -120,7 +120,7 @@ Decoration {
bottomMargin: 1
topMargin: 1
}
visible: !decoration.maximized
visible: !decoration.client.maximized
width: root.borders.left
color: root.titleBarColor
Rectangle {
@ -130,7 +130,7 @@ Decoration {
top: parent.top
bottom: parent.bottom
}
color: colorHelper.shade(root.titleBarColor, ColorHelper.LightShade, colorHelper.contrast - (decoration.active ? 0.4 : 0.8))
color: colorHelper.shade(root.titleBarColor, ColorHelper.LightShade, colorHelper.contrast - (decoration.client.active ? 0.4 : 0.8))
}
}
Rectangle {
@ -143,7 +143,7 @@ Decoration {
bottomMargin: 1
topMargin: 1
}
visible: !decoration.maximzied
visible: !decoration.client.maximzied
width: root.borders.right -1
color: root.titleBarColor
Rectangle {
@ -153,7 +153,7 @@ Decoration {
top: parent.top
}
x: parent.x + parent.width - 1
color: colorHelper.shade(root.titleBarColor, ColorHelper.DarkShade, colorHelper.contrast - (decoration.active ? 0.4 : 0.8))
color: colorHelper.shade(root.titleBarColor, ColorHelper.DarkShade, colorHelper.contrast - (decoration.client.active ? 0.4 : 0.8))
}
}
Rectangle {
@ -166,7 +166,7 @@ Decoration {
rightMargin: 1
}
height: root.borders.bottom
visible: !decoration.maximzied
visible: !decoration.client.maximzied
color: root.titleBarColor
Rectangle {
height: 1
@ -175,7 +175,7 @@ Decoration {
right: parent.right
}
y: parent.y + parent.height - 1
color: colorHelper.shade(root.titleBarColor, ColorHelper.DarkShade, colorHelper.contrast - (decoration.active ? 0.4 : 0.8))
color: colorHelper.shade(root.titleBarColor, ColorHelper.DarkShade, colorHelper.contrast - (decoration.client.active ? 0.4 : 0.8))
}
}
@ -184,14 +184,14 @@ Decoration {
property int topMargin: 1
property real normalHeight: titleRow.normalHeight + topMargin + 1
property real maximizedHeight: titleRow.maximizedHeight + 1
height: decoration.maximized ? maximizedHeight : normalHeight
height: decoration.client.maximized ? maximizedHeight : normalHeight
anchors {
left: parent.left
right: parent.right
top: parent.top
topMargin: decoration.maximized ? 0 : top.topMargin
leftMargin: decoration.maximized ? 0 : 2
rightMargin: decoration.maximized ? 0 : 2
topMargin: decoration.client.maximized ? 0 : top.topMargin
leftMargin: decoration.client.maximized ? 0 : 2
rightMargin: decoration.client.maximized ? 0 : 2
}
gradient: Gradient {
id: topGradient
@ -201,7 +201,7 @@ Decoration {
}
GradientStop {
id: middleGradientStop
position: 4.0/(decoration.maximized ? top.maximizedHeight : top.normalHeight)
position: 4.0/(decoration.client.maximized ? top.maximizedHeight : top.normalHeight)
color: colorHelper.shade(root.titleBarColor, ColorHelper.MidShade, colorHelper.contrast - 0.4)
}
GradientStop {
@ -216,21 +216,8 @@ Decoration {
left: top.left
right: top.right
}
visible: !decoration.maximized
color: colorHelper.shade(root.titleBarColor, ColorHelper.LightShade, colorHelper.contrast - (decoration.active ? 0.4 : 0.8))
}
MouseArea {
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
anchors.fill: parent
onDoubleClicked: decoration.titlebarDblClickOperation()
onPressed: {
if (mouse.button == Qt.LeftButton) {
mouse.accepted = false;
} else {
decoration.titlePressed(mouse.button, mouse.buttons);
}
}
onReleased: decoration.titleReleased(mouse.button, mouse.buttons)
visible: !decoration.client.maximized
color: colorHelper.shade(root.titleBarColor, ColorHelper.LightShade, colorHelper.contrast - (decoration.client.active ? 0.4 : 0.8))
}
Item {
@ -244,9 +231,9 @@ Decoration {
left: parent.left
right: parent.right
top: parent.top
topMargin: decoration.maximized ? 0 : titleRow.topMargin
leftMargin: decoration.maximized ? 0 : 3
rightMargin: decoration.maximized ? 0 : 3
topMargin: decoration.client.maximized ? 0 : titleRow.topMargin
leftMargin: decoration.client.maximized ? 0 : 3
rightMargin: decoration.client.maximized ? 0 : 3
bottomMargin: titleRow.bottomMargin
}
ButtonGroup {
@ -284,7 +271,7 @@ Decoration {
Behavior on color {
ColorAnimation { duration: root.animationDuration }
}
text: decoration.caption
text: decoration.client.caption
font: options.titleFont
style: root.titleShadow ? Text.Raised : Text.Normal
styleColor: colorHelper.shade(color, ColorHelper.ShadowShade)
@ -311,6 +298,9 @@ Decoration {
right: parent.right
}
}
Component.onCompleted: {
decoration.installTitleItem(titleRow);
}
}
}
@ -325,7 +315,7 @@ Decoration {
}
height: 1
y: top.height - 1
visible: decoration.maximized
visible: decoration.client.maximized
color: colorHelper.shade(root.titleBarColor, ColorHelper.MidShade)
}
@ -341,7 +331,7 @@ Decoration {
width: 1
color: colorHelper.shade(root.titleBarColor, ColorHelper.MidShade)
}
visible: !decoration.maximized
visible: !decoration.client.maximized
color: root.titleBarColor
}
}
@ -423,8 +413,4 @@ Decoration {
maximizedBorders.setTitle(top.maximizedHeight);
readConfig();
}
Connections {
target: decoration
onConfigChanged: readConfig()
}
}