2009-06-19 09:18:07 +00:00
|
|
|
/********************************************************************
|
2012-01-07 16:05:22 +00:00
|
|
|
Copyright (C) 2009, 2010, 2012 Martin Gräßlin <mgraesslin@kde.org>
|
2009-06-19 09:18:07 +00:00
|
|
|
|
|
|
|
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) any later version.
|
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
|
|
|
|
|
|
|
#include "aurorae.h"
|
2010-04-12 19:28:58 +00:00
|
|
|
#include "auroraetheme.h"
|
2012-07-22 15:35:18 +00:00
|
|
|
#include "config-kwin.h"
|
2014-06-18 07:06:49 +00:00
|
|
|
// qml imports
|
|
|
|
#include "decorationoptions.h"
|
2014-10-24 11:48:31 +00:00
|
|
|
// KDecoration2
|
|
|
|
#include <KDecoration2/DecoratedClient>
|
|
|
|
#include <KDecoration2/DecorationSettings>
|
2014-10-27 11:45:05 +00:00
|
|
|
#include <KDecoration2/DecorationShadow>
|
2014-10-24 11:48:31 +00:00
|
|
|
// KDE
|
|
|
|
#include <KConfigGroup>
|
2014-12-05 12:44:16 +00:00
|
|
|
#include <KConfigLoader>
|
|
|
|
#include <KConfigDialogManager>
|
2014-10-28 08:57:38 +00:00
|
|
|
#include <KDesktopFile>
|
2014-12-05 12:44:16 +00:00
|
|
|
#include <KLocalizedTranslator>
|
2014-10-24 11:48:31 +00:00
|
|
|
#include <KPluginFactory>
|
|
|
|
#include <KSharedConfig>
|
|
|
|
#include <KService>
|
|
|
|
#include <KServiceTypeTrader>
|
|
|
|
// Qt
|
2013-09-02 09:12:14 +00:00
|
|
|
#include <QDebug>
|
2014-06-18 07:06:49 +00:00
|
|
|
#include <QDirIterator>
|
2014-12-03 15:22:15 +00:00
|
|
|
#include <QOffscreenSurface>
|
|
|
|
#include <QOpenGLContext>
|
2013-10-02 12:54:43 +00:00
|
|
|
#include <QOpenGLFramebufferObject>
|
|
|
|
#include <QPainter>
|
2014-10-24 11:48:31 +00:00
|
|
|
#include <QQuickItem>
|
2014-12-03 15:22:15 +00:00
|
|
|
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
|
|
|
#define HAVE_RENDER_CONTROL 1
|
|
|
|
#else
|
|
|
|
#define HAVE_RENDER_CONTROL 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if HAVE_RENDER_CONTROL
|
|
|
|
#include <QQuickRenderControl>
|
|
|
|
#endif
|
2014-10-24 11:48:31 +00:00
|
|
|
#include <QQuickWindow>
|
2013-10-02 08:04:10 +00:00
|
|
|
#include <QQmlComponent>
|
|
|
|
#include <QQmlContext>
|
|
|
|
#include <QQmlEngine>
|
2013-08-03 20:29:13 +00:00
|
|
|
#include <QStandardPaths>
|
2014-12-03 15:22:15 +00:00
|
|
|
#include <QTimer>
|
2014-12-05 12:44:16 +00:00
|
|
|
#include <QUiLoader>
|
|
|
|
#include <QVBoxLayout>
|
2009-06-19 09:18:07 +00:00
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
K_PLUGIN_FACTORY_WITH_JSON(AuroraeDecoFactory,
|
2014-03-12 13:53:43 +00:00
|
|
|
"aurorae.json",
|
2014-10-28 08:57:38 +00:00
|
|
|
registerPlugin<Aurorae::Decoration>();
|
|
|
|
registerPlugin<Aurorae::ThemeFinder>(QStringLiteral("themes"));
|
2014-12-05 12:44:16 +00:00
|
|
|
registerPlugin<Aurorae::ConfigurationModule>(QStringLiteral("kcmodule"));
|
2014-10-28 08:57:38 +00:00
|
|
|
)
|
2014-02-21 09:48:24 +00:00
|
|
|
|
2009-06-19 09:18:07 +00:00
|
|
|
namespace Aurorae
|
|
|
|
{
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
class Helper
|
2009-06-19 09:18:07 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
public:
|
|
|
|
void ref();
|
|
|
|
void unref();
|
|
|
|
QQmlComponent *component(const QString &theme);
|
|
|
|
QQmlContext *rootContext();
|
|
|
|
QQmlComponent *svgComponent() {
|
|
|
|
return m_svgComponent.data();
|
|
|
|
}
|
2009-06-19 09:18:07 +00:00
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
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()
|
2009-06-19 09:18:07 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
static Helper s_helper;
|
|
|
|
return s_helper;
|
|
|
|
}
|
2011-12-05 14:29:26 +00:00
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Helper::ref()
|
|
|
|
{
|
|
|
|
m_refCount++;
|
|
|
|
if (m_refCount == 1) {
|
|
|
|
m_engine.reset(new QQmlEngine);
|
|
|
|
init();
|
2014-06-18 07:06:49 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
}
|
2014-06-18 07:06:49 +00:00
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Helper::unref()
|
|
|
|
{
|
|
|
|
m_refCount--;
|
|
|
|
if (m_refCount == 0) {
|
|
|
|
// cleanup
|
|
|
|
m_svgComponent.reset();
|
|
|
|
m_engine.reset();
|
|
|
|
m_components.clear();
|
2012-07-22 15:35:18 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-19 09:18:07 +00:00
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
static const QString s_defaultTheme = QStringLiteral("kwin4_decoration_qml_plastik");
|
|
|
|
|
|
|
|
QQmlComponent *Helper::component(const QString &themeName)
|
2012-07-22 15:35:18 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
// 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();
|
2012-10-12 06:23:00 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
// 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);
|
2012-01-11 20:14:29 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
return nullptr;
|
2009-06-19 09:18:07 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
QQmlComponent *Helper::loadComponent(const QString &themeName)
|
2012-07-22 15:35:18 +00:00
|
|
|
{
|
2013-11-25 13:55:58 +00:00
|
|
|
qCDebug(AURORAE) << "Trying to load QML Decoration " << themeName;
|
2012-07-22 15:35:18 +00:00
|
|
|
const QString internalname = themeName.toLower();
|
|
|
|
|
2013-07-25 16:04:27 +00:00
|
|
|
QString constraint = QStringLiteral("[X-KDE-PluginInfo-Name] == '%1'").arg(internalname);
|
|
|
|
KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("KWin/Decoration"), constraint);
|
2012-07-22 15:35:18 +00:00
|
|
|
if (offers.isEmpty()) {
|
2013-11-25 13:55:58 +00:00
|
|
|
qCCritical(AURORAE) << "Couldn't find QML Decoration " << themeName << endl;
|
2012-07-22 15:35:18 +00:00
|
|
|
// TODO: what to do in error case?
|
2014-10-24 11:48:31 +00:00
|
|
|
return nullptr;
|
2012-07-22 15:35:18 +00:00
|
|
|
}
|
|
|
|
KService::Ptr service = offers.first();
|
2013-07-25 16:04:27 +00:00
|
|
|
const QString pluginName = service->property(QStringLiteral("X-KDE-PluginInfo-Name")).toString();
|
|
|
|
const QString scriptName = service->property(QStringLiteral("X-Plasma-MainScript")).toString();
|
2013-08-03 20:29:13 +00:00
|
|
|
const QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral(KWIN_NAME) + QStringLiteral("/decorations/") + pluginName + QStringLiteral("/contents/") + scriptName);
|
2012-07-22 15:35:18 +00:00
|
|
|
if (file.isNull()) {
|
2013-11-25 13:55:58 +00:00
|
|
|
qCDebug(AURORAE) << "Could not find script file for " << pluginName;
|
2012-07-22 15:35:18 +00:00
|
|
|
// TODO: what to do in error case?
|
2014-10-24 11:48:31 +00:00
|
|
|
return nullptr;
|
2012-07-22 15:35:18 +00:00
|
|
|
}
|
|
|
|
// setup the QML engine
|
2013-05-26 13:32:21 +00:00
|
|
|
/* 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" */
|
2013-08-03 20:29:13 +00:00
|
|
|
QStringListIterator paths(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("module/imports"), QStandardPaths::LocateDirectory));
|
2013-05-26 13:32:21 +00:00
|
|
|
paths.toBack();
|
|
|
|
while (paths.hasPrevious()) {
|
|
|
|
m_engine->addImportPath(paths.previous());
|
2012-07-22 15:35:18 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
QQmlComponent *component = new QQmlComponent(m_engine.data(), m_engine.data());
|
|
|
|
component->loadUrl(QUrl::fromLocalFile(file));
|
|
|
|
return component;
|
2012-07-22 15:35:18 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
QQmlContext *Helper::rootContext()
|
2009-06-19 09:18:07 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
return m_engine->rootContext();
|
2009-06-19 09:18:07 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Helper::init()
|
2009-06-19 09:18:07 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
// 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:
|
|
|
|
QString pluginPath;
|
|
|
|
for (const QString &path : m_engine->importPathList()) {
|
|
|
|
QDirIterator it(path, QDirIterator::Subdirectories);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
QFileInfo fileInfo = it.fileInfo();
|
|
|
|
if (!fileInfo.isFile()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!fileInfo.path().endsWith(QLatin1String("/org/kde/kwin/decoration"))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (fileInfo.fileName() == QLatin1String("libdecorationplugin.so")) {
|
|
|
|
pluginPath = fileInfo.absoluteFilePath();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!pluginPath.isEmpty()) {
|
|
|
|
break;
|
|
|
|
}
|
2009-06-19 09:18:07 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
m_engine->importPlugin(pluginPath, "org.kde.kwin.decoration", nullptr);
|
|
|
|
qmlRegisterType<KWin::Borders>("org.kde.kwin.decoration", 0, 1, "Borders");
|
2009-11-08 20:35:34 +00:00
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
qmlRegisterType<KDecoration2::Decoration>();
|
|
|
|
qmlRegisterType<KDecoration2::DecoratedClient>();
|
2014-12-05 16:19:46 +00:00
|
|
|
qRegisterMetaType<KDecoration2::BorderSize>();
|
2012-01-11 20:14:29 +00:00
|
|
|
}
|
2009-06-19 09:18:07 +00:00
|
|
|
|
2014-12-05 12:44:16 +00:00
|
|
|
static QString findTheme(const QVariantList &args)
|
|
|
|
{
|
|
|
|
if (args.isEmpty()) {
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
const auto map = args.first().toMap();
|
|
|
|
auto it = map.constFind(QStringLiteral("theme"));
|
|
|
|
if (it == map.constEnd()) {
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
return it.value().toString();
|
|
|
|
}
|
2009-06-19 09:18:07 +00:00
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
Decoration::Decoration(QObject *parent, const QVariantList &args)
|
2014-10-30 08:01:06 +00:00
|
|
|
: KDecoration2::Decoration(parent, args)
|
2014-10-24 11:48:31 +00:00
|
|
|
, m_item(nullptr)
|
2014-06-18 07:06:49 +00:00
|
|
|
, m_borders(nullptr)
|
|
|
|
, m_maximizedBorders(nullptr)
|
|
|
|
, m_extendedBorders(nullptr)
|
|
|
|
, m_padding(nullptr)
|
2014-10-24 11:48:31 +00:00
|
|
|
, m_themeName(s_defaultTheme)
|
|
|
|
, m_mutex(QMutex::Recursive)
|
|
|
|
{
|
2014-12-05 12:44:16 +00:00
|
|
|
m_themeName = findTheme(args);
|
2014-10-24 11:48:31 +00:00
|
|
|
Helper::instance().ref();
|
2009-06-19 09:18:07 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
Decoration::~Decoration()
|
2010-06-19 15:23:48 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
Helper::instance().unref();
|
2014-12-03 15:22:15 +00:00
|
|
|
#if HAVE_RENDER_CONTROL
|
|
|
|
if (m_context) {
|
|
|
|
m_context->makeCurrent(m_offscreenSurface.data());
|
|
|
|
|
|
|
|
delete m_renderControl;
|
|
|
|
delete m_view.data();
|
|
|
|
m_fbo.reset();
|
|
|
|
delete m_item;
|
|
|
|
|
|
|
|
m_context->doneCurrent();
|
|
|
|
}
|
|
|
|
#endif
|
2010-06-19 15:23:48 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::init()
|
2009-06-19 09:18:07 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
KDecoration2::Decoration::init();
|
2014-10-29 15:11:20 +00:00
|
|
|
auto s = settings();
|
2014-12-05 14:58:05 +00:00
|
|
|
connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, this, &Decoration::configChanged);
|
2014-10-29 15:11:20 +00:00
|
|
|
// recreate scene when compositing gets disabled, TODO: remove with rendercontrol
|
2014-12-03 15:22:15 +00:00
|
|
|
#if !HAVE_RENDER_CONTROL
|
2014-10-29 15:11:20 +00:00
|
|
|
if (!m_recreateNonCompositedConnection) {
|
|
|
|
m_recreateNonCompositedConnection = connect(s.data(), &KDecoration2::DecorationSettings::alphaChannelSupportedChanged,
|
|
|
|
this, [this](bool alpha) {
|
|
|
|
if (!alpha && m_item) {
|
|
|
|
m_item->deleteLater();
|
|
|
|
m_decorationWindow.reset();
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2014-12-03 15:22:15 +00:00
|
|
|
#endif
|
2014-10-29 15:11:20 +00:00
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
QQmlContext *context = new QQmlContext(Helper::instance().rootContext(), this);
|
|
|
|
context->setContextProperty(QStringLiteral("decoration"), this);
|
2014-12-05 15:43:13 +00:00
|
|
|
context->setContextProperty(QStringLiteral("decorationSettings"), s.data());
|
2014-10-24 11:48:31 +00:00
|
|
|
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);
|
2014-12-05 16:36:25 +00:00
|
|
|
theme->setBorderSize(s->borderSize());
|
|
|
|
connect(s.data(), &KDecoration2::DecorationSettings::borderSizeChanged, theme, &AuroraeTheme::setBorderSize);
|
2014-10-24 11:48:31 +00:00
|
|
|
// 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*>());
|
2014-10-28 07:17:46 +00:00
|
|
|
visualParent.value<QQuickItem*>()->setProperty("drawBackground", false);
|
2014-10-24 11:48:31 +00:00
|
|
|
} else {
|
2014-12-03 15:22:15 +00:00
|
|
|
#if HAVE_RENDER_CONTROL
|
|
|
|
// first create the context
|
|
|
|
QSurfaceFormat format;
|
|
|
|
format.setDepthBufferSize(16);
|
|
|
|
format.setStencilBufferSize(8);
|
|
|
|
m_context.reset(new QOpenGLContext);
|
|
|
|
m_context->setFormat(format);
|
|
|
|
m_context->create();
|
|
|
|
// and the offscreen surface
|
|
|
|
m_offscreenSurface.reset(new QOffscreenSurface);
|
|
|
|
m_offscreenSurface->setFormat(m_context->format());
|
|
|
|
m_offscreenSurface->create();
|
|
|
|
|
|
|
|
m_renderControl = new QQuickRenderControl(this);
|
|
|
|
m_view = new QQuickWindow(m_renderControl);
|
|
|
|
m_view->setColor(Qt::transparent);
|
|
|
|
|
|
|
|
// delay rendering a little bit for better performance
|
|
|
|
m_updateTimer.reset(new QTimer);
|
|
|
|
m_updateTimer->setSingleShot(true);
|
|
|
|
m_updateTimer->setInterval(5);
|
|
|
|
connect(m_updateTimer.data(), &QTimer::timeout, this,
|
|
|
|
[this] {
|
|
|
|
if (!m_context->makeCurrent(m_offscreenSurface.data())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (m_fbo.isNull() || m_fbo->size() != m_view->size()) {
|
|
|
|
m_fbo.reset(new QOpenGLFramebufferObject(m_view->size(), QOpenGLFramebufferObject::CombinedDepthStencil));
|
|
|
|
if (!m_fbo->isValid()) {
|
|
|
|
qCWarning(AURORAE) << "Creating FBO as render target failed";
|
|
|
|
m_fbo.reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_view->setRenderTarget(m_fbo.data());
|
|
|
|
m_renderControl->polishItems();
|
|
|
|
m_renderControl->sync();
|
|
|
|
m_renderControl->render();
|
|
|
|
|
|
|
|
m_view->resetOpenGLState();
|
|
|
|
m_buffer = m_fbo->toImage();
|
|
|
|
QOpenGLFramebufferObject::bindDefault();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
auto requestUpdate = [this] {
|
|
|
|
if (m_updateTimer->isActive()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_updateTimer->start();
|
|
|
|
};
|
|
|
|
connect(m_renderControl, &QQuickRenderControl::renderRequested, this, requestUpdate);
|
|
|
|
connect(m_renderControl, &QQuickRenderControl::sceneChanged, this, requestUpdate);
|
|
|
|
|
|
|
|
m_item->setParentItem(m_view->contentItem());
|
|
|
|
|
|
|
|
m_context->makeCurrent(m_offscreenSurface.data());
|
|
|
|
m_renderControl->initialize(m_context.data());
|
|
|
|
m_context->doneCurrent();
|
|
|
|
#else
|
2014-10-24 11:48:31 +00:00
|
|
|
// we need a QQuickWindow till we depend on Qt 5.4
|
2014-11-28 15:28:39 +00:00
|
|
|
m_decorationWindow.reset(QWindow::fromWinId(client().data()->decorationId()));
|
2014-10-27 11:43:39 +00:00
|
|
|
m_view = new QQuickWindow(m_decorationWindow.data());
|
2014-10-24 11:48:31 +00:00
|
|
|
m_view->setFlags(Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput);
|
|
|
|
m_view->setColor(Qt::transparent);
|
|
|
|
connect(m_view.data(), &QQuickWindow::beforeRendering, [this]() {
|
2014-10-29 15:11:20 +00:00
|
|
|
if (!settings()->isAlphaChannelSupported()) {
|
2014-10-24 11:48:31 +00:00
|
|
|
// directly render to QQuickWindow
|
2014-10-27 11:45:05 +00:00
|
|
|
m_fbo.reset();
|
2014-10-24 11:48:31 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-10-27 11:45:05 +00:00
|
|
|
if (m_fbo.isNull() || m_fbo->size() != m_view->size()) {
|
|
|
|
m_fbo.reset(new QOpenGLFramebufferObject(m_view->size(), QOpenGLFramebufferObject::CombinedDepthStencil));
|
2013-10-02 12:54:43 +00:00
|
|
|
if (!m_fbo->isValid()) {
|
2013-11-25 13:55:58 +00:00
|
|
|
qCWarning(AURORAE) << "Creating FBO as render target failed";
|
2013-10-02 12:54:43 +00:00
|
|
|
m_fbo.reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_view->setRenderTarget(m_fbo.data());
|
|
|
|
});
|
2014-10-24 11:48:31 +00:00
|
|
|
connect(m_view.data(), &QQuickWindow::afterRendering, [this] {
|
|
|
|
if (!m_fbo) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QMutexLocker locker(&m_mutex);
|
2013-10-02 12:54:43 +00:00
|
|
|
m_buffer = m_fbo->toImage();
|
|
|
|
});
|
2014-10-29 15:11:20 +00:00
|
|
|
connect(s.data(), &KDecoration2::DecorationSettings::alphaChannelSupportedChanged,
|
2014-10-24 11:48:31 +00:00
|
|
|
m_view.data(), &QQuickWindow::update);
|
|
|
|
connect(m_view.data(), &QQuickWindow::afterRendering, this, [this] { update(); }, Qt::QueuedConnection);
|
2013-10-02 08:04:10 +00:00
|
|
|
m_item->setParentItem(m_view->contentItem());
|
2014-12-03 15:22:15 +00:00
|
|
|
#endif
|
2013-10-02 08:04:10 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
setupBorders(m_item);
|
|
|
|
if (m_extendedBorders) {
|
|
|
|
auto updateExtendedBorders = [this] {
|
2014-11-11 10:33:02 +00:00
|
|
|
setResizeOnlyBorders(*m_extendedBorders);
|
2014-10-24 11:48:31 +00:00
|
|
|
};
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
connect(client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateBorders, Qt::QueuedConnection);
|
|
|
|
updateBorders();
|
|
|
|
if (!m_view.isNull()) {
|
2014-12-03 15:22:15 +00:00
|
|
|
#if !HAVE_RENDER_CONTROL
|
2014-10-24 11:48:31 +00:00
|
|
|
m_view->setVisible(true);
|
2014-12-03 15:22:15 +00:00
|
|
|
#endif
|
2014-10-24 11:48:31 +00:00
|
|
|
auto resizeWindow = [this] {
|
2014-10-27 11:45:05 +00:00
|
|
|
QRect rect(QPoint(0, 0), size());
|
2014-11-28 15:28:39 +00:00
|
|
|
if (m_padding && !client().data()->isMaximized()) {
|
2014-10-27 11:45:05 +00:00
|
|
|
rect = rect.adjusted(-m_padding->left(), -m_padding->top(), m_padding->right(), m_padding->bottom());
|
|
|
|
}
|
|
|
|
m_view->setGeometry(rect);
|
2014-12-03 15:22:15 +00:00
|
|
|
#if !HAVE_RENDER_CONTROL
|
2014-10-24 11:48:31 +00:00
|
|
|
m_view->lower();
|
|
|
|
m_view->update();
|
2014-12-03 15:22:15 +00:00
|
|
|
#endif
|
2014-10-24 11:48:31 +00:00
|
|
|
};
|
2014-10-27 11:45:05 +00:00
|
|
|
connect(this, &Decoration::bordersChanged, this, resizeWindow);
|
2014-10-27 11:43:39 +00:00
|
|
|
connect(client().data(), &KDecoration2::DecoratedClient::widthChanged, this, resizeWindow);
|
|
|
|
connect(client().data(), &KDecoration2::DecoratedClient::heightChanged, this, resizeWindow);
|
2014-10-27 11:45:05 +00:00
|
|
|
connect(client().data(), &KDecoration2::DecoratedClient::maximizedChanged, this, resizeWindow);
|
2014-10-24 11:48:31 +00:00
|
|
|
resizeWindow();
|
2014-10-28 07:16:53 +00:00
|
|
|
} else {
|
|
|
|
// create a dummy shadow for the configuration interface
|
|
|
|
if (m_padding) {
|
2014-12-01 08:40:24 +00:00
|
|
|
auto s = QSharedPointer<KDecoration2::DecorationShadow>::create();
|
2014-11-11 14:18:35 +00:00
|
|
|
s->setPadding(*m_padding);
|
2014-11-11 16:02:15 +00:00
|
|
|
s->setInnerShadowRect(QRect(m_padding->left(), m_padding->top(), 1, 1));
|
2014-10-28 07:16:53 +00:00
|
|
|
setShadow(s);
|
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant Decoration::readConfig(const QString &key, const QVariant &defaultValue)
|
2012-07-30 18:00:25 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("auroraerc"));
|
2014-12-05 13:53:55 +00:00
|
|
|
return config->group(m_themeName).readEntry(key, defaultValue);
|
2010-01-29 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::setupBorders(QQuickItem *item)
|
2010-01-29 12:37:42 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
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"));
|
2010-01-29 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::updateBorders()
|
2009-06-19 09:18:07 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
KWin::Borders *b = m_borders;
|
2014-11-28 15:28:39 +00:00
|
|
|
if (client().data()->isMaximized() && m_maximizedBorders) {
|
2014-10-24 11:48:31 +00:00
|
|
|
b = m_maximizedBorders;
|
2012-01-09 22:07:22 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
if (!b) {
|
2013-01-16 07:43:53 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-11-11 09:49:10 +00:00
|
|
|
setBorders(*b);
|
2009-06-19 09:18:07 +00:00
|
|
|
}
|
|
|
|
|
2014-11-28 09:26:23 +00:00
|
|
|
void Decoration::paint(QPainter *painter, const QRect &repaintRegion)
|
2009-06-19 09:18:07 +00:00
|
|
|
{
|
2014-11-11 08:39:45 +00:00
|
|
|
Q_UNUSED(repaintRegion)
|
2014-12-03 15:22:15 +00:00
|
|
|
#if !HAVE_RENDER_CONTROL
|
2014-10-29 15:11:20 +00:00
|
|
|
if (!settings()->isAlphaChannelSupported()) {
|
2014-10-27 11:45:05 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
QMutexLocker locker(&m_mutex);
|
2014-12-03 15:22:15 +00:00
|
|
|
#endif
|
2014-10-24 11:48:31 +00:00
|
|
|
painter->fillRect(rect(), Qt::transparent);
|
2014-10-27 11:45:05 +00:00
|
|
|
QRectF r(QPointF(0, 0), m_buffer.size());
|
|
|
|
if (m_padding &&
|
|
|
|
(m_padding->left() > 0 || m_padding->top() > 0 || m_padding->right() > 0 || m_padding->bottom() > 0) &&
|
2014-11-28 15:28:39 +00:00
|
|
|
!client().data()->isMaximized()) {
|
2014-10-27 11:45:05 +00:00
|
|
|
r = r.adjusted(m_padding->left(), m_padding->top(), -m_padding->right(), -m_padding->bottom());
|
2014-12-01 08:40:24 +00:00
|
|
|
auto s = QSharedPointer<KDecoration2::DecorationShadow>::create();
|
2014-10-27 11:45:05 +00:00
|
|
|
s->setShadow(m_buffer);
|
2014-11-11 14:18:35 +00:00
|
|
|
s->setPadding(*m_padding);
|
2014-11-11 16:02:15 +00:00
|
|
|
s->setInnerShadowRect(QRect(m_padding->left(),
|
|
|
|
m_padding->top(),
|
|
|
|
m_buffer.width() - m_padding->left() - m_padding->right(),
|
|
|
|
m_buffer.height() - m_padding->top() - m_padding->bottom()));
|
2014-12-12 21:12:11 +00:00
|
|
|
m_scheduledShadow = s;
|
2014-10-27 11:45:05 +00:00
|
|
|
} else {
|
2014-12-12 21:12:11 +00:00
|
|
|
m_scheduledShadow = QSharedPointer<KDecoration2::DecorationShadow>();
|
2014-10-27 11:45:05 +00:00
|
|
|
}
|
2014-12-12 21:12:11 +00:00
|
|
|
QMetaObject::invokeMethod(this, "updateShadow", Qt::QueuedConnection);
|
2014-10-27 11:45:05 +00:00
|
|
|
painter->drawImage(rect(), m_buffer, r);
|
|
|
|
}
|
|
|
|
|
2014-12-12 21:12:11 +00:00
|
|
|
void Decoration::updateShadow()
|
|
|
|
{
|
|
|
|
setShadow(m_scheduledShadow);
|
|
|
|
}
|
|
|
|
|
2014-10-27 11:45:05 +00:00
|
|
|
QMouseEvent Decoration::translatedMouseEvent(QMouseEvent *orig)
|
|
|
|
{
|
2014-11-28 15:28:39 +00:00
|
|
|
if (!m_padding || client().data()->isMaximized()) {
|
2014-10-27 11:45:05 +00:00
|
|
|
orig->setAccepted(false);
|
|
|
|
return *orig;
|
|
|
|
}
|
|
|
|
QMouseEvent event(orig->type(), orig->localPos() + QPointF(m_padding->left(), m_padding->top()), orig->button(), orig->buttons(), orig->modifiers());
|
|
|
|
event.setAccepted(false);
|
|
|
|
return event;
|
2009-06-19 09:18:07 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::hoverEnterEvent(QHoverEvent *event)
|
2009-06-19 09:18:07 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
if (m_view) {
|
|
|
|
event->setAccepted(false);
|
|
|
|
QCoreApplication::sendEvent(m_view.data(), event);
|
2010-04-12 19:28:58 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
KDecoration2::Decoration::hoverEnterEvent(event);
|
2010-01-29 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::hoverLeaveEvent(QHoverEvent *event)
|
2012-01-11 20:14:29 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
if (m_view) {
|
|
|
|
event->setAccepted(false);
|
|
|
|
QCoreApplication::sendEvent(m_view.data(), event);
|
2012-01-11 20:14:29 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
KDecoration2::Decoration::hoverLeaveEvent(event);
|
2012-08-10 06:52:11 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::hoverMoveEvent(QHoverEvent *event)
|
2012-07-29 09:20:48 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
if (m_view) {
|
2014-10-27 11:45:05 +00:00
|
|
|
QMouseEvent mouseEvent(QEvent::MouseMove, event->posF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
|
|
|
|
QMouseEvent ev = translatedMouseEvent(&mouseEvent);
|
2014-10-24 11:48:31 +00:00
|
|
|
QCoreApplication::sendEvent(m_view.data(), &ev);
|
2014-10-27 11:45:05 +00:00
|
|
|
event->setAccepted(ev.isAccepted());
|
2014-10-24 11:48:31 +00:00
|
|
|
}
|
|
|
|
KDecoration2::Decoration::hoverMoveEvent(event);
|
2012-07-29 09:20:48 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::mouseMoveEvent(QMouseEvent *event)
|
2012-10-12 09:34:05 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
if (m_view) {
|
2014-10-27 11:45:05 +00:00
|
|
|
QMouseEvent ev = translatedMouseEvent(event);
|
|
|
|
QCoreApplication::sendEvent(m_view.data(), &ev);
|
|
|
|
event->setAccepted(ev.isAccepted());
|
2012-10-12 09:34:05 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
KDecoration2::Decoration::mouseMoveEvent(event);
|
2012-10-12 09:34:05 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::mousePressEvent(QMouseEvent *event)
|
2012-12-27 07:51:15 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
if (m_view) {
|
2014-10-27 11:45:05 +00:00
|
|
|
QMouseEvent ev = translatedMouseEvent(event);
|
|
|
|
QCoreApplication::sendEvent(m_view.data(), &ev);
|
|
|
|
event->setAccepted(ev.isAccepted());
|
2012-12-27 07:51:15 +00:00
|
|
|
}
|
2014-10-24 11:48:31 +00:00
|
|
|
KDecoration2::Decoration::mousePressEvent(event);
|
2012-12-27 07:51:15 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::mouseReleaseEvent(QMouseEvent *event)
|
2013-03-12 17:36:21 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
if (m_view) {
|
2014-10-27 11:45:05 +00:00
|
|
|
QMouseEvent ev = translatedMouseEvent(event);
|
|
|
|
QCoreApplication::sendEvent(m_view.data(), &ev);
|
|
|
|
event->setAccepted(ev.isAccepted());
|
2014-10-24 11:48:31 +00:00
|
|
|
}
|
|
|
|
KDecoration2::Decoration::mouseReleaseEvent(event);
|
2013-03-12 17:36:21 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:48:31 +00:00
|
|
|
void Decoration::installTitleItem(QQuickItem *item)
|
2013-10-07 12:40:12 +00:00
|
|
|
{
|
2014-10-24 11:48:31 +00:00
|
|
|
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();
|
|
|
|
}
|
2014-11-11 10:55:20 +00:00
|
|
|
setTitleBar(rect);
|
2014-10-24 11:48:31 +00:00
|
|
|
};
|
|
|
|
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);
|
2013-10-07 12:40:12 +00:00
|
|
|
}
|
|
|
|
|
2014-11-28 15:28:39 +00:00
|
|
|
KDecoration2::DecoratedClient *Decoration::clientPointer() const
|
|
|
|
{
|
|
|
|
return client().data();
|
|
|
|
}
|
|
|
|
|
2014-10-28 08:57:38 +00:00
|
|
|
ThemeFinder::ThemeFinder(QObject *parent, const QVariantList &args)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
|
|
|
Q_UNUSED(args)
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeFinder::init()
|
|
|
|
{
|
|
|
|
findAllQmlThemes();
|
|
|
|
findAllSvgThemes();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeFinder::findAllQmlThemes()
|
|
|
|
{
|
|
|
|
const KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("KWin/Decoration"));
|
|
|
|
for (const auto &offer : offers) {
|
|
|
|
m_themes.insert(offer->name(), offer->property(QStringLiteral("X-KDE-PluginInfo-Name")).toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeFinder::findAllSvgThemes()
|
|
|
|
{
|
|
|
|
QStringList themes;
|
|
|
|
const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("aurorae/themes/"), QStandardPaths::LocateDirectory);
|
|
|
|
QStringList themeDirectories;
|
|
|
|
for (const QString &dir : dirs) {
|
|
|
|
QDir directory = QDir(dir);
|
|
|
|
for (const QString &themeDir : directory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
|
|
|
|
themeDirectories << dir + themeDir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const QString &dir : themeDirectories) {
|
|
|
|
for (const QString & file : QDir(dir).entryList(QStringList() << QStringLiteral("metadata.desktop"))) {
|
|
|
|
themes.append(dir + '/' + file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const QString & theme : themes) {
|
|
|
|
int themeSepIndex = theme.lastIndexOf('/', -1);
|
|
|
|
QString themeRoot = theme.left(themeSepIndex);
|
|
|
|
int themeNameSepIndex = themeRoot.lastIndexOf('/', -1);
|
|
|
|
QString packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1);
|
|
|
|
|
|
|
|
KDesktopFile df(theme);
|
|
|
|
QString name = df.readName();
|
|
|
|
if (name.isEmpty()) {
|
|
|
|
name = packageName;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_themes.insert(name, QStringLiteral("__aurorae__svg__") + packageName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-05 12:44:16 +00:00
|
|
|
static const QString s_configUiPath = QStringLiteral("kwin/decorations/%1/contents/ui/config.ui");
|
|
|
|
static const QString s_configXmlPath = QStringLiteral("kwin/decorations/%1/contents/config/main.xml");
|
|
|
|
|
|
|
|
bool ThemeFinder::hasConfiguration(const QString &theme) const
|
|
|
|
{
|
|
|
|
if (theme.startsWith(QLatin1String("__aurorae__svg__"))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const QString ui = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
|
|
|
s_configUiPath.arg(theme));
|
|
|
|
const QString xml = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
|
|
|
s_configXmlPath.arg(theme));
|
|
|
|
return !(ui.isEmpty() || xml.isEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfigurationModule::ConfigurationModule(QWidget *parent, const QVariantList &args)
|
|
|
|
: KCModule(parent, args)
|
|
|
|
, m_theme(findTheme(args))
|
|
|
|
{
|
|
|
|
setLayout(new QVBoxLayout(this));
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigurationModule::init()
|
|
|
|
{
|
|
|
|
const QString ui = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
|
|
|
s_configUiPath.arg(m_theme));
|
|
|
|
const QString xml = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
|
|
|
s_configXmlPath.arg(m_theme));
|
|
|
|
if (ui.isEmpty() || xml.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
KLocalizedTranslator *translator = new KLocalizedTranslator(this);
|
|
|
|
QCoreApplication::instance()->installTranslator(translator);
|
|
|
|
const KDesktopFile metaData(QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
|
|
|
QStringLiteral("kwin/decorations/%1/metadata.desktop").arg(m_theme)));
|
|
|
|
const QString translationDomain = metaData.desktopGroup().readEntry("X-KWin-Config-TranslationDomain", QString());
|
|
|
|
if (!translationDomain.isEmpty()) {
|
|
|
|
translator->setTranslationDomain(translationDomain);
|
|
|
|
}
|
|
|
|
// load the KConfigSkeleton
|
|
|
|
QFile configFile(xml);
|
|
|
|
KSharedConfigPtr auroraeConfig = KSharedConfig::openConfig("auroraerc");
|
|
|
|
KConfigGroup configGroup = auroraeConfig->group(m_theme);
|
|
|
|
m_skeleton = new KConfigLoader(configGroup, &configFile, this);
|
|
|
|
// load the ui file
|
|
|
|
QUiLoader *loader = new QUiLoader(this);
|
|
|
|
loader->setLanguageChangeEnabled(true);
|
|
|
|
QFile uiFile(ui);
|
|
|
|
uiFile.open(QFile::ReadOnly);
|
|
|
|
QWidget *customConfigForm = loader->load(&uiFile, this);
|
|
|
|
translator->addContextToMonitor(customConfigForm->objectName());
|
|
|
|
uiFile.close();
|
|
|
|
layout()->addWidget(customConfigForm);
|
|
|
|
// connect the ui file with the skeleton
|
2014-12-05 14:58:05 +00:00
|
|
|
addConfig(m_skeleton, customConfigForm);
|
2014-12-05 12:44:16 +00:00
|
|
|
|
|
|
|
// send a custom event to the translator to retranslate using our translator
|
|
|
|
QEvent le(QEvent::LanguageChange);
|
|
|
|
QCoreApplication::sendEvent(customConfigForm, &le);
|
|
|
|
}
|
|
|
|
|
2014-06-18 07:06:49 +00:00
|
|
|
}
|
|
|
|
|
2009-06-19 09:18:07 +00:00
|
|
|
#include "aurorae.moc"
|