diff --git a/app/view/indicator/indicator.cpp b/app/view/indicator/indicator.cpp index 0e51983c..defedde7 100644 --- a/app/view/indicator/indicator.cpp +++ b/app/view/indicator/indicator.cpp @@ -1,459 +1,460 @@ /* * 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 "indicatorinfo.h" #include "../view.h" #include "../../lattecorona.h" #include "../../indicator/factory.h" #include "../../../liblatte2/types.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::enabledForAppletsChanged, this, &Indicator::saveConfig); connect(this, &Indicator::paddingChanged, 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() { 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::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(); } float Indicator::padding() const { return m_padding; } void Indicator::setPadding(float padding) { if (m_padding == padding) { return; } m_padding = padding; emit paddingChanged(); } 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.plasma"); 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::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_enabledForApplets = config.readEntry("enabledForApplets", true); m_padding = config.readEntry("padding", (float)0.08); 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("enabledForApplets", m_enabledForApplets); config.writeEntry("padding", m_padding); config.writeEntry("type", m_type); config.sync(); } } } diff --git a/app/view/settings/CMakeLists.txt b/app/view/settings/CMakeLists.txt index 2fb856d3..9b93441a 100644 --- a/app/view/settings/CMakeLists.txt +++ b/app/view/settings/CMakeLists.txt @@ -1,7 +1,6 @@ set(lattedock-app_SRCS ${lattedock-app_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/primaryconfigview.cpp ${CMAKE_CURRENT_SOURCE_DIR}/secondaryconfigview.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dialogshadows.cpp PARENT_SCOPE ) diff --git a/app/view/settings/dialogshadows.cpp b/app/view/settings/dialogshadows.cpp deleted file mode 100644 index 12ac35b2..00000000 --- a/app/view/settings/dialogshadows.cpp +++ /dev/null @@ -1,747 +0,0 @@ -/* -* Copyright 2011 by Aaron Seigo -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU Library General Public License version 2, -* 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 Library General Public -* License along with this program; if not, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "dialogshadows_p.h" - -#include -#include -#include - -#include -#if HAVE_X11 -#include -#include -#include -#include -#include -#endif - -#if HAVE_KWAYLAND -#include -#include -#include -#include -#include -#include -#endif - -#include - -class DialogShadows::Private -{ -public: - Private(DialogShadows *shadows) - : q(shadows) -#if HAVE_X11 - , _connection(nullptr) - , _gc(0x0) - , m_isX11(KWindowSystem::isPlatformX11()) -#endif - { - setupWaylandIntegration(); - } - - ~Private() - { - // Do not call clearPixmaps() from here: it creates new QPixmap(), - // which causes a crash when application is stopping. - freeX11Pixmaps(); - } - - void freeX11Pixmaps(); - void freeWaylandBuffers(); - void clearPixmaps(); - void setupPixmaps(); - Qt::HANDLE createPixmap(const QPixmap &source); - void initPixmap(const QString &element); - QPixmap initEmptyPixmap(const QSize &size); - void updateShadow(const QWindow *window, Plasma::FrameSvg::EnabledBorders); - void updateShadowX11(const QWindow *window, Plasma::FrameSvg::EnabledBorders); - void updateShadowWayland(const QWindow *window, Plasma::FrameSvg::EnabledBorders); - void clearShadow(const QWindow *window); - void clearShadowX11(const QWindow *window); - void clearShadowWayland(const QWindow *window); - void updateShadows(); - void windowDestroyed(QObject *deletedObject); - void setupData(Plasma::FrameSvg::EnabledBorders enabledBorders); - - void setupWaylandIntegration(); - - DialogShadows *q; - QList m_shadowPixmaps; - - QPixmap m_emptyCornerPix; - QPixmap m_emptyCornerLeftPix; - QPixmap m_emptyCornerTopPix; - QPixmap m_emptyCornerRightPix; - QPixmap m_emptyCornerBottomPix; - QPixmap m_emptyVerticalPix; - QPixmap m_emptyHorizontalPix; - -#if HAVE_X11 - //! xcb connection - xcb_connection_t *_connection; - - //! graphical context - xcb_gcontext_t _gc; - bool m_isX11; -#endif - -#if HAVE_KWAYLAND - struct Wayland { - KWayland::Client::ShadowManager *manager = nullptr; - KWayland::Client::ShmPool *shmPool = nullptr; - KWayland::Client::PlasmaShell *plasmaShell = nullptr; - - QList shadowBuffers; - }; - Wayland m_wayland; -#endif - - QHash > data; - QHash m_windows; -}; - -class DialogShadowsSingleton -{ -public: - DialogShadowsSingleton() - { - } - - DialogShadows self; -}; - -Q_GLOBAL_STATIC(DialogShadowsSingleton, privateDialogShadowsSelf) - -DialogShadows::DialogShadows(QObject *parent, const QString &prefix) - : Plasma::Svg(parent), - d(new Private(this)) -{ - setImagePath(prefix); - connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateShadows())); -} - -DialogShadows::~DialogShadows() -{ - delete d; -} - -DialogShadows *DialogShadows::self() -{ - return &privateDialogShadowsSelf->self; -} - -void DialogShadows::addWindow(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) -{ - if (!window) { - return; - } - - d->m_windows[window] = enabledBorders; - d->updateShadow(window, enabledBorders); - connect(window, SIGNAL(destroyed(QObject*)), - this, SLOT(windowDestroyed(QObject*)), Qt::UniqueConnection); -} - -void DialogShadows::removeWindow(const QWindow *window) -{ - if (!d->m_windows.contains(window)) { - return; - } - - d->m_windows.remove(window); - disconnect(window, nullptr, this, nullptr); - d->clearShadow(window); - - if (d->m_windows.isEmpty()) { - d->clearPixmaps(); - } -} - -void DialogShadows::setEnabledBorders(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) -{ - if (!window || !d->m_windows.contains(window)) { - return; - } - - d->updateShadow(window, enabledBorders); -} - - -void DialogShadows::Private::windowDestroyed(QObject *deletedObject) -{ - m_windows.remove(static_cast(deletedObject)); - - if (m_windows.isEmpty()) { - clearPixmaps(); - } -} - -void DialogShadows::Private::updateShadows() -{ - setupPixmaps(); - QHash::const_iterator i; - for (i = m_windows.constBegin(); i != m_windows.constEnd(); ++i) { - updateShadow(i.key(), i.value()); - } -} - -Qt::HANDLE DialogShadows::Private::createPixmap(const QPixmap &source) -{ - - // do nothing for invalid pixmaps - if (source.isNull()) { - return nullptr; - } - - /* - in some cases, pixmap handle is invalid. This is the case notably - when Qt uses to RasterEngine. In this case, we create an X11 Pixmap - explicitly and draw the source pixmap on it. - */ - -#if HAVE_X11 - if (!m_isX11) { - return nullptr; - } - - // check connection - if (!_connection) { - _connection = QX11Info::connection(); - } - - const int width(source.width()); - const int height(source.height()); - - // create X11 pixmap - Pixmap pixmap = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), width, height, 32); - - // check gc - if (!_gc) { - _gc = xcb_generate_id(_connection); - xcb_create_gc(_connection, _gc, pixmap, 0, nullptr); - } - -// // create explicitly shared QPixmap from it -// QPixmap dest( QPixmap::fromX11Pixmap( pixmap, QPixmap::ExplicitlyShared ) ); -// -// // create surface for pixmap -// { -// QPainter painter( &dest ); -// painter.setCompositionMode( QPainter::CompositionMode_Source ); -// painter.drawPixmap( 0, 0, source ); -// } -// -// -// return pixmap; - QImage image(source.toImage()); - xcb_put_image( - _connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, _gc, - image.width(), image.height(), 0, 0, - 0, 32, - image.sizeInBytes(), image.constBits()); - - return (Qt::HANDLE)pixmap; - -#else - return nullptr; -#endif - -} - -void DialogShadows::Private::initPixmap(const QString &element) -{ - m_shadowPixmaps << q->pixmap(element); -} - -QPixmap DialogShadows::Private::initEmptyPixmap(const QSize &size) -{ -#if HAVE_X11 - if (!m_isX11) { - return QPixmap(); - } - QPixmap tempEmptyPix(size); - if (!size.isEmpty()) { - tempEmptyPix.fill(Qt::transparent); - } - return tempEmptyPix; -#else - Q_UNUSED(size) - return QPixmap(); -#endif -} - -void DialogShadows::Private::setupPixmaps() -{ - clearPixmaps(); - initPixmap(QStringLiteral("shadow-top")); - initPixmap(QStringLiteral("shadow-topright")); - initPixmap(QStringLiteral("shadow-right")); - initPixmap(QStringLiteral("shadow-bottomright")); - initPixmap(QStringLiteral("shadow-bottom")); - initPixmap(QStringLiteral("shadow-bottomleft")); - initPixmap(QStringLiteral("shadow-left")); - initPixmap(QStringLiteral("shadow-topleft")); - - m_emptyCornerPix = initEmptyPixmap(QSize(1, 1)); - m_emptyCornerLeftPix = initEmptyPixmap(QSize(q->elementSize(QStringLiteral("shadow-topleft")).width(), 1)); - m_emptyCornerTopPix = initEmptyPixmap(QSize(1, q->elementSize(QStringLiteral("shadow-topleft")).height())); - m_emptyCornerRightPix = initEmptyPixmap(QSize(q->elementSize(QStringLiteral("shadow-bottomright")).width(), 1)); - m_emptyCornerBottomPix = initEmptyPixmap(QSize(1, q->elementSize(QStringLiteral("shadow-bottomright")).height())); - m_emptyVerticalPix = initEmptyPixmap(QSize(1, q->elementSize(QStringLiteral("shadow-left")).height())); - m_emptyHorizontalPix = initEmptyPixmap(QSize(q->elementSize(QStringLiteral("shadow-top")).width(), 1)); - -#if HAVE_KWAYLAND - if (m_wayland.shmPool) { - for (auto it = m_shadowPixmaps.constBegin(); it != m_shadowPixmaps.constEnd(); ++it) { - m_wayland.shadowBuffers << m_wayland.shmPool->createBuffer(it->toImage()); - } - } -#endif -} - -void DialogShadows::Private::setupData(Plasma::FrameSvg::EnabledBorders enabledBorders) -{ -#if HAVE_X11 - if (!m_isX11) { - return; - } - //shadow-top - if (enabledBorders & Plasma::FrameSvg::TopBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_shadowPixmaps[0])); - } else { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyHorizontalPix)); - } - - //shadow-topright - if (enabledBorders & Plasma::FrameSvg::TopBorder && - enabledBorders & Plasma::FrameSvg::RightBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_shadowPixmaps[1])); - } else if (enabledBorders & Plasma::FrameSvg::TopBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerTopPix)); - } else if (enabledBorders & Plasma::FrameSvg::RightBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerRightPix)); - } else { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerPix)); - } - - //shadow-right - if (enabledBorders & Plasma::FrameSvg::RightBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_shadowPixmaps[2])); - } else { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyVerticalPix)); - } - - //shadow-bottomright - if (enabledBorders & Plasma::FrameSvg::BottomBorder && - enabledBorders & Plasma::FrameSvg::RightBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_shadowPixmaps[3])); - } else if (enabledBorders & Plasma::FrameSvg::BottomBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerBottomPix)); - } else if (enabledBorders & Plasma::FrameSvg::RightBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerRightPix)); - } else { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerPix)); - } - - //shadow-bottom - if (enabledBorders & Plasma::FrameSvg::BottomBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_shadowPixmaps[4])); - } else { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyHorizontalPix)); - } - - //shadow-bottomleft - if (enabledBorders & Plasma::FrameSvg::BottomBorder && - enabledBorders & Plasma::FrameSvg::LeftBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_shadowPixmaps[5])); - } else if (enabledBorders & Plasma::FrameSvg::BottomBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerBottomPix)); - } else if (enabledBorders & Plasma::FrameSvg::LeftBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerLeftPix)); - } else { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerPix)); - } - - //shadow-left - if (enabledBorders & Plasma::FrameSvg::LeftBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_shadowPixmaps[6])); - } else { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyVerticalPix)); - } - - //shadow-topleft - if (enabledBorders & Plasma::FrameSvg::TopBorder && - enabledBorders & Plasma::FrameSvg::LeftBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_shadowPixmaps[7])); - } else if (enabledBorders & Plasma::FrameSvg::TopBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerTopPix)); - } else if (enabledBorders & Plasma::FrameSvg::LeftBorder) { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerLeftPix)); - } else { - data[enabledBorders] << reinterpret_cast(createPixmap(m_emptyCornerPix)); - } -#endif - - int left, top, right, bottom = 0; - - QSize marginHint; - if (enabledBorders & Plasma::FrameSvg::TopBorder) { - marginHint = q->elementSize(QStringLiteral("shadow-hint-top-margin")); - if (marginHint.isValid()) { - top = marginHint.height(); - } else { - top = m_shadowPixmaps[0].height(); // top - } - } else { - top = 1; - } - - if (enabledBorders & Plasma::FrameSvg::RightBorder) { - marginHint = q->elementSize(QStringLiteral("shadow-hint-right-margin")); - if (marginHint.isValid()) { - right = marginHint.width(); - } else { - right = m_shadowPixmaps[2].width(); // right - } - } else { - right = 1; - } - - if (enabledBorders & Plasma::FrameSvg::BottomBorder) { - marginHint = q->elementSize(QStringLiteral("shadow-hint-bottom-margin")); - if (marginHint.isValid()) { - bottom = marginHint.height(); - } else { - bottom = m_shadowPixmaps[4].height(); // bottom - } - } else { - bottom = 1; - } - - if (enabledBorders & Plasma::FrameSvg::LeftBorder) { - marginHint = q->elementSize(QStringLiteral("shadow-hint-left-margin")); - if (marginHint.isValid()) { - left = marginHint.width(); - } else { - left = m_shadowPixmaps[6].width(); // left - } - } else { - left = 1; - } - - data[enabledBorders] << top << right << bottom << left; -} - -void DialogShadows::Private::freeX11Pixmaps() -{ -#if HAVE_X11 - if (!m_isX11) { - return; - } - - auto *display = QX11Info::display(); - if (!display) { - return; - } - - foreach (const QPixmap &pixmap, m_shadowPixmaps) { - if (!pixmap.isNull()) { - XFreePixmap(display, reinterpret_cast(createPixmap(pixmap))); - } - } - - if (!m_emptyCornerPix.isNull()) { - XFreePixmap(display, reinterpret_cast(createPixmap(m_emptyCornerPix))); - } - if (!m_emptyCornerBottomPix.isNull()) { - XFreePixmap(display, reinterpret_cast(createPixmap(m_emptyCornerBottomPix))); - } - if (!m_emptyCornerLeftPix.isNull()) { - XFreePixmap(display, reinterpret_cast(createPixmap(m_emptyCornerLeftPix))); - } - if (!m_emptyCornerRightPix.isNull()) { - XFreePixmap(display, reinterpret_cast(createPixmap(m_emptyCornerRightPix))); - } - if (!m_emptyCornerTopPix.isNull()) { - XFreePixmap(display, reinterpret_cast(createPixmap(m_emptyCornerTopPix))); - } - if (!m_emptyVerticalPix.isNull()) { - XFreePixmap(display, reinterpret_cast(createPixmap(m_emptyVerticalPix))); - } - if (!m_emptyHorizontalPix.isNull()) { - XFreePixmap(display, reinterpret_cast(createPixmap(m_emptyHorizontalPix))); - } -#endif -} - -void DialogShadows::Private::clearPixmaps() -{ -#if HAVE_X11 - freeX11Pixmaps(); - - m_emptyCornerPix = QPixmap(); - m_emptyCornerBottomPix = QPixmap(); - m_emptyCornerLeftPix = QPixmap(); - m_emptyCornerRightPix = QPixmap(); - m_emptyCornerTopPix = QPixmap(); - m_emptyVerticalPix = QPixmap(); - m_emptyHorizontalPix = QPixmap(); -#endif - freeWaylandBuffers(); - m_shadowPixmaps.clear(); - data.clear(); -} - -void DialogShadows::Private::freeWaylandBuffers() -{ -#if HAVE_KWAYLAND - m_wayland.shadowBuffers.clear(); -#endif -} - -void DialogShadows::Private::updateShadow(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) -{ -#if HAVE_X11 - if (m_isX11) { - updateShadowX11(window, enabledBorders); - } -#endif -#if HAVE_KWAYLAND - if (m_wayland.manager) { - updateShadowWayland(window, enabledBorders); - } -#endif -} - -void DialogShadows::Private::updateShadowX11(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) -{ -#if HAVE_X11 - if (m_shadowPixmaps.isEmpty()) { - setupPixmaps(); - } - - if (!data.contains(enabledBorders)) { - setupData(enabledBorders); - } - - Display *dpy = QX11Info::display(); - Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SHADOW", False); - - //qDebug() << "going to set the shadow of" << window->winId() << "to" << data; - XChangeProperty(dpy, window->winId(), atom, XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast(data[enabledBorders].constData()), data[enabledBorders].size()); -#endif -} - -void DialogShadows::Private::updateShadowWayland(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders) -{ -#if HAVE_KWAYLAND - if (!m_wayland.shmPool) { - return; - } - if (m_wayland.shadowBuffers.isEmpty()) { - setupPixmaps(); - } - // TODO: check whether the surface already has a shadow - KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(const_cast(window)); - if (!surface) { - return; - } - auto shadow = m_wayland.manager->createShadow(surface, surface); - - //shadow-top - if (enabledBorders & Plasma::FrameSvg::TopBorder) { - shadow->attachTop(m_wayland.shadowBuffers.at(0)); - } - - //shadow-topright - if (enabledBorders & Plasma::FrameSvg::TopBorder && - enabledBorders & Plasma::FrameSvg::RightBorder) { - shadow->attachTopRight(m_wayland.shadowBuffers.at(1)); - } - - //shadow-right - if (enabledBorders & Plasma::FrameSvg::RightBorder) { - shadow->attachRight(m_wayland.shadowBuffers.at(2)); - } - - //shadow-bottomright - if (enabledBorders & Plasma::FrameSvg::BottomBorder && - enabledBorders & Plasma::FrameSvg::RightBorder) { - shadow->attachBottomRight(m_wayland.shadowBuffers.at(3)); - } - - //shadow-bottom - if (enabledBorders & Plasma::FrameSvg::BottomBorder) { - shadow->attachBottom(m_wayland.shadowBuffers.at(4)); - } - - //shadow-bottomleft - if (enabledBorders & Plasma::FrameSvg::BottomBorder && - enabledBorders & Plasma::FrameSvg::LeftBorder) { - shadow->attachBottomLeft(m_wayland.shadowBuffers.at(5)); - } - - //shadow-left - if (enabledBorders & Plasma::FrameSvg::LeftBorder) { - shadow->attachLeft(m_wayland.shadowBuffers.at(6)); - } - - //shadow-topleft - if (enabledBorders & Plasma::FrameSvg::TopBorder && - enabledBorders & Plasma::FrameSvg::LeftBorder) { - shadow->attachTopLeft(m_wayland.shadowBuffers.at(7)); - } - - QSize marginHint; - QMarginsF margins; - if (enabledBorders & Plasma::FrameSvg::TopBorder) { - marginHint = q->elementSize(QStringLiteral("shadow-hint-top-margin")); - if (marginHint.isValid()) { - margins.setTop(marginHint.height()); - } else { - margins.setTop(m_shadowPixmaps[0].height()); - } - } - - if (enabledBorders & Plasma::FrameSvg::RightBorder) { - marginHint = q->elementSize(QStringLiteral("shadow-hint-right-margin")); - if (marginHint.isValid()) { - margins.setRight(marginHint.width()); - } else { - margins.setRight(m_shadowPixmaps[2].width()); - } - } - - if (enabledBorders & Plasma::FrameSvg::BottomBorder) { - marginHint = q->elementSize(QStringLiteral("shadow-hint-bottom-margin")); - if (marginHint.isValid()) { - margins.setBottom(marginHint.height()); - } else { - margins.setBottom(m_shadowPixmaps[4].height()); - } - } - - if (enabledBorders & Plasma::FrameSvg::LeftBorder) { - marginHint = q->elementSize(QStringLiteral("shadow-hint-left-margin")); - if (marginHint.isValid()) { - margins.setLeft(marginHint.width()); - } else { - margins.setLeft(m_shadowPixmaps[6].width()); - } - } - - shadow->setOffsets(margins); - shadow->commit(); - surface->commit(KWayland::Client::Surface::CommitFlag::None); -#endif -} - -void DialogShadows::Private::clearShadow(const QWindow *window) -{ - if (!static_cast(window)->surfaceHandle()) { - qWarning() << "Cannot clear shadow from window without native surface!"; - return; - } -#if HAVE_X11 - if (m_isX11) { - clearShadowX11(window); - } -#endif -#if HAVE_KWAYLAND - if (m_wayland.manager) { - clearShadowWayland(window); - } -#endif -} - -void DialogShadows::Private::clearShadowX11(const QWindow* window) -{ -#if HAVE_X11 - Display *dpy = QX11Info::display(); - Atom atom = XInternAtom(dpy, "_KDE_NET_WM_SHADOW", False); - XDeleteProperty(dpy, window->winId(), atom); -#endif -} - -void DialogShadows::Private::clearShadowWayland(const QWindow *window) -{ -#if HAVE_KWAYLAND - KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(const_cast(window)); - if (!surface) { - return; - } - m_wayland.manager->removeShadow(surface); - surface->commit(KWayland::Client::Surface::CommitFlag::None); -#endif -} - -bool DialogShadows::enabled() const -{ - return hasElement(QStringLiteral("shadow-left")); -} - -KWayland::Client::PlasmaShell *DialogShadows::waylandPlasmaShellInterface() const -{ -#if HAVE_KWAYLAND - return d->m_wayland.plasmaShell; -#else - return nullptr; -#endif -} - -void DialogShadows::Private::setupWaylandIntegration() -{ -#if HAVE_KWAYLAND - if (!KWindowSystem::isPlatformWayland()) { - return; - } - using namespace KWayland::Client; - ConnectionThread *connection = ConnectionThread::fromApplication(q); - if (!connection) { - return; - } - Registry *registry = new Registry(q); - registry->create(connection); - connect(registry, &Registry::shadowAnnounced, q, - [this, registry] (quint32 name, quint32 version) { - m_wayland.manager = registry->createShadowManager(name, version, q); - updateShadows(); - }, Qt::QueuedConnection - ); - connect(registry, &Registry::shmAnnounced, q, - [this, registry] (quint32 name, quint32 version) { - m_wayland.shmPool = registry->createShmPool(name, version, q); - updateShadows(); - }, Qt::QueuedConnection - ); - connect(registry, &Registry::plasmaShellAnnounced, q, - [this, registry] (quint32 name, quint32 version) { - m_wayland.plasmaShell = registry->createPlasmaShell(name, version, q); - } - ); - registry->setup(); - connection->roundtrip(); -#endif -} - -#include "moc_dialogshadows_p.cpp" - - diff --git a/app/view/settings/dialogshadows_p.h b/app/view/settings/dialogshadows_p.h deleted file mode 100644 index 8d370327..00000000 --- a/app/view/settings/dialogshadows_p.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -* Copyright 2011 by Aaron Seigo -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU Library General Public License version 2, -* 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 Library General Public -* License along with this program; if not, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef PLASMA_DIALOGSHADOWS_H -#define PLASMA_DIALOGSHADOWS_H - -#include - -#include "plasma/framesvg.h" -#include "plasma/svg.h" - -namespace KWayland -{ - namespace Client - { - class PlasmaShell; - } -} - -class DialogShadows : public Plasma::Svg -{ - Q_OBJECT - -public: - explicit DialogShadows(QObject *parent = nullptr, const QString &prefix = QStringLiteral("dialogs/background")); - ~DialogShadows(); - - static DialogShadows *self(); - - void addWindow(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders = Plasma::FrameSvg::AllBorders); - void removeWindow(const QWindow *window); - - void setEnabledBorders(const QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders = Plasma::FrameSvg::AllBorders); - - bool enabled() const; - - KWayland::Client::PlasmaShell *waylandPlasmaShellInterface() const; - -private: - class Private; - Private *const d; - - Q_PRIVATE_SLOT(d, void updateShadows()) - Q_PRIVATE_SLOT(d, void windowDestroyed(QObject *deletedObject)) -}; - -#endif - - diff --git a/app/view/settings/primaryconfigview.cpp b/app/view/settings/primaryconfigview.cpp index 327d0af8..a3e6ca2d 100644 --- a/app/view/settings/primaryconfigview.cpp +++ b/app/view/settings/primaryconfigview.cpp @@ -1,753 +1,751 @@ /* * 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 "dialogshadows_p.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(); if (KWindowSystem::isPlatformX11()) { m_corona->wm()->registerIgnoredWindow(winId()); } else { connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, [&]() { if (m_waylandWindowId.isNull()) { m_waylandWindowId = m_corona->wm()->winIdFor("latte-dock", geometry()); m_corona->wm()->registerIgnoredWindow(m_waylandWindowId); } }); } setScreen(m_latteView->screen()); if (containment) { setIcon(qGuiApp->windowIcon()); } m_screenSyncTimer.setSingleShot(true); m_screenSyncTimer.setInterval(100); connect(this, &PrimaryConfigView::availableScreenGeometryChanged, this, &PrimaryConfigView::syncGeometry); connect(this, &PrimaryConfigView::complexityChanged, this, &PrimaryConfigView::saveConfig); connect(this, &PrimaryConfigView::complexityChanged, this, &PrimaryConfigView::updateShowInlineProperties); connect(this, &PrimaryConfigView::complexityChanged, this, &PrimaryConfigView::syncGeometry); 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 ..."; - DialogShadows::self()->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(); setDefaultAlphaBuffer(true); setColor(Qt::transparent); - DialogShadows::self()->addWindow(this); + PanelShadows::self()->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; } 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()) { //! 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(); m_availableScreenGeometry = m_corona->availableScreenRectWithCriteria(currentScrId, QString(), {}, {}, true); emit availableScreenGeometryChanged(); } QRect PrimaryConfigView::availableScreenGeometry() const { return m_availableScreenGeometry; } QRect PrimaryConfigView::geometryWhenVisible() const { return m_geometryWhenVisible; } void PrimaryConfigView::requestActivate() { if (KWindowSystem::isPlatformWayland() && m_shellSurface) { if (m_waylandWindowId.isNull()) { m_waylandWindowId = m_corona->wm()->winIdFor("latte-dock", geometry()); } 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_complexity == Latte::Types::ExpertSettings) { 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 complexityApprovedSecWindow{false}; if (m_complexity != Latte::Types::BasicSettings && !(m_complexity == Latte::Types::ExpertSettings && m_latteView->formFactor() == Plasma::Types::Vertical)) { showSecWindow = true; complexityApprovedSecWindow = 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 (complexityApprovedSecWindow) { 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; } int PrimaryConfigView::complexity() const { return (int)m_complexity; } void PrimaryConfigView::setComplexity(int complexity) { if ((int)m_complexity == complexity) { return; } m_complexity = static_cast(complexity); emit complexityChanged(); } 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; - DialogShadows::self()->addWindow(this, m_enabledBorders); + PanelShadows::self()->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; } QRegion mask; QQuickItem *rootObject = this->rootObject(); if (rootObject) { const QVariant maskProperty = rootObject->property("backgroundMask"); if (static_cast(maskProperty.type()) == QMetaType::QRegion) { qDebug() << "found 2..."; mask = maskProperty.value(); } } if (!mask.isEmpty()) { setMask(mask); KWindowEffects::enableBlurBehind(winId(), true, mask); } else { setMask(QRect()); 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", (int)Latte::Types::BasicSettings); setComplexity(static_cast(complexity)); } void PrimaryConfigView::saveConfig() { if (!m_latteView || !m_latteView->containment()) { return; } auto config = m_latteView->containment()->config(); config.writeEntry("settingsComplexity", (int)m_complexity); config.sync(); } //!END configuration } } diff --git a/app/view/settings/secondaryconfigview.cpp b/app/view/settings/secondaryconfigview.cpp index a72e27e0..78a591b9 100644 --- a/app/view/settings/secondaryconfigview.cpp +++ b/app/view/settings/secondaryconfigview.cpp @@ -1,477 +1,475 @@ /* * Copyright 2018 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 "secondaryconfigview.h" // local #include -#include "dialogshadows_p.h" #include "primaryconfigview.h" +#include "../panelshadows_p.h" #include "../view.h" #include "../../lattecorona.h" #include "../../wm/abstractwindowinterface.h" // Qt #include #include #include #include // KDE #include #include #include #include #include #include // Plasma #include namespace Latte { namespace ViewPart { SecondaryConfigView::SecondaryConfigView(Latte::View *view, QWindow *parent) : QQuickView(nullptr), m_latteView(view) { m_parent = qobject_cast(parent); m_corona = qobject_cast(m_latteView->containment()->corona()); setupWaylandIntegration(); if (KWindowSystem::isPlatformX11()) { m_corona->wm()->registerIgnoredWindow(winId()); } else { connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, [&]() { if (m_waylandWindowId.isNull()) { m_waylandWindowId = m_corona->wm()->winIdFor("latte-dock", geometry()); m_corona->wm()->registerIgnoredWindow(m_waylandWindowId); } }); } setResizeMode(QQuickView::SizeViewToRootObject); setScreen(m_latteView->screen()); if (m_latteView && m_latteView->containment()) { setIcon(qGuiApp->windowIcon()); } m_screenSyncTimer.setSingleShot(true); m_screenSyncTimer.setInterval(100); connect(this, &QQuickView::statusChanged, [&](QQuickView::Status status) { if (status == QQuickView::Ready) { updateEffects(); } }); connections << connect(m_parent, &PrimaryConfigView::availableScreenGeometryChanged, this, &SecondaryConfigView::syncGeometry); 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, &SecondaryConfigView::syncGeometry); 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(); }); } SecondaryConfigView::~SecondaryConfigView() { qDebug() << "SecDockConfigView deleting ..."; - DialogShadows::self()->removeWindow(this); - m_corona->wm()->unregisterIgnoredWindow(KWindowSystem::isPlatformX11() ? winId() : m_waylandWindowId); for (const auto &var : connections) { QObject::disconnect(var); } } void SecondaryConfigView::init() { qDebug() << "dock secondary config view : initialization started..."; setDefaultAlphaBuffer(true); setColor(Qt::transparent); - DialogShadows::self()->addWindow(this); + PanelShadows::self()->addWindow(this); rootContext()->setContextProperty(QStringLiteral("latteView"), m_latteView); rootContext()->setContextProperty(QStringLiteral("viewConfig"), this); rootContext()->setContextProperty(QStringLiteral("plasmoid"), m_latteView->containment()->property("_plasma_graphicObject").value()); 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 = "lattedocksecondaryconfigurationui"; updateEnabledBorders(); auto source = QUrl::fromLocalFile(m_latteView->containment()->corona()->kPackage().filePath(tempFilePath)); setSource(source); syncGeometry(); syncSlideEffect(); if (m_parent && KWindowSystem::isPlatformX11()) { m_parent->requestActivate(); } qDebug() << "dock secondary config view : initialization ended..."; } inline Qt::WindowFlags SecondaryConfigView::wFlags() const { return (flags() | Qt::FramelessWindowHint /*| Qt::WindowStaysOnTopHint*/) & ~Qt::WindowDoesNotAcceptFocus; } QRect SecondaryConfigView::geometryWhenVisible() const { return m_geometryWhenVisible; } void SecondaryConfigView::requestActivate() { if (KWindowSystem::isPlatformWayland() && m_shellSurface) { if (m_waylandWindowId.isNull()) { m_waylandWindowId = m_corona->wm()->winIdFor("latte-dock", geometry()); } m_corona->wm()->requestActivate(m_waylandWindowId); } else { QQuickView::requestActivate(); } } void SecondaryConfigView::syncGeometry() { if (!m_latteView || !m_latteView->layout() || !m_latteView->containment() || !m_parent || !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_parent->availableScreenGeometry(); int clearThickness = m_latteView->editThickness(); int secondaryConfigSpacing = 2 * m_latteView->fontPixelSize(); QPoint position{0, 0}; int xPos{0}; int yPos{0}; switch (m_latteView->containment()->formFactor()) { case Plasma::Types::Horizontal: { if (qApp->isLeftToRight()) { xPos = availGeometry.x() + secondaryConfigSpacing; } else { xPos = availGeometry.x() + availGeometry.width() - size.width() - secondaryConfigSpacing; } 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: { yPos = availGeometry.y() + secondaryConfigSpacing; if (location == Plasma::Types::LeftEdge) { xPos = scrGeometry.x() + clearThickness; } else if (location == Plasma::Types::RightEdge) { xPos = scrGeometry.x() + scrGeometry.width() - clearThickness - size.width(); } } 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); } //! after placement request to activate the main config window in order to avoid //! rare cases of closing settings window from secondaryConfigView->focusOutEvent if (m_parent && KWindowSystem::isPlatformX11()) { m_parent->requestActivate(); } } void SecondaryConfigView::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 SecondaryConfigView::showEvent(QShowEvent *ev) { QQuickWindow::showEvent(ev); if (!m_latteView) { return; } setFlags(wFlags()); m_corona->wm()->setViewExtraFlags(this, false, Latte::Types::NormalWindow); syncGeometry(); syncSlideEffect(); m_screenSyncTimer.start(); QTimer::singleShot(400, this, &SecondaryConfigView::syncGeometry); emit showSignal(); } void SecondaryConfigView::focusOutEvent(QFocusEvent *ev) { Q_UNUSED(ev); const auto *focusWindow = qGuiApp->focusWindow(); if ((focusWindow && (focusWindow->flags().testFlag(Qt::Popup) || focusWindow->flags().testFlag(Qt::ToolTip))) || m_latteView->alternativesIsShown()) { return; } const auto parent = qobject_cast(m_parent); if (!m_latteView->containsMouse() && parent && !parent->sticker() && !parent->isActive()) { parent->hideConfigWindow(); } } void SecondaryConfigView::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 secondary settings surface was created..."; m_shellSurface = interface->createSurface(s, this); m_corona->wm()->setViewExtraFlags(m_shellSurface, false); syncGeometry(); } } bool SecondaryConfigView::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 secondary config window surface was deleted..."; } break; } } } return QQuickView::event(e); } void SecondaryConfigView::hideConfigWindow() { if (m_shellSurface) { //!NOTE: Avoid crash in wayland environment with qt5.9 close(); } else { hide(); } } void SecondaryConfigView::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; } QRegion mask; QQuickItem *rootObject = this->rootObject(); if (rootObject) { const QVariant maskProperty = rootObject->property("backgroundMask"); if (static_cast(maskProperty.type()) == QMetaType::QRegion) { qDebug() << "found 2..."; mask = maskProperty.value(); } } if (!mask.isEmpty()) { setMask(mask); KWindowEffects::enableBlurBehind(winId(), true, mask); } else { setMask(QRect()); KWindowEffects::enableBlurBehind(winId(), false); } } //!BEGIN borders Plasma::FrameSvg::EnabledBorders SecondaryConfigView::enabledBorders() const { return m_enabledBorders; } void SecondaryConfigView::updateEnabledBorders() { if (!this->screen()) { return; } Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; switch (m_latteView->location()) { case Plasma::Types::TopEdge: borders &= ~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 &= ~Plasma::FrameSvg::BottomBorder; break; default: break; } if (m_enabledBorders != borders) { m_enabledBorders = borders; - DialogShadows::self()->addWindow(this, m_enabledBorders); + PanelShadows::self()->addWindow(this, m_enabledBorders); emit enabledBordersChanged(); } } //!END borders } } diff --git a/shell/package/contents/configuration/LatteDockConfiguration.qml b/shell/package/contents/configuration/LatteDockConfiguration.qml index 7fd2080a..e3f45169 100644 --- a/shell/package/contents/configuration/LatteDockConfiguration.qml +++ b/shell/package/contents/configuration/LatteDockConfiguration.qml @@ -1,709 +1,709 @@ /* * 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 . */ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import QtQuick.Window 2.2 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.extras 2.0 as PlasmaExtras import QtQuick.Controls.Styles.Plasma 2.0 as Styles import org.kde.plasma.plasmoid 2.0 import org.kde.kquickcontrolsaddons 2.0 as KQuickControlAddons import org.kde.latte 0.2 as Latte import org.kde.latte.components 1.0 as LatteComponents import "pages" as Pages import "../controls" as LatteExtraControls FocusScope { id: dialog property alias backgroundMask: backgroundFrameSvgItem.mask readonly property bool basicLevel: viewConfig.complexity === Latte.Types.BasicSettings readonly property bool advancedLevel: viewConfig.complexity === Latte.Types.AdvancedSettings readonly property bool expertLevel: viewConfig.complexity === Latte.Types.ExpertSettings readonly property bool highLevel: advancedLevel || expertLevel readonly property bool inConfigureAppletsMode: plasmoid.configuration.inConfigureAppletsMode || !Latte.WindowSystem.compositingActive //! max size based on screen resolution //! TODO: if we can access availableScreenGeometry.height this can be improved, currently //! we use 100px. or 50px. in order to give space for othe views to be shown and to have also //! some space around the settings window property int maxHeight: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? viewConfig.availableScreenGeometry.height - (latteView.editThickness - latteView.normalThickness) - 16 : viewConfig.availableScreenGeometry.height - 2 * units.largeSpacing property int maxWidth: 0.6 * latteView.screenGeometry.width //! propose size based on font size property int proposedWidth: 0.82 * proposedHeight + units.smallSpacing * 2 property int proposedHeight: 36 * theme.mSize(theme.defaultFont).height //! chosen size to be applied, if the user has set or not a different scale for the settings window property int chosenWidth: userScaleWidth !== 1 ? userScaleWidth * proposedWidth : proposedWidth property int chosenHeight: userScaleHeight !== 1 ? userScaleHeight * heightLevel * proposedHeight : heightLevel * proposedHeight readonly property int optionsWidth: appliedWidth - units.smallSpacing * 10 //! user set scales based on its preference, e.g. 96% of the proposed size property real userScaleWidth: 1 property real userScaleHeight: 1 readonly property real heightLevel: (dialog.expertLevel ? 100 : 1) onHeightChanged: viewConfig.syncGeometry(); //! applied size in order to not be out of boundaries //! width can be between 200px - maxWidth //! height can be between 400px - maxHeight property int appliedWidth: Math.min(maxWidth, Math.max(200, chosenWidth)) property int appliedHeight: Math.min(maxHeight, Math.max(400, chosenHeight)) width: appliedWidth height: appliedHeight Layout.minimumWidth: width Layout.minimumHeight: height LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true readonly property bool viewIsPanel: latteView.type === Latte.Types.PanelView property bool panelIsVertical: plasmoid.formFactor === PlasmaCore.Types.Vertical property int subGroupSpacing: units.largeSpacing + units.smallSpacing * 1.5 property color bC: theme.backgroundColor property color transparentBackgroundColor: Qt.rgba(bC.r, bC.g, bC.b, 0.7) onHighLevelChanged: { //! switch to appearancePage when effectsPage becomes hidden because //! advancedLevel was disabled by the user if (!highLevel && tabGroup.currentTab === effectsPage) { tabGroup.currentTab = appearancePage; tabBar.currentTab = appearanceTabBtn; } } Component.onCompleted: { updateScales(); } Connections { target: latteView.positioner onCurrentScreenNameChanged: dialog.updateScales(); } function updateScales() { userScaleWidth = universalSettings.screenWidthScale(latteView.positioner.currentScreenName); userScaleHeight = universalSettings.screenHeightScale(latteView.positioner.currentScreenName); } PlasmaCore.FrameSvgItem{ id: backgroundFrameSvgItem anchors.fill: parent - imagePath: "dialogs/background" + imagePath: "widgets/panel-background" enabledBorders: viewConfig.enabledBorders onEnabledBordersChanged: viewConfig.updateEffects() onWidthChanged: viewConfig.updateEffects() onHeightChanged: viewConfig.updateEffects() Component.onCompleted: viewConfig.updateEffects() } MouseArea{ id: backgroundMouseArea anchors.fill: parent hoverEnabled: true property bool blockWheel: false property bool updatingWidthScale: false property bool updatingHeightScale: false property bool wheelTriggeredOnce: false property real scaleStep: 0.04 onWheel: { var metaModifier = (wheel.modifiers & Qt.MetaModifier); var ctrlModifier = (wheel.modifiers & Qt.ControlModifier); if (blockWheel || !(metaModifier || ctrlModifier)){ return; } updatingWidthScale = metaModifier || (dialog.expertLevel && ctrlModifier); updatingHeightScale = !dialog.expertLevel && ctrlModifier; blockWheel = true; wheelTriggeredOnce = true; scrollDelayer.start(); var angle = wheel.angleDelta.y / 8; //positive direction if (angle > 12) { var scales; if (updatingWidthScale) { userScaleWidth = userScaleWidth + scaleStep; } if (updatingHeightScale) { userScaleHeight = userScaleHeight + scaleStep; } universalSettings.setScreenScales(latteView.positioner.currentScreenName, userScaleWidth, userScaleHeight); viewConfig.syncGeometry(); //negative direction } else if (angle < -12) { if (updatingWidthScale) { userScaleWidth = userScaleWidth - scaleStep; } if (updatingHeightScale) { userScaleHeight = userScaleHeight - scaleStep; } universalSettings.setScreenScales(latteView.positioner.currentScreenName, userScaleWidth, userScaleHeight); viewConfig.syncGeometry(); } } } PlasmaComponents.Button { id: backgroundMouseAreaTooltip anchors.fill: parent opacity: 0 //tooltip: i18n("You can use Ctrl/Meta + Scroll Wheel to alter the window size") onHoveredChanged: { if (!hovered) { backgroundMouseArea.wheelTriggeredOnce = false; } } } PlasmaComponents.Label{ anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter text: backgroundMouseArea.updatingWidthScale ? i18nc("view settings width scale","Width scale at %0%").arg(userScaleWidth * 100) : i18nc("view settings height scale","Height scale at %0%").arg(userScaleHeight * 100) visible: backgroundMouseAreaTooltip.hovered && backgroundMouseArea.wheelTriggeredOnce } //! A timer is needed in order to handle also touchpads that probably //! send too many signals very fast. This way the signals per sec are limited. //! The user needs to have a steady normal scroll in order to not //! notice a annoying delay Timer{ id: scrollDelayer interval: 75 onTriggered: backgroundMouseArea.blockWheel = false; } ColumnLayout { id: content Layout.minimumWidth: width Layout.minimumHeight: calculatedHeight Layout.preferredWidth: width Layout.preferredHeight: calculatedHeight width: (dialog.appliedWidth - units.smallSpacing * 2) anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top spacing: units.smallSpacing property int calculatedHeight: header.height + headerSpacer.height+ tabBar.height + pagesBackground.height + actionButtons.height + spacing * 3 Keys.onPressed: { if (event.key === Qt.Key_Escape) { viewConfig.hideConfigWindow(); } } Component.onCompleted: forceActiveFocus(); RowLayout { id: header Layout.fillWidth: true spacing: 0 Item { Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.fillWidth: false Layout.topMargin: units.smallSpacing Layout.preferredWidth: width Layout.preferredHeight: height width: Qt.application.layoutDirection !== Qt.RightToLeft ? logo.width + latteTxt.width + units.smallSpacing : logo.width + units.smallSpacing height: logo.height Latte.IconItem { id: logo width: Math.round(1.4 * latteTxtMetrics.font.pixelSize) height: width smooth: true source: "latte-dock" // animated: true usesPlasmaTheme: false active: aboutArea.hovered } PlasmaComponents.Label { id: latteTxtMetrics text: i18n("Latte") width: 0 font.pointSize: 2 * theme.defaultFont.pointSize visible: false } PlasmaCore.SvgItem{ id: latteTxt width: 2.2 * height height: 0.4 * latteTxtMetrics.font.pixelSize visible: Qt.application.layoutDirection !== Qt.RightToLeft anchors.left: logo.right anchors.verticalCenter: logo.verticalCenter svg: PlasmaCore.Svg{ imagePath: universalSettings.trademarkIconPath() } } PlasmaComponents.Button{ id: aboutArea //! Used as tooltip anchors.fill: parent opacity: 0 tooltip: i18n("Open Latte settings window") onPressedChanged: { if (pressed) { layoutsManager.showLatteSettingsDialog(Latte.Types.PreferencesPage) } } } Rectangle { anchors.top: parent.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 2 width: parent.width + 4 height: 2 color: theme.highlightColor visible: aboutArea.hovered } } Item{ id: headerSpacer Layout.minimumHeight: complexitySettings.height + 2*units.smallSpacing } ColumnLayout { PlasmaComponents.ToolButton { id: pinButton Layout.fillWidth: false Layout.fillHeight: false Layout.preferredWidth: width Layout.preferredHeight: height Layout.alignment: Qt.AlignRight | Qt.AlignVCenter Layout.bottomMargin: units.smallSpacing //!avoid editMode box shadow Layout.topMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing iconSource: "window-pin" checkable: true width: Math.round(units.gridUnit * 1.25) height: width property bool inStartup: true onClicked: { plasmoid.configuration.configurationSticker = checked viewConfig.setSticker(checked) } Component.onCompleted: { checked = plasmoid.configuration.configurationSticker viewConfig.setSticker(plasmoid.configuration.configurationSticker) } } RowLayout { id: complexitySettings Layout.fillWidth: true Layout.rightMargin: units.smallSpacing * 2 Layout.alignment: Qt.AlignRight | Qt.AlignTop PlasmaComponents.Label { Layout.fillWidth: true Layout.alignment: Qt.AlignRight } PlasmaComponents.Label { id: complexityLbl Layout.alignment: Qt.AlignRight // opacity: dialog.basicLevel ? basicOpacity : 1 //! TODO: the term here is not accurate because the expert settings mode //! is used currently. In the future this term will be rethought if //! it must remain or be changed text: i18nc("advanced settings", "Advanced") readonly property real textColorBrightness: colorBrightness(theme.textColor) readonly property real basicOpacity: textColorBrightness > 127 ? 0.7 : 0.3 color: { if (dialog.basicLevel) { return textColorBrightness > 127 ? Qt.darker(theme.textColor, 1.4) : Qt.lighter(theme.textColor, 2.8); } return theme.textColor; } function colorBrightness(color) { return colorBrightnessFromRGB(color.r * 255, color.g * 255, color.b * 255); } // formula for brightness according to: // https://www.w3.org/TR/AERT/#color-contrast function colorBrightnessFromRGB(r, g, b) { return (r * 299 + g * 587 + b * 114) / 1000 } MouseArea { id: complexityMouseArea anchors.fill: parent hoverEnabled: true onClicked: { complexitySwitch.checked = !complexitySwitch.checked; } } } LatteComponents.Switch { id: complexitySwitch checked: (viewConfig.complexity === Latte.Types.ExpertSettings) onCheckedChanged: { if (checked) { viewConfig.complexity = Latte.Types.ExpertSettings; } else { viewConfig.complexity = Latte.Types.BasicSettings; } } } } } } PlasmaComponents.TabBar { id: tabBar Layout.fillWidth: true Layout.maximumWidth: (dialog.appliedWidth - units.smallSpacing * 2) PlasmaComponents.TabButton { id: behaviorTabBtn text: i18n("Behavior") tab: behaviorPage } PlasmaComponents.TabButton { id: appearanceTabBtn text: i18n("Appearance") tab: appearancePage } PlasmaComponents.TabButton { id: effectsTabBtn text: i18n("Effects") tab: effectsPage visible: dialog.highLevel } PlasmaComponents.TabButton { id: tasksTabBtn text: i18n("Tasks") tab: tasksPage visible: latteView.latteTasksArePresent } } Rectangle { id: pagesBackground Layout.fillWidth: true Layout.fillHeight: false Layout.minimumWidth: dialog.appliedWidth - units.smallSpacing * 4 Layout.minimumHeight: height Layout.maximumHeight: height width: dialog.appliedWidth - units.smallSpacing * 3 height: availableFreeHeight + units.smallSpacing * 4 color: transparentBackgroundColor border.width: 1 border.color: theme.backgroundColor //fix the height binding loop when showing the configuration window property int availableFreeHeight: dialog.appliedHeight - header.height - headerSpacer.height - tabBar.height - actionButtons.height - 2 * units.smallSpacing PlasmaExtras.ScrollArea { id: scrollArea anchors.fill: parent verticalScrollBarPolicy: Qt.ScrollBarAsNeeded horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff flickableItem.flickableDirection: Flickable.VerticalFlick PlasmaComponents.TabGroup { id: tabGroup width: currentTab.Layout.maximumWidth height: currentTab.Layout.maximumHeight Pages.BehaviorConfig { id: behaviorPage } Pages.AppearanceConfig { id: appearancePage } Pages.EffectsConfig { id: effectsPage } Pages.TasksConfig { id: tasksPage } } } } RowLayout { id: actionButtons Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom spacing: units.largeSpacing Connections{ target: latteView.layout onViewsCountChanged: actionButtons.updateEnabled(); } function updateEnabled() { var screenFreeEdges = latteView.layout.qmlFreeEdges(latteView.positioner.currentScreenId); actionsComboBtn.buttonEnabled = screenFreeEdges.length > 0; if (actionsModel.count > 0) { actionsModel.get(0).enabled = actionsComboBtn.buttonEnabled; } removeView.enabled = latteView.layout.viewsCount>1 /*&& !(latteView.layout.viewsWithTasks()===1 && latteView.tasksPresent())*/ } LatteComponents.ComboBoxButton { id: actionsComboBtn Layout.fillWidth: true implicitWidth: removeView.implicitWidth implicitHeight: removeView.implicitHeight buttonEnabled: true buttonText: i18n("New Dock") buttonIconSource: "list-add" buttonToolTip: i18n("Add a new dock") comboBoxEnabled: true comboBoxBlankSpaceForEmptyIcons: true comboBoxPopUpAlignRight: Qt.application.layoutDirection === Qt.RightToLeft comboBoxEnabledRole: "enabled" comboBoxTextRole: "name" comboBoxIconRole: "icon" comboBoxMinimumPopUpWidth: actionsModel.count > 1 ? dialog.width / 2 : 150 property var centralLayoutsNames: [] property var sharedLayoutsNames: [] Component.onCompleted: { comboBox.model = actionsModel; actionButtons.updateEnabled(); } ListModel { id: actionsModel } Connections{ target: actionsComboBtn.comboBox Component.onCompleted:{ actionsComboBtn.addModel(); actionButtons.updateEnabled(); } onActivated: { if (index==0) { latteView.copyView(); } else if (index>=1) { var layouts = actionsComboBtn.sharedLayoutsNames.concat(actionsComboBtn.centralLayoutsNames); latteView.positioner.hideDockDuringMovingToLayout(layouts[index-1]); } actionsComboBtn.comboBox.currentIndex = -1; } onEnabledChanged: { if (enabled) { actionsComboBtn.addModel(); } else { actionsComboBtn.emptyModel(); } } } Connections{ target: actionsComboBtn.button onClicked: latteView.layout.addNewView(); } Connections{ target: latteView onTypeChanged: actionsComboBtn.updateCopyText() } function addModel() { actionsModel.clear(); var copy = {actionId: 'copy:', enabled: true, name: '', icon: 'edit-copy'}; actionsModel.append(copy); updateCopyText(); var tempCentralLayouts = layoutsManager.centralLayoutsNames(); var tempSharedLayouts = layoutsManager.sharedLayoutsNames(); if (tempSharedLayouts.length > 0) { var curIndex = tempSharedLayouts.indexOf(latteView.layout.name); if (curIndex >=0) { tempSharedLayouts.splice(curIndex,1); } sharedLayoutsNames = tempSharedLayouts; var icon = "document-share"; for(var i=0; i 0) { var curIndex = tempCentralLayouts.indexOf(latteView.layout.name); if (curIndex >=0) { tempCentralLayouts.splice(curIndex,1); } centralLayoutsNames = tempCentralLayouts; var iconArrow = Qt.application.layoutDirection === Qt.RightToLeft ? 'arrow-left' : 'arrow-right'; for(var i=0; i 1 ? 1 : 0 tooltip: i18n("Remove current dock") onClicked: latteView.removeView() } PlasmaComponents.Button { id: closeButton Layout.fillWidth: true text: i18n("Close") iconSource: "dialog-close" tooltip: i18n("Close settings window") onClicked: viewConfig.hideConfigWindow(); } } } //! HACK FOR X11 environments //! show an inner shadow similar to Latte::View editShadow in order to //! not break the visual user experience LatteExtraControls.InnerShadow{ width: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? dialog.width + 2*shadowSize : shadowSize height: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? shadowSize : dialog.height + 2*shadowSize shadowSize: latteView.effects.editShadow shadowOpacity: Math.max(0.35, maxOpacity) shadowDirection: plasmoid.location visible: !Latte.WindowSystem.isPlatformWayland && Latte.WindowSystem.compositingActive && latteView.effects.settingsMaskSubtracted readonly property real maxOpacity: Latte.WindowSystem.compositingActive && !plasmoid.configuration.inConfigureAppletsMode ? plasmoid.configuration.editBackgroundOpacity : 1 } } diff --git a/shell/package/contents/configuration/LatteDockSecondaryConfiguration.qml b/shell/package/contents/configuration/LatteDockSecondaryConfiguration.qml index 2b941e44..e263475f 100644 --- a/shell/package/contents/configuration/LatteDockSecondaryConfiguration.qml +++ b/shell/package/contents/configuration/LatteDockSecondaryConfiguration.qml @@ -1,97 +1,97 @@ /* * 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 . */ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import QtQuick.Window 2.2 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras import QtQuick.Controls.Styles.Plasma 2.0 as Styles import org.kde.plasma.plasmoid 2.0 import org.kde.kquickcontrolsaddons 2.0 as KQuickControlAddons import org.kde.latte 0.2 as Latte import "../controls" as LatteExtraControls FocusScope { id: dialog property alias backgroundMask: backgroundFrameSvgItem.mask width: typeSettings.width + units.smallSpacing * 4 height: typeSettings.height + units.smallSpacing * 4 Layout.minimumWidth: width Layout.minimumHeight: height LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true property bool panelIsVertical: plasmoid.formFactor === PlasmaCore.Types.Vertical PlasmaCore.FrameSvgItem{ id: backgroundFrameSvgItem anchors.fill: parent - imagePath: "dialogs/background" + imagePath: "widgets/panel-background" enabledBorders: viewConfig.enabledBorders onEnabledBordersChanged: viewConfig.updateEffects() onWidthChanged: viewConfig.updateEffects() onHeightChanged: viewConfig.updateEffects() Component.onCompleted: viewConfig.updateEffects() } LatteExtraControls.TypeSelection{ id: typeSettings anchors.centerIn: parent Component.onCompleted: forceActiveFocus(); Keys.onPressed: { if (event.key === Qt.Key_Escape) { viewConfig.hideConfigWindow(); } } } //! HACK FOR X11 environments //! show an inner shadow similar to Latte::View editShadow in order to //! not break the visual user experience LatteExtraControls.InnerShadow{ width: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? dialog.width + 2*shadowSize : shadowSize height: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? shadowSize : dialog.height + 2*shadowSize shadowSize: latteView.effects.editShadow shadowOpacity: Math.max(0.35, maxOpacity) shadowDirection: plasmoid.location visible: !Latte.WindowSystem.isPlatformWayland && Latte.WindowSystem.compositingActive && latteView.effects.settingsMaskSubtracted readonly property real maxOpacity: Latte.WindowSystem.compositingActive && !plasmoid.configuration.inConfigureAppletsMode ? plasmoid.configuration.editBackgroundOpacity : 1 } }