diff --git a/app/view/indicator/indicator.cpp b/app/view/indicator/indicator.cpp index 15bdea24..b012128a 100644 --- a/app/view/indicator/indicator.cpp +++ b/app/view/indicator/indicator.cpp @@ -1,445 +1,454 @@ /* * Copyright 2019 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock 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. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "indicator.h" // local #include #include "indicatorinfo.h" #include "../view.h" #include "../../lattecorona.h" #include "../../indicator/factory.h" // Qt #include // KDE #include #include #include #include namespace Latte { namespace ViewPart { Indicator::Indicator(Latte::View *parent) : QObject(parent), m_view(parent), m_info(new IndicatorPart::Info(this)), m_resources(new IndicatorPart::Resources(this)) { m_corona = qobject_cast(m_view->corona()); loadConfig(); connect(this, &Indicator::enabledChanged, this, &Indicator::saveConfig); connect(this, &Indicator::pluginChanged, this, &Indicator::saveConfig); connect(m_view, &Latte::View::latteTasksArePresentChanged, this, &Indicator::latteTasksArePresentChanged); connect(m_view, &Latte::View::indicatorPluginChanged, [this](const QString &indicatorId) { if (m_corona && m_corona->indicatorFactory()->isCustomType(indicatorId)) { emit customPluginsChanged(); } }); connect(m_view, &Latte::View::indicatorPluginRemoved, [this](const QString &indicatorId) { if (m_corona && m_type == indicatorId && !m_corona->indicatorFactory()->pluginExists(indicatorId)) { setType("org.kde.latte.default"); } if (m_corona && m_corona->indicatorFactory()->isCustomType(indicatorId)) { emit customPluginsChanged(); } }); load(m_type); loadPlasmaComponent(); } Indicator::~Indicator() { unloadIndicators(); if (m_component) { m_component->deleteLater(); } if (m_configLoader) { m_configLoader->deleteLater(); } if (m_configuration) { m_configuration->deleteLater(); } if (m_info) { m_info->deleteLater(); } } bool Indicator::enabled() const { return m_enabled; } void Indicator::setEnabled(bool enabled) { if (m_enabled == enabled) { return; } m_enabled = enabled; emit enabledChanged(); } bool Indicator::enabledForApplets() const { return m_enabledForApplets; } void Indicator::setEnabledForApplets(bool enabled) { if (m_enabledForApplets == enabled) { return; } m_enabledForApplets = enabled; emit enabledForAppletsChanged(); } bool Indicator::isCustomIndicator() const { return m_corona->indicatorFactory()->isCustomType(type()); } bool Indicator::latteTasksArePresent() { return m_view->latteTasksArePresent(); } bool Indicator::providesConfigUi() const { return m_providesConfigUi; } void Indicator::setProvidesConfigUi(bool provides) { if (m_providesConfigUi == provides) { return; } m_providesConfigUi = provides; emit providesConfigUiChanged(); } bool Indicator::pluginIsReady() { return m_pluginIsReady; } void Indicator::setPluginIsReady(bool ready) { if (m_pluginIsReady == ready) { return; } m_pluginIsReady = ready; emit pluginIsReadyChanged(); } QString Indicator::type() const { return m_type; } void Indicator::setType(QString type) { if (m_type == type) { return; } load(type); } QString Indicator::customType() const { return m_customType; } void Indicator::setCustomType(QString type) { if (m_customType == type) { return; } m_customType = type; emit customPluginChanged(); } int Indicator::customPluginsCount() const { return m_corona->indicatorFactory()->customPluginsCount(); } QString Indicator::uiPath() const { return m_corona->indicatorFactory()->uiPath(m_type); } QStringList Indicator::customPluginIds() const { return m_corona->indicatorFactory()->customPluginIds(); } QStringList Indicator::customPluginNames() const { return m_corona->indicatorFactory()->customPluginNames(); } QStringList Indicator::customLocalPluginIds() const { return m_corona->indicatorFactory()->customLocalPluginIds(); } IndicatorPart::Info *Indicator::info() const { return m_info; } IndicatorPart::Resources *Indicator::resources() const { return m_resources; } QQmlComponent *Indicator::component() const { return m_component; } QQmlComponent *Indicator::plasmaComponent() const { return m_plasmaComponent; } QObject *Indicator::configuration() const { return m_configuration; } void Indicator::load(QString type) { KPluginMetaData metadata = m_corona->indicatorFactory()->metadata(type); if (metadata.isValid()) { bool state{m_enabled}; //! remove all previous indicators setPluginIsReady(false); m_metadata = metadata; m_type = type; QString path = m_metadata.fileName(); m_pluginPath = path.remove("metadata.desktop"); if (m_corona && m_corona->indicatorFactory()->isCustomType(type)) { setCustomType(type); } updateScheme(); updateComponent(); emit pluginChanged(); //! create all indicators with the new type setPluginIsReady(true); } else if (type!="org.kde.latte.default") { qDebug() << " Indicator metadata are not valid : " << type; setType("org.kde.latte.default"); } } void Indicator::updateComponent() { auto prevComponent = m_component; QString uiPath = m_metadata.value("X-Latte-MainScript"); if (!uiPath.isEmpty()) { uiPath = m_pluginPath + "package/" + uiPath; m_component = new QQmlComponent(m_view->engine(), uiPath); } if (prevComponent) { prevComponent->deleteLater(); } } void Indicator::loadPlasmaComponent() { auto prevComponent = m_plasmaComponent; KPluginMetaData metadata = m_corona->indicatorFactory()->metadata("org.kde.latte.plasmatabstyle"); QString uiPath = metadata.value("X-Latte-MainScript"); if (!uiPath.isEmpty()) { QString path = metadata.fileName(); path = path.remove("metadata.desktop"); uiPath = path + "package/" + uiPath; m_plasmaComponent = new QQmlComponent(m_view->engine(), uiPath); } if (prevComponent) { prevComponent->deleteLater(); } emit plasmaComponentChanged(); } void Indicator::configUiFor(QString type, QQuickItem *parent) { if (m_lastCreatedConfigUi) { delete m_lastCreatedConfigUi; m_lastCreatedConfigUi = nullptr; } + auto prevConfigUi = m_lastCreatedConfigUi; KPluginMetaData metadata; if (m_metadata.pluginId() == type) { metadata = m_metadata; } else { metadata = m_corona->indicatorFactory()->metadata(type); } if (metadata.isValid()) { QString uiPath = metadata.value("X-Latte-ConfigUi"); if (!uiPath.isEmpty()) { m_lastCreatedConfigUi = new KDeclarative::QmlObjectSharedEngine(parent); m_lastCreatedConfigUi->setTranslationDomain(QLatin1String("latte_indicator_") + m_metadata.pluginId()); m_lastCreatedConfigUi->setInitializationDelayed(true); uiPath = m_pluginPath + "package/" + uiPath; m_lastCreatedConfigUi->setSource(QUrl::fromLocalFile(uiPath)); m_lastCreatedConfigUi->rootContext()->setContextProperty(QStringLiteral("dialog"), parent); m_lastCreatedConfigUi->rootContext()->setContextProperty(QStringLiteral("indicator"), this); m_lastCreatedConfigUi->completeInitialization(); QQuickItem *qmlItem = qobject_cast(m_lastCreatedConfigUi->rootObject()); qmlItem->setParentItem(parent); setProvidesConfigUi(true); } else { setProvidesConfigUi(false); } } } +void Indicator::releaseConfigUi() +{ + if (m_lastCreatedConfigUi) { + delete m_lastCreatedConfigUi; + m_lastCreatedConfigUi = nullptr; + } +} + void Indicator::unloadIndicators() { setPluginIsReady(false); } void Indicator::updateScheme() { auto prevConfigLoader = m_configLoader; auto prevConfiguration = m_configuration; QString xmlPath = m_metadata.value("X-Latte-ConfigXml"); if (!xmlPath.isEmpty()) { QFile file(m_pluginPath + "package/" + xmlPath); m_configLoader = new KConfigLoader(m_view->containment()->config().group("Indicator").group(m_metadata.pluginId()), &file); m_configuration = new KDeclarative::ConfigPropertyMap(m_configLoader, this); } else { m_configLoader = nullptr; m_configuration = nullptr; } if (prevConfigLoader) { prevConfigLoader->deleteLater(); } if (prevConfiguration) { prevConfiguration->deleteLater(); } } void Indicator::addIndicator() { QFileDialog *fileDialog = new QFileDialog(nullptr , i18nc("add indicator", "Add Indicator") , QDir::homePath() , QStringLiteral("indicator.latte")); fileDialog->setFileMode(QFileDialog::AnyFile); fileDialog->setAcceptMode(QFileDialog::AcceptOpen); fileDialog->setDefaultSuffix("indicator.latte"); QStringList filters; filters << QString(i18nc("add indicator file", "Latte Indicator") + "(*.indicator.latte)"); fileDialog->setNameFilters(filters); connect(fileDialog, &QFileDialog::finished, fileDialog, &QFileDialog::deleteLater); connect(fileDialog, &QFileDialog::fileSelected, this, [&](const QString & file) { qDebug() << "Trying to import indicator file ::: " << file; m_corona->indicatorFactory()->importIndicatorFile(file); }); fileDialog->open(); } void Indicator::downloadIndicator() { //! call asynchronously in order to not crash when view settings window //! loses focus and it closes QTimer::singleShot(0, [this]() { m_corona->indicatorFactory()->downloadIndicator(); }); } void Indicator::removeIndicator(QString pluginId) { //! call asynchronously in order to not crash when view settings window //! loses focus and it closes QTimer::singleShot(0, [this, pluginId]() { m_corona->indicatorFactory()->removeIndicator(pluginId); }); } void Indicator::loadConfig() { auto config = m_view->containment()->config().group("Indicator"); m_customType = config.readEntry("customType", QString()); m_enabled = config.readEntry("enabled", true); m_type = config.readEntry("type", "org.kde.latte.default"); } void Indicator::saveConfig() { auto config = m_view->containment()->config().group("Indicator"); config.writeEntry("customType", m_customType); config.writeEntry("enabled", m_enabled); config.writeEntry("type", m_type); } } } diff --git a/app/view/indicator/indicator.h b/app/view/indicator/indicator.h index 7c95d00d..bada41de 100644 --- a/app/view/indicator/indicator.h +++ b/app/view/indicator/indicator.h @@ -1,189 +1,190 @@ /* * Copyright 2019 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock 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. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VIEWINDICATOR_H #define VIEWINDICATOR_H // local #include "indicatorinfo.h" #include "indicatorresources.h" // Qt #include #include #include #include #include // KDE #include #include namespace KDeclarative { class ConfigPropertyMap; class QmlObjectSharedEngine; } namespace Latte { class Corona; class View; } namespace Latte { namespace ViewPart { class Indicator: public QObject { Q_OBJECT Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(bool enabledForApplets READ enabledForApplets WRITE setEnabledForApplets NOTIFY enabledForAppletsChanged) Q_PROPERTY(bool latteTasksArePresent READ latteTasksArePresent NOTIFY latteTasksArePresentChanged) Q_PROPERTY(bool pluginIsReady READ pluginIsReady NOTIFY pluginIsReadyChanged) Q_PROPERTY(bool providesConfigUi READ providesConfigUi NOTIFY providesConfigUiChanged) Q_PROPERTY(QString type READ type WRITE setType NOTIFY pluginChanged) Q_PROPERTY(QString customType READ customType NOTIFY customPluginChanged) /* Custom plugins */ Q_PROPERTY(int customPluginsCount READ customPluginsCount NOTIFY customPluginsChanged) Q_PROPERTY(QStringList customPluginIds READ customPluginIds NOTIFY customPluginsChanged) Q_PROPERTY(QStringList customPluginNames READ customPluginNames NOTIFY customPluginsChanged) Q_PROPERTY(QStringList customLocalPluginIds READ customLocalPluginIds NOTIFY customPluginsChanged) /** * Configuration object: each config key will be a writable property of this object. property bindings work. */ Q_PROPERTY(QObject *configuration READ configuration NOTIFY pluginChanged) Q_PROPERTY(QQmlComponent *component READ component NOTIFY pluginChanged) Q_PROPERTY(QQmlComponent *plasmaComponent READ plasmaComponent NOTIFY plasmaComponentChanged) /** * Information provided from the indicator itself */ Q_PROPERTY(Latte::ViewPart::IndicatorPart::Info *info READ info NOTIFY infoChanged) /** * Resources provided from the indicator itself */ Q_PROPERTY(Latte::ViewPart::IndicatorPart::Resources *resources READ resources NOTIFY resourcesChanged) public: Indicator(Latte::View *parent); virtual ~Indicator(); bool enabled() const; void setEnabled(bool enabled); bool enabledForApplets() const; void setEnabledForApplets(bool enabled); bool isCustomIndicator() const; bool latteTasksArePresent(); bool providesConfigUi() const; bool pluginIsReady(); QString type() const; void setType(QString type); QString uiPath() const; QString customType() const; int customPluginsCount() const; QStringList customPluginIds() const; QStringList customPluginNames() const; QStringList customLocalPluginIds() const; IndicatorPart::Info *info() const; IndicatorPart::Resources *resources() const; QObject *configuration() const; QQmlComponent *component() const; QQmlComponent *plasmaComponent() const; void load(QString type); void unloadIndicators(); public slots: Q_INVOKABLE void configUiFor(QString type, QQuickItem *parent); Q_INVOKABLE void addIndicator(); Q_INVOKABLE void downloadIndicator(); Q_INVOKABLE void removeIndicator(QString pluginId); + void releaseConfigUi(); signals: void customPluginsChanged(); void enabledChanged(); void enabledForAppletsChanged(); void customPluginChanged(); void infoChanged(); void latteTasksArePresentChanged(); void plasmaComponentChanged(); void pluginChanged(); void pluginIsReadyChanged(); void providesConfigUiChanged(); void resourcesChanged(); private: void loadConfig(); void saveConfig(); void setPluginIsReady(bool ready); void setProvidesConfigUi(bool provides); void setCustomType(QString type); void loadPlasmaComponent(); void updateComponent(); void updateScheme(); private: bool m_enabled{true}; bool m_enabledForApplets{true}; bool m_pluginIsReady{false}; bool m_providesConfigUi{true}; QString m_pluginPath; QString m_type{"org.kde.latte.default"}; QString m_customType; QPointer m_component; QPointer m_plasmaComponent; QPointer m_configUi; QPointer m_configLoader; QPointer m_corona; QPointer m_view; KPluginMetaData m_metadata; QPointer m_info; QPointer m_resources; QPointer m_configuration; QPointer m_lastCreatedConfigUi; }; } } #endif diff --git a/app/view/settings/primaryconfigview.cpp b/app/view/settings/primaryconfigview.cpp index ca30c71d..5edb2cd3 100644 --- a/app/view/settings/primaryconfigview.cpp +++ b/app/view/settings/primaryconfigview.cpp @@ -1,786 +1,791 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock 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. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "primaryconfigview.h" // local #include #include "secondaryconfigview.h" #include "../effects.h" #include "../panelshadows_p.h" #include "../view.h" #include "../../lattecorona.h" #include "../../layouts/manager.h" #include "../../layout/genericlayout.h" #include "../../settings/universalsettings.h" #include "../../shortcuts/globalshortcuts.h" #include "../../shortcuts/shortcutstracker.h" #include "../../wm/abstractwindowinterface.h" // Qt #include #include #include #include // KDE #include #include #include #include #include #include // Plasma #include namespace Latte { namespace ViewPart { PrimaryConfigView::PrimaryConfigView(Plasma::Containment *containment, Latte::View *view, QWindow *parent) : PlasmaQuick::ConfigView(containment, parent), m_latteView(view) { m_corona = qobject_cast(m_latteView->containment()->corona()); setupWaylandIntegration(); setTitle(validTitle()); if (KWindowSystem::isPlatformX11()) { m_corona->wm()->registerIgnoredWindow(winId()); } else { connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, &PrimaryConfigView::updateWaylandId); } setScreen(m_latteView->screen()); if (containment) { setIcon(qGuiApp->windowIcon()); } m_screenSyncTimer.setSingleShot(true); m_screenSyncTimer.setInterval(100); connect(this, &QQuickView::widthChanged, this, &PrimaryConfigView::updateEffects); connect(this, &QQuickView::heightChanged, this, &PrimaryConfigView::updateEffects); connect(this, &PrimaryConfigView::availableScreenGeometryChanged, this, &PrimaryConfigView::syncGeometry); connect(this, &PrimaryConfigView::inAdvancedModeChanged, this, &PrimaryConfigView::saveConfig); connect(this, &PrimaryConfigView::inAdvancedModeChanged, this, &PrimaryConfigView::updateShowInlineProperties); connect(this, &PrimaryConfigView::inAdvancedModeChanged, this, &PrimaryConfigView::syncGeometry); connect(this, &PrimaryConfigView::inAdvancedModeChanged, m_latteView, &Latte::View::inSettingsAdvancedModeChanged); connect(this, &QQuickView::statusChanged, [&](QQuickView::Status status) { if (status == QQuickView::Ready) { updateEffects(); } }); connections << connect(&m_screenSyncTimer, &QTimer::timeout, this, [this]() { setScreen(m_latteView->screen()); setFlags(wFlags()); if (KWindowSystem::isPlatformX11()) { m_corona->wm()->setViewExtraFlags(this, false, Latte::Types::NormalWindow); } syncGeometry(); syncSlideEffect(); }); connections << connect(m_latteView->visibility(), &VisibilityManager::modeChanged, this, &PrimaryConfigView::syncGeometry); connections << connect(containment, &Plasma::Containment::immutabilityChanged, this, &PrimaryConfigView::immutabilityChanged); m_thicknessSyncTimer.setSingleShot(true); m_thicknessSyncTimer.setInterval(200); connections << connect(&m_thicknessSyncTimer, &QTimer::timeout, this, [this]() { syncGeometry(); }); connections << connect(m_latteView, &Latte::View::normalThicknessChanged, [&]() { m_thicknessSyncTimer.start(); }); if (m_corona) { connections << connect(m_corona, &Latte::Corona::raiseViewsTemporaryChanged, this, &PrimaryConfigView::raiseDocksTemporaryChanged); connections << connect(m_corona, &Latte::Corona::availableScreenRectChangedFrom, this, &PrimaryConfigView::updateAvailableScreenGeometry); } if (m_latteView->layout()) { emit m_latteView->layout()->setLastConfigViewFor(m_latteView); } } PrimaryConfigView::~PrimaryConfigView() { qDebug() << "ConfigView deleting ..."; + if (m_latteView->indicator()) { + //! destroy indicator config ui when the configuration window is closed + m_latteView->indicator()->releaseConfigUi(); + } + m_corona->dialogShadows()->removeWindow(this); m_corona->wm()->unregisterIgnoredWindow(KWindowSystem::isPlatformX11() ? winId() : m_waylandWindowId); deleteSecondaryWindow(); for (const auto &var : connections) { QObject::disconnect(var); } } void PrimaryConfigView::init() { qDebug() << "dock config view : initialization started..."; m_originalByPassWM = m_latteView->byPassWM(); m_originalMode = m_latteView->visibility()->mode(); loadConfig(); //! inform view about the current settings level emit m_latteView->inSettingsAdvancedModeChanged(); setDefaultAlphaBuffer(true); setColor(Qt::transparent); m_corona->dialogShadows()->addWindow(this); rootContext()->setContextProperty(QStringLiteral("latteView"), m_latteView); rootContext()->setContextProperty(QStringLiteral("shortcutsEngine"), m_corona->globalShortcuts()->shortcutsTracker()); rootContext()->setContextProperty(QStringLiteral("viewConfig"), this); if (m_corona) { rootContext()->setContextProperty(QStringLiteral("universalSettings"), m_corona->universalSettings()); rootContext()->setContextProperty(QStringLiteral("layoutsManager"), m_corona->layoutsManager()); } KDeclarative::KDeclarative kdeclarative; kdeclarative.setDeclarativeEngine(engine()); kdeclarative.setTranslationDomain(QStringLiteral("latte-dock")); #if KF5_VERSION_MINOR >= 45 kdeclarative.setupContext(); kdeclarative.setupEngine(engine()); #else kdeclarative.setupBindings(); #endif QByteArray tempFilePath = "lattedockconfigurationui"; updateEnabledBorders(); updateAvailableScreenGeometry(); auto source = QUrl::fromLocalFile(m_latteView->containment()->corona()->kPackage().filePath(tempFilePath)); setSource(source); syncGeometry(); syncSlideEffect(); qDebug() << "dock config view : initialization ended..."; } inline Qt::WindowFlags PrimaryConfigView::wFlags() const { return (flags() | Qt::FramelessWindowHint) & ~Qt::WindowDoesNotAcceptFocus; } QString PrimaryConfigView::validTitle() const { return QString("#primaryconfig#" + QString::number(m_latteView->containment()->id())); } QQuickView *PrimaryConfigView::secondaryWindow() { return m_secConfigView; } void PrimaryConfigView::createSecondaryWindow() { if (m_secConfigView) { return; } m_secConfigView = new SecondaryConfigView(m_latteView, this); m_secConfigView->init(); } void PrimaryConfigView::deleteSecondaryWindow() { if (m_secConfigView) { auto secWindow = m_secConfigView; m_secConfigView = nullptr; secWindow->deleteLater(); if (KWindowSystem::isPlatformX11() && m_latteView->effects()) { //! this is needed in order for subtracked mask of secondary window to //! be released properly when changing for Advanced to Basic mode. //! Under wayland this is not needed because masks do not break any visuals. m_latteView->effects()->updateMask(); } } } void PrimaryConfigView::updateAvailableScreenGeometry(View *origin) { int currentScrId = m_latteView->positioner()->currentScreenId(); QList ignoreModes{Latte::Types::SideBar}; if (m_latteView->visibility() && m_latteView->visibility()->mode() == Latte::Types::SideBar) { ignoreModes.removeAll(Latte::Types::SideBar); } m_availableScreenGeometry = m_corona->availableScreenRectWithCriteria(currentScrId, QString(), ignoreModes, {}, false); emit availableScreenGeometryChanged(); } QRect PrimaryConfigView::availableScreenGeometry() const { return m_availableScreenGeometry; } QRect PrimaryConfigView::geometryWhenVisible() const { return m_geometryWhenVisible; } void PrimaryConfigView::requestActivate() { if (KWindowSystem::isPlatformWayland() && m_shellSurface) { updateWaylandId(); m_corona->wm()->requestActivate(m_waylandWindowId); } else { QQuickView::requestActivate(); } } void PrimaryConfigView::syncGeometry() { if (!m_latteView || !m_latteView->layout() || !m_latteView->containment() || !rootObject()) { return; } const QSize size(rootObject()->width(), rootObject()->height()); setMaximumSize(size); setMinimumSize(size); resize(size); const auto location = m_latteView->containment()->location(); const auto scrGeometry = m_latteView->screenGeometry(); const auto availGeometry = m_availableScreenGeometry; int clearThickness = m_latteView->editThickness(); QPoint position{0, 0}; int xPos{0}; int yPos{0}; switch (m_latteView->formFactor()) { case Plasma::Types::Horizontal: { if (m_inAdvancedMode) { if (qApp->isLeftToRight()) { xPos = availGeometry.x() + availGeometry.width() - size.width(); } else { xPos = availGeometry.x(); } } else { xPos = scrGeometry.center().x() - size.width() / 2; } if (location == Plasma::Types::TopEdge) { yPos = scrGeometry.y() + clearThickness; } else if (location == Plasma::Types::BottomEdge) { yPos = scrGeometry.y() + scrGeometry.height() - clearThickness - size.height(); } } break; case Plasma::Types::Vertical: { if (location == Plasma::Types::LeftEdge) { xPos = scrGeometry.x() + clearThickness; yPos = availGeometry.y() + (availGeometry.height() - size.height())/2; } else if (location == Plasma::Types::RightEdge) { xPos = scrGeometry.x() + scrGeometry.width() - clearThickness - size.width(); yPos = availGeometry.y() + (availGeometry.height() - size.height())/2; } } break; default: qWarning() << "no sync geometry, wrong formFactor"; break; } position = {xPos, yPos}; updateEnabledBorders(); m_geometryWhenVisible = QRect(position.x(), position.y(), size.width(), size.height()); setPosition(position); if (m_shellSurface) { m_shellSurface->setPosition(position); } updateShowInlineProperties(); emit m_latteView->configWindowGeometryChanged(); } void PrimaryConfigView::syncSlideEffect() { if (!m_latteView || !m_latteView->containment()) { return; } auto slideLocation = WindowSystem::AbstractWindowInterface::Slide::None; switch (m_latteView->containment()->location()) { case Plasma::Types::TopEdge: slideLocation = WindowSystem::AbstractWindowInterface::Slide::Top; break; case Plasma::Types::RightEdge: slideLocation = WindowSystem::AbstractWindowInterface::Slide::Right; break; case Plasma::Types::BottomEdge: slideLocation = WindowSystem::AbstractWindowInterface::Slide::Bottom; break; case Plasma::Types::LeftEdge: slideLocation = WindowSystem::AbstractWindowInterface::Slide::Left; break; default: qDebug() << staticMetaObject.className() << "wrong location"; break; } m_corona->wm()->slideWindow(*this, slideLocation); } void PrimaryConfigView::showEvent(QShowEvent *ev) { QQuickWindow::showEvent(ev); if (!m_latteView) { return; } setFlags(wFlags()); m_corona->wm()->setViewExtraFlags(this, false, Latte::Types::NormalWindow); syncGeometry(); syncSlideEffect(); if (m_latteView && m_latteView->containment()) m_latteView->containment()->setUserConfiguring(true); m_screenSyncTimer.start(); QTimer::singleShot(400, this, &PrimaryConfigView::syncGeometry); emit showSignal(); } void PrimaryConfigView::hideEvent(QHideEvent *ev) { if (!m_latteView) { deleteLater(); //QQuickWindow::hideEvent(ev); return; } if (m_latteView->containment()) { m_latteView->containment()->setUserConfiguring(false); } // QQuickWindow::hideEvent(ev); const auto mode = m_latteView->visibility()->mode(); if ((mode == Types::AlwaysVisible || mode == Types::WindowsGoBelow) && !(m_originalMode == Types::AlwaysVisible || m_originalMode == Types::WindowsGoBelow)) { //! mode changed to AlwaysVisible OR WindowsGoBelow FROM Dodge mode if (m_originalByPassWM) { //! if original by pass is active m_latteView->layout()->recreateView(m_latteView->containment()); } } else if (m_latteView->byPassWM() != m_originalByPassWM) { m_latteView->layout()->recreateView(m_latteView->containment()); } deleteLater(); } void PrimaryConfigView::focusOutEvent(QFocusEvent *ev) { Q_UNUSED(ev); const auto *focusWindow = qGuiApp->focusWindow(); if (!m_latteView || (focusWindow && (focusWindow->flags().testFlag(Qt::Popup) || focusWindow->flags().testFlag(Qt::ToolTip))) || m_latteView->alternativesIsShown()) { return; } if (!m_blockFocusLost && !m_latteView->containsMouse() && (!m_secConfigView || (m_secConfigView && !m_secConfigView->isActive()))) { hideConfigWindow(); } } void PrimaryConfigView::setupWaylandIntegration() { if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_latteView || !m_latteView->containment()) { // already setup return; } if (m_corona) { using namespace KWayland::Client; PlasmaShell *interface = m_corona->waylandCoronaInterface(); if (!interface) { return; } Surface *s = Surface::fromWindow(this); if (!s) { return; } qDebug() << "wayland primary settings surface was created..."; m_shellSurface = interface->createSurface(s, this); m_corona->wm()->setViewExtraFlags(m_shellSurface, false); syncGeometry(); } } bool PrimaryConfigView::event(QEvent *e) { if (e->type() == QEvent::PlatformSurface) { if (auto pe = dynamic_cast(e)) { switch (pe->surfaceEventType()) { case QPlatformSurfaceEvent::SurfaceCreated: if (m_shellSurface) { break; } setupWaylandIntegration(); break; case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: if (m_shellSurface) { delete m_shellSurface; m_shellSurface = nullptr; qDebug() << "WAYLAND config window surface was deleted..."; } break; } } } return PlasmaQuick::ConfigView::event(e); } void PrimaryConfigView::immutabilityChanged(Plasma::Types::ImmutabilityType type) { if (type != Plasma::Types::Mutable && isVisible()) hideConfigWindow(); } bool PrimaryConfigView::sticker() const { return m_blockFocusLost; } void PrimaryConfigView::setSticker(bool blockFocusLost) { if (m_blockFocusLost == blockFocusLost) return; m_blockFocusLost = blockFocusLost; } bool PrimaryConfigView::showInlineProperties() const { return m_showInlineProperties; } void PrimaryConfigView::setShowInlineProperties(bool show) { if (m_showInlineProperties == show) { return; } m_showInlineProperties = show; emit showInlinePropertiesChanged(); } void PrimaryConfigView::updateShowInlineProperties() { if (!m_latteView) { return; } bool showSecWindow{false}; bool advancedApprovedSecWindow{false}; if (m_inAdvancedMode && m_latteView->formFactor() != Plasma::Types::Vertical) { showSecWindow = true; advancedApprovedSecWindow = true; } //! consider screen geometry for showing or not the secondary window if (!geometryWhenVisible().isNull()) { createSecondaryWindow(); if (m_secConfigView->geometryWhenVisible().intersects(geometryWhenVisible())) { showSecWindow = false; } else if (advancedApprovedSecWindow) { showSecWindow = true; } } if (showSecWindow) { if (!m_secConfigView) { createSecondaryWindow(); } QTimer::singleShot(150, m_secConfigView, SLOT(show())); setShowInlineProperties(false); } else { deleteSecondaryWindow(); setShowInlineProperties(true); } // qDebug() << " showSecWindow:" << showSecWindow << " _ " << " inline:"<< !showSecWindow; } void PrimaryConfigView::updateWaylandId() { Latte::WindowSystem::WindowId newId = m_corona->wm()->winIdFor("latte-dock", validTitle()); if (m_waylandWindowId != newId) { if (!m_waylandWindowId.isNull()) { m_corona->wm()->unregisterIgnoredWindow(m_waylandWindowId); } m_waylandWindowId = newId; m_corona->wm()->registerIgnoredWindow(m_waylandWindowId); } } bool PrimaryConfigView::inAdvancedMode() const { return m_inAdvancedMode; } void PrimaryConfigView::setInAdvancedMode(bool advanced) { if (m_inAdvancedMode == advanced) { return; } m_inAdvancedMode = advanced; emit inAdvancedModeChanged(); } void PrimaryConfigView::hideConfigWindow() { if (m_shellSurface) { //!NOTE: Avoid crash in wayland environment with qt5.9 close(); } else { hide(); } } void PrimaryConfigView::updateLaunchersForGroup(int groupInt) { Types::LaunchersGroup group = (Types::LaunchersGroup)groupInt; //! when the layout/global launchers list is empty then the current dock launchers are used for them //! as a start point if (m_corona && m_latteView->layout()) { if ((group == Types::LayoutLaunchers && m_latteView->layout()->launchers().isEmpty()) || (group == Types::GlobalLaunchers && m_corona->universalSettings()->launchers().isEmpty())) { Plasma::Containment *c = m_latteView->containment(); const auto &applets = c->applets(); for (auto *applet : applets) { KPluginMetaData meta = applet->kPackage().metadata(); if (meta.pluginId() == "org.kde.latte.plasmoid") { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { // not using QMetaObject::invokeMethod to avoid warnings when calling // this on applets that don't have it or other child items since this // is pretty much trial and error. // Also, "var" arguments are treated as QVariant in QMetaObject int methodIndex = metaObject->indexOfMethod("getLauncherList()"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); QVariant launchers; if (method.invoke(item, Q_RETURN_ARG(QVariant, launchers))) { if (group == Types::LayoutLaunchers) { m_latteView->layout()->setLaunchers(launchers.toStringList()); } else if (group == Types::GlobalLaunchers) { m_corona->universalSettings()->setLaunchers(launchers.toStringList()); } } } } } } } } } } //!BEGIN borders Plasma::FrameSvg::EnabledBorders PrimaryConfigView::enabledBorders() const { return m_enabledBorders; } void PrimaryConfigView::updateEnabledBorders() { if (!this->screen()) { return; } Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; switch (m_latteView->location()) { case Plasma::Types::TopEdge: borders &= m_inReverse ? ~Plasma::FrameSvg::BottomBorder : ~Plasma::FrameSvg::TopBorder; break; case Plasma::Types::LeftEdge: borders &= ~Plasma::FrameSvg::LeftBorder; break; case Plasma::Types::RightEdge: borders &= ~Plasma::FrameSvg::RightBorder; break; case Plasma::Types::BottomEdge: borders &= m_inReverse ? ~Plasma::FrameSvg::TopBorder : ~Plasma::FrameSvg::BottomBorder; break; default: break; } if (m_enabledBorders != borders) { m_enabledBorders = borders; m_corona->dialogShadows()->addWindow(this, m_enabledBorders); emit enabledBordersChanged(); } } //!END borders void PrimaryConfigView::updateEffects() { //! Don't apply any effect before the wayland surface is created under wayland //! https://bugs.kde.org/show_bug.cgi?id=392890 if (KWindowSystem::isPlatformWayland() && !m_shellSurface) { return; } if (!m_background) { m_background = new Plasma::FrameSvg(this); } if (m_background->imagePath() != "widgets/panel-background") { m_background->setImagePath(QStringLiteral("widgets/panel-background")); } m_background->setEnabledBorders(m_enabledBorders); m_background->resizeFrame(size()); QRegion mask = m_background->mask(); QRegion fixedMask = mask.isNull() ? QRegion(QRect(0,0,width(),height())) : mask; if (!fixedMask.isEmpty()) { setMask(fixedMask); } else { setMask(QRegion()); } if (KWindowSystem::compositingActive()) { KWindowEffects::enableBlurBehind(winId(), true, fixedMask); } else { KWindowEffects::enableBlurBehind(winId(), false); } } //!BEGIN configuration void PrimaryConfigView::loadConfig() { if (!m_latteView || !m_latteView->containment()) { return; } auto config = m_latteView->containment()->config(); int complexity = config.readEntry("settingsComplexity", 0); setInAdvancedMode(complexity>0); } void PrimaryConfigView::saveConfig() { if (!m_latteView || !m_latteView->containment()) { return; } auto config = m_latteView->containment()->config(); int complexity = m_inAdvancedMode ? 1 : 0; config.writeEntry("settingsComplexity", complexity); } //!END configuration } }