diff --git a/app/view/effects.cpp b/app/view/effects.cpp index 746b5b2b..07e281ce 100644 --- a/app/view/effects.cpp +++ b/app/view/effects.cpp @@ -1,565 +1,565 @@ /* * 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 "effects.h" // local #include #include #include "panelshadows_p.h" #include "view.h" // Qt #include // KDE #include #include namespace Latte { namespace ViewPart { Effects::Effects(Latte::View *parent) : QObject(parent), m_view(parent) { init(); } Effects::~Effects() { } void Effects::init() { connect(this, &Effects::backgroundOpacityChanged, this, &Effects::updateEffects); connect(this, &Effects::drawEffectsChanged, this, &Effects::updateEffects); connect(this, &Effects::enabledBordersChanged, this, &Effects::updateEffects); connect(this, &Effects::rectChanged, this, &Effects::updateEffects); connect(this, &Effects::subtractedMaskRegionsChanged, this, &Effects::updateMask); connect(this, &Effects::unitedMaskRegionsChanged, this, &Effects::updateMask); connect(this, &Effects::drawShadowsChanged, this, [&]() { if (m_view->behaveAsPlasmaPanel()) { updateEnabledBorders(); } }); connect(m_view, &Latte::View::alignmentChanged, this, &Effects::updateEnabledBorders); connect(m_view, &Latte::View::screenEdgeMarginEnabledChanged, this, &Effects::updateEnabledBorders); connect(m_view, &Latte::View::behaveAsPlasmaPanelChanged, this, &Effects::updateEffects); connect(this, &Effects::drawShadowsChanged, this, &Effects::updateShadows); connect(m_view, &Latte::View::behaveAsPlasmaPanelChanged, this, &Effects::updateShadows); connect(m_view, &Latte::View::configWindowGeometryChanged, this, &Effects::updateMask); connect(&m_theme, &Plasma::Theme::themeChanged, this, [&]() { auto background = m_background; m_background = new Plasma::FrameSvg(this); if (background) { background->deleteLater(); } if (m_background->imagePath() != "widgets/panel-background") { m_background->setImagePath(QStringLiteral("widgets/panel-background")); } updateBackgroundContrastValues(); updateEffects(); }); } bool Effects::animationsBlocked() const { return m_animationsBlocked; } void Effects::setAnimationsBlocked(bool blocked) { if (m_animationsBlocked == blocked) { return; } m_animationsBlocked = blocked; emit animationsBlockedChanged(); } bool Effects::drawShadows() const { return m_drawShadows; } void Effects::setDrawShadows(bool draw) { if (m_drawShadows == draw) { return; } m_drawShadows = draw; emit drawShadowsChanged(); } bool Effects::drawEffects() const { return m_drawEffects; } void Effects::setDrawEffects(bool draw) { if (m_drawEffects == draw) { return; } m_drawEffects = draw; emit drawEffectsChanged(); } void Effects::setForceBottomBorder(bool draw) { if (m_forceBottomBorder == draw) { return; } m_forceBottomBorder = draw; updateEnabledBorders(); } void Effects::setForceTopBorder(bool draw) { if (m_forceTopBorder == draw) { return; } m_forceTopBorder = draw; updateEnabledBorders(); } float Effects::backgroundOpacity() const { return m_backgroundOpacity; } void Effects::setBackgroundOpacity(float opacity) { if (m_backgroundOpacity == opacity) { return; } m_backgroundOpacity = opacity; updateBackgroundContrastValues(); emit backgroundOpacityChanged(); } int Effects::editShadow() const { return m_editShadow; } void Effects::setEditShadow(int shadow) { if (m_editShadow == shadow) { return; } m_editShadow = shadow; emit editShadowChanged(); } int Effects::innerShadow() const { return m_innerShadow; } void Effects::setInnerShadow(int shadow) { if (m_innerShadow == shadow) return; m_innerShadow = shadow; emit innerShadowChanged(); } QRect Effects::rect() const { return m_rect; } void Effects::setRect(QRect area) { if (m_rect == area) { return; } m_rect = area; emit rectChanged(); } QRect Effects::mask() const { return m_mask; } void Effects::setMask(QRect area) { if (m_mask == area) return; m_mask = area; updateMask(); // qDebug() << "dock mask set:" << m_mask; emit maskChanged(); } void Effects::forceMaskRedraw() { if (m_background) { delete m_background; } m_background = new Plasma::FrameSvg(this); m_background->setImagePath(QStringLiteral("widgets/panel-background")); m_background->setEnabledBorders(m_enabledBorders); updateMask(); } void Effects::setSubtractedMaskRegion(const QString ®ionid, const QRegion ®ion) { - if (!m_subtractedMaskRegions.contains(regionid) || m_subtractedMaskRegions[regionid] != region) { + if (m_subtractedMaskRegions.contains(regionid) && m_subtractedMaskRegions[regionid] == region) { return; } m_subtractedMaskRegions[regionid] = region; emit subtractedMaskRegionsChanged(); } void Effects::removeSubtractedMaskRegion(const QString ®ionid) { if (!m_subtractedMaskRegions.contains(regionid)) { return; } m_subtractedMaskRegions.remove(regionid); emit subtractedMaskRegionsChanged(); } void Effects::setUnitedMaskRegion(const QString ®ionid, const QRegion ®ion) { - if (!m_unitedMaskRegions.contains(regionid) || m_unitedMaskRegions[regionid] != region) { + if (m_unitedMaskRegions.contains(regionid) && m_unitedMaskRegions[regionid] == region) { return; } m_unitedMaskRegions[regionid] = region; emit unitedMaskRegionsChanged(); } void Effects::removeUnitedMaskRegion(const QString ®ionid) { if (!m_unitedMaskRegions.contains(regionid)) { return; } m_unitedMaskRegions.remove(regionid); emit unitedMaskRegionsChanged(); } QRegion Effects::maskCombinedRegion() { QRegion region = m_mask; for(auto subregion : m_subtractedMaskRegions) { region = region.subtracted(subregion); } for(auto subregion : m_unitedMaskRegions) { region = region.united(subregion); } return region; } void Effects::updateMask() { if (KWindowSystem::compositingActive()) { if (m_view->behaveAsPlasmaPanel()) { m_view->setMask(QRect()); } else { m_view->setMask(maskCombinedRegion()); } } else { //! this is used when compositing is disabled and provides //! the correct way for the mask to be painted in order for //! rounded corners to be shown correctly //! the enabledBorders check was added because there was cases //! that the mask region wasn't calculated correctly after location changes if (!m_background) { if (m_background && m_background->enabledBorders() != m_enabledBorders) { delete 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(m_mask.size()); QRegion fixedMask = m_background->mask(); fixedMask.translate(m_mask.x(), m_mask.y()); //! fix for KF5.32 that return empty QRegion's for the mask if (fixedMask.isEmpty()) { fixedMask = QRegion(m_mask); } m_view->setMask(fixedMask); } } void Effects::clearShadows() { PanelShadows::self()->removeWindow(m_view); } void Effects::updateShadows() { if (m_view->behaveAsPlasmaPanel() && drawShadows()) { PanelShadows::self()->addWindow(m_view, enabledBorders()); } else { PanelShadows::self()->removeWindow(m_view); } } void Effects::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_view->surface()) { return; } bool clearEffects{true}; if (m_drawEffects) { if (!m_view->behaveAsPlasmaPanel()) { if (!m_rect.isNull() && !m_rect.isEmpty()) { //! this is used when compositing is disabled and provides //! the correct way for the mask to be painted in order for //! rounded corners to be shown correctly 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(m_rect.size()); QRegion backMask = m_background->mask(); //! There are cases that mask is NULL even though it should not //! Example: SideBar from v0.10 that BEHAVEASPLASMAPANEL in EditMode //! switching multiple times between inConfigureAppletsMode and LiveEditMode //! is such a case QRegion fixedMask; int fX = m_rect.x(); int fY = m_rect.y(); #if KF5_VERSION_MINOR >= 65 //! Latte is now using GtkFrameExtents so Effects geometries must be adjusted //! windows that use GtkFrameExtents and apply Effects on them they take GtkFrameExtents //! as granted if (KWindowSystem::isPlatformX11()) { if (m_view->location() == Plasma::Types::BottomEdge) { fY = qMax(0, fY - m_view->headThicknessGap()); } else if (m_view->location() == Plasma::Types::RightEdge) { fX = qMax(0, fX - m_view->headThicknessGap()); } } #endif if (!backMask.isNull()) { fixedMask = backMask; fixedMask.translate(fX, fY); } else { fixedMask = QRect(fX, fY, m_rect.width(), m_rect.height()); } if (!fixedMask.isEmpty()) { clearEffects = false; KWindowEffects::enableBlurBehind(m_view->winId(), true, fixedMask); KWindowEffects::enableBackgroundContrast(m_view->winId(), m_theme.backgroundContrastEnabled(), m_backEffectContrast, m_backEffectIntesity, m_backEffectSaturation, fixedMask); } } } else { //! BEHAVEASPLASMAPANEL case clearEffects = false; KWindowEffects::enableBlurBehind(m_view->winId(), true); KWindowEffects::enableBackgroundContrast(m_view->winId(), m_theme.backgroundContrastEnabled(), m_backEffectContrast, m_backEffectIntesity, m_backEffectSaturation); } } if (clearEffects) { KWindowEffects::enableBlurBehind(m_view->winId(), false); KWindowEffects::enableBackgroundContrast(m_view->winId(), false); } } //!BEGIN draw panel shadows outside the dock window Plasma::FrameSvg::EnabledBorders Effects::enabledBorders() const { return m_enabledBorders; } qreal Effects::currentMidValue(const qreal &max, const qreal &factor, const qreal &min) const { if (max==min || factor==0) { return min; } qreal space = 0; qreal distance = 0; if (maxscreen()) { return; } Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; if (!m_view->screenEdgeMarginEnabled()) { switch (m_view->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_view->location() == Plasma::Types::LeftEdge || m_view->location() == Plasma::Types::RightEdge)) { if (m_view->maxLength() == 1 && m_view->alignment() == Latte::Types::Justify) { if (!m_forceTopBorder) { borders &= ~Plasma::FrameSvg::TopBorder; } if (!m_forceBottomBorder) { borders &= ~Plasma::FrameSvg::BottomBorder; } } if (m_view->alignment() == Latte::Types::Top && !m_forceTopBorder && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::TopBorder; } if (m_view->alignment() == Latte::Types::Bottom && !m_forceBottomBorder && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::BottomBorder; } } if (m_view->location() == Plasma::Types::TopEdge || m_view->location() == Plasma::Types::BottomEdge) { if (m_view->maxLength() == 1 && m_view->alignment() == Latte::Types::Justify) { borders &= ~Plasma::FrameSvg::LeftBorder; borders &= ~Plasma::FrameSvg::RightBorder; } if (m_view->alignment() == Latte::Types::Left && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::LeftBorder; } if (m_view->alignment() == Latte::Types::Right && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::RightBorder; } } if (m_enabledBorders != borders) { m_enabledBorders = borders; emit enabledBordersChanged(); } if (!m_view->behaveAsPlasmaPanel() || !m_drawShadows) { PanelShadows::self()->removeWindow(m_view); } else { PanelShadows::self()->setEnabledBorders(m_view, borders); } } //!END draw panel shadows outside the dock window } } diff --git a/app/view/settings/primaryconfigview.cpp b/app/view/settings/primaryconfigview.cpp index cec97a4e..861a7fee 100644 --- a/app/view/settings/primaryconfigview.cpp +++ b/app/view/settings/primaryconfigview.cpp @@ -1,816 +1,864 @@ /* * 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, &View::hiddenConfigurationWindowsAreDeletedChanged, this, &PrimaryConfigView::onHiddenConfigurationWindowsAreDeletedChanged); 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); } } 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); if (m_secConfigView) { m_secConfigView->deleteLater(); } 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::showSecondaryWindow() { if (!m_secConfigView) { m_secConfigView = new SecondaryConfigView(m_latteView, this); m_secConfigView->init(); } else if (m_secConfigView && !m_latteView->hiddenConfigurationWindowsAreDeleted() && !m_secConfigView->isVisible()){ m_secConfigView->show(); } } void PrimaryConfigView::hideSecondaryWindow() { if (m_secConfigView) { if (m_latteView->hiddenConfigurationWindowsAreDeleted()) { auto secWindow = m_secConfigView; m_secConfigView = nullptr; secWindow->deleteLater(); } else { m_secConfigView->hide(); } 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::onHiddenConfigurationWindowsAreDeletedChanged() { if (m_latteView && m_latteView->hiddenConfigurationWindowsAreDeleted() && !isVisible()) { deleteLater(); } } 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()); 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(); auto geometry = QRect(position.x(), position.y(), size.width(), size.height()); if (m_geometryWhenVisible == geometry) { return; } m_geometryWhenVisible = geometry; setPosition(position); if (m_shellSurface) { m_shellSurface->setPosition(position); } setMaximumSize(size); setMinimumSize(size); resize(size); + updateViewMask(); emit m_latteView->configWindowGeometryChanged(); } +void PrimaryConfigView::updateViewMask() +{ + bool environmentState = (KWindowSystem::isPlatformX11() && KWindowSystem::compositingActive()); + + if (!environmentState) { + return; + } + + int x, y, thickness, length; + QRegion area; + + thickness = m_latteView->effects()->editShadow(); + + if (m_latteView->formFactor() == Plasma::Types::Vertical) { + length = m_geometryWhenVisible.height(); + } else { + length = m_geometryWhenVisible.width(); + } + + if (m_latteView->formFactor() == Plasma::Types::Horizontal) { + x = m_geometryWhenVisible.x() - m_latteView->x(); + } else { + y = m_geometryWhenVisible.y() - m_latteView->y(); + } + + if (m_latteView->location() == Plasma::Types::BottomEdge) { + y = m_latteView->height() - m_latteView->editThickness() - m_latteView->effects()->editShadow(); + } else if (m_latteView->location() == Plasma::Types::TopEdge) { + y = m_latteView->editThickness(); + } else if (m_latteView->location() == Plasma::Types::LeftEdge) { + x = m_latteView->editThickness(); + } else if (m_latteView->location() == Plasma::Types::RightEdge) { + x = m_latteView->width() - m_latteView->editThickness() - m_latteView->effects()->editShadow(); + } + + if (m_latteView->formFactor() == Plasma::Types::Horizontal) { + area = QRect(x, y, length, thickness); + } else { + area = QRect(x, y, thickness, length); + } + + m_latteView->effects()->setSubtractedMaskRegion(validTitle(), area); +} + 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); updateShowInlineProperties(); + updateViewMask(); emit showSignal(); if (m_latteView && m_latteView->layout()) { m_latteView->layout()->setLastConfigViewFor(m_latteView); } if (m_shellSurface) { //! readd shadows after hiding because the window shadows are not shown again after first showing m_corona->dialogShadows()->addWindow(this, m_enabledBorders); } } void PrimaryConfigView::hideEvent(QHideEvent *ev) { if (!m_latteView) { deleteLater(); return; } if (m_latteView->containment()) { m_latteView->containment()->setUserConfiguring(false); } + m_latteView->effects()->removeSubtractedMaskRegion(validTitle()); + 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()); } if (m_latteView->hiddenConfigurationWindowsAreDeleted()) { deleteLater(); } else { setVisible(false); } } 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 (showSecWindow && !geometryWhenVisible().isNull()) { if (m_secConfigView && m_secConfigView->geometryWhenVisible().intersects(geometryWhenVisible())) { showSecWindow = false; } else if (advancedApprovedSecWindow) { showSecWindow = true; } } if (showSecWindow) { showSecondaryWindow(); // QTimer::singleShot(150, m_secConfigView, SLOT(show())); setShowInlineProperties(false); } else { hideSecondaryWindow(); 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(); } hideSecondaryWindow(); } 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() != "dialogs/background") { m_background->setImagePath(QStringLiteral("dialogs/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 } } diff --git a/app/view/settings/primaryconfigview.h b/app/view/settings/primaryconfigview.h index f94b7b7e..f58827d9 100644 --- a/app/view/settings/primaryconfigview.h +++ b/app/view/settings/primaryconfigview.h @@ -1,180 +1,182 @@ /* * 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 . */ #ifndef PRIMARYCONFIGVIEW_H #define PRIMARYCONFIGVIEW_H // local #include #include "../../plasma/quick/configview.h" #include "../../wm/windowinfowrap.h" //Qt #include #include #include #include // Plasma #include #include namespace Plasma { class Applet; class Containment; class FrameSvg; class Types; } namespace KWayland { namespace Client { class PlasmaShellSurface; } } namespace Latte { class Corona; class View; } namespace Latte { namespace ViewPart { class SecondaryConfigView; } } namespace Latte { namespace ViewPart { class PrimaryConfigView : public PlasmaQuick::ConfigView { Q_OBJECT //! used when the secondary config window can not be shown Q_PROPERTY(bool showInlineProperties READ showInlineProperties NOTIFY showInlinePropertiesChanged) Q_PROPERTY(bool inAdvancedMode READ inAdvancedMode WRITE setInAdvancedMode NOTIFY inAdvancedModeChanged) Q_PROPERTY(QRect availableScreenGeometry READ availableScreenGeometry NOTIFY availableScreenGeometryChanged) Q_PROPERTY(Plasma::FrameSvg::EnabledBorders enabledBorders READ enabledBorders NOTIFY enabledBordersChanged) public: enum ConfigViewType { PrimaryConfig = 0, SecondaryConfig }; PrimaryConfigView(Plasma::Containment *containment, Latte::View *view, QWindow *parent = nullptr); ~PrimaryConfigView() override; void init() override; void requestActivate(); Qt::WindowFlags wFlags() const; bool inAdvancedMode() const; void setInAdvancedMode(bool advanced); bool showInlineProperties() const; bool sticker() const; QRect availableScreenGeometry() const; QRect geometryWhenVisible() const; QString validTitle() const; Plasma::FrameSvg::EnabledBorders enabledBorders() const; QQuickView *secondaryWindow(); public slots: Q_INVOKABLE void hideConfigWindow(); Q_INVOKABLE void setSticker(bool blockFocusLost); Q_INVOKABLE void syncGeometry(); Q_INVOKABLE void updateLaunchersForGroup(int groupInt); Q_INVOKABLE void updateEffects(); signals: void availableScreenGeometryChanged(); void enabledBordersChanged(); void inAdvancedModeChanged(); void raiseDocksTemporaryChanged(); void showInlinePropertiesChanged(); void showSignal(); protected: void showEvent(QShowEvent *ev) override; void hideEvent(QHideEvent *ev) override; void focusOutEvent(QFocusEvent *ev) override; bool event(QEvent *e) override; void syncSlideEffect(); private slots: void immutabilityChanged(Plasma::Types::ImmutabilityType type); void onHiddenConfigurationWindowsAreDeletedChanged(); void updateAvailableScreenGeometry(View *origin = nullptr); void updateEnabledBorders(); void updateShowInlineProperties(); void updateWaylandId(); void showSecondaryWindow(); void hideSecondaryWindow(); void setShowInlineProperties(bool show); + void updateViewMask(); + void loadConfig(); void saveConfig(); private: void setupWaylandIntegration(); bool m_blockFocusLost{false}; bool m_blockFocusLostOnStartup{true}; bool m_originalByPassWM{false}; bool m_inAdvancedMode{false}; bool m_inReverse{false}; //! it is used by the borders bool m_showInlineProperties{false}; Latte::Types::Visibility m_originalMode{Latte::Types::DodgeActive}; QRect m_availableScreenGeometry; QRect m_geometryWhenVisible; QPointer m_latteView; QPointer m_secConfigView; QTimer m_screenSyncTimer; QTimer m_thicknessSyncTimer; QList connections; Plasma::FrameSvg::EnabledBorders m_enabledBorders{Plasma::FrameSvg::AllBorders}; //only for the mask on disabled compositing, not to actually paint Plasma::FrameSvg *m_background{nullptr}; Latte::Corona *m_corona{nullptr}; Latte::WindowSystem::WindowId m_waylandWindowId; KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr}; }; } } #endif //PRIMARYCONFIGVIEW_H diff --git a/app/view/settings/secondaryconfigview.cpp b/app/view/settings/secondaryconfigview.cpp index 093f88c1..7485e583 100644 --- a/app/view/settings/secondaryconfigview.cpp +++ b/app/view/settings/secondaryconfigview.cpp @@ -1,507 +1,562 @@ /* * 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 "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(); setTitle(validTitle()); if (KWindowSystem::isPlatformX11()) { m_corona->wm()->registerIgnoredWindow(winId()); } else { connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, &SecondaryConfigView::updateWaylandId); } 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::widthChanged, this, &SecondaryConfigView::updateEffects); connect(this, &QQuickView::heightChanged, this, &SecondaryConfigView::updateEffects); 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 ..."; m_corona->dialogShadows()->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); m_corona->dialogShadows()->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; } QString SecondaryConfigView::validTitle() const { return QString("#secconfig#" + QString::number(m_latteView->containment()->id())); } QRect SecondaryConfigView::geometryWhenVisible() const { return m_geometryWhenVisible; } void SecondaryConfigView::requestActivate() { if (KWindowSystem::isPlatformWayland() && m_shellSurface) { updateWaylandId(); 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()); + auto geometry = QRect(position.x(), position.y(), size.width(), size.height()); + + if (m_geometryWhenVisible == geometry) { + return; + } + + m_geometryWhenVisible = geometry; setPosition(position); if (m_shellSurface) { m_shellSurface->setPosition(position); } + setMaximumSize(size); + setMinimumSize(size); + resize(size); + + updateViewMask(); + //! 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::updateViewMask() +{ + bool environmentState = (KWindowSystem::isPlatformX11() && KWindowSystem::compositingActive()); + + if (!environmentState) { + return; + } + + int x, y, thickness, length; + QRegion area; + + thickness = m_latteView->effects()->editShadow(); + + if (m_latteView->formFactor() == Plasma::Types::Vertical) { + length = m_geometryWhenVisible.height(); + } else { + length = m_geometryWhenVisible.width(); + } + + if (m_latteView->formFactor() == Plasma::Types::Horizontal) { + x = m_geometryWhenVisible.x() - m_latteView->x(); + } else { + y = m_geometryWhenVisible.y() - m_latteView->y(); + } + + if (m_latteView->location() == Plasma::Types::BottomEdge) { + y = m_latteView->height() - m_latteView->editThickness() - m_latteView->effects()->editShadow(); + } else if (m_latteView->location() == Plasma::Types::TopEdge) { + y = m_latteView->editThickness(); + } else if (m_latteView->location() == Plasma::Types::LeftEdge) { + x = m_latteView->editThickness(); + } else if (m_latteView->location() == Plasma::Types::RightEdge) { + x = m_latteView->width() - m_latteView->editThickness() - m_latteView->effects()->editShadow(); + } + + if (m_latteView->formFactor() == Plasma::Types::Horizontal) { + area = QRect(x, y, length, thickness); + } else { + area = QRect(x, y, thickness, length); + } + + m_latteView->effects()->setSubtractedMaskRegion(validTitle(), area); +} + 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); + updateViewMask(); 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() { + m_latteView->effects()->removeSubtractedMaskRegion(validTitle()); + if (m_shellSurface) { //!NOTE: Avoid crash in wayland environment with qt5.9 close(); } else { hide(); } } void SecondaryConfigView::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); } } 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; } //! 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() != "dialogs/background") { m_background->setImagePath(QStringLiteral("dialogs/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 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; m_corona->dialogShadows()->addWindow(this, m_enabledBorders); emit enabledBordersChanged(); } } //!END borders } } diff --git a/app/view/settings/secondaryconfigview.h b/app/view/settings/secondaryconfigview.h index f50f9e4b..728fca8b 100644 --- a/app/view/settings/secondaryconfigview.h +++ b/app/view/settings/secondaryconfigview.h @@ -1,128 +1,129 @@ /* * 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 . */ #ifndef SECONDARYCONFIGVIEW_H #define SECONDARYCONFIGVIEW_H // local #include #include "../../wm/windowinfowrap.h" //Qt #include #include #include #include // Plasma #include #include namespace Plasma { class Applet; class Containment; class FrameSvg; class Types; } namespace KWayland { namespace Client { class PlasmaShellSurface; } } namespace Latte { class Corona; class View; } namespace Latte { namespace ViewPart { class PrimaryConfigView; } } namespace Latte { namespace ViewPart { class SecondaryConfigView : public QQuickView { Q_OBJECT Q_PROPERTY(Plasma::FrameSvg::EnabledBorders enabledBorders READ enabledBorders NOTIFY enabledBordersChanged) public: SecondaryConfigView(Latte::View *view, QWindow *parent); ~SecondaryConfigView() override; void init(); void requestActivate(); Qt::WindowFlags wFlags() const; QRect geometryWhenVisible() const; QString validTitle() const; Plasma::FrameSvg::EnabledBorders enabledBorders() const; public slots: Q_INVOKABLE void hideConfigWindow(); Q_INVOKABLE void syncGeometry(); Q_INVOKABLE void updateEffects(); signals: void enabledBordersChanged(); void showSignal(); protected: void showEvent(QShowEvent *ev) override; void focusOutEvent(QFocusEvent *ev) override; bool event(QEvent *e) override; void syncSlideEffect(); private slots: void updateEnabledBorders(); void updateWaylandId(); + void updateViewMask(); private: void setupWaylandIntegration(); QRect m_geometryWhenVisible; QPointer m_latteView; QPointer m_parent; QTimer m_screenSyncTimer; QTimer m_thicknessSyncTimer; QList connections; Plasma::FrameSvg::EnabledBorders m_enabledBorders{Plasma::FrameSvg::AllBorders}; //only for the mask on disabled compositing, not to actually paint Plasma::FrameSvg *m_background{nullptr}; Latte::Corona *m_corona{nullptr}; Latte::WindowSystem::WindowId m_waylandWindowId; KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr}; }; } } #endif //SECONDARYCONFIGVIEW_H diff --git a/shell/package/contents/configuration/LatteDockConfiguration.qml b/shell/package/contents/configuration/LatteDockConfiguration.qml index 70d91389..3af7c009 100644 --- a/shell/package/contents/configuration/LatteDockConfiguration.qml +++ b/shell/package/contents/configuration/LatteDockConfiguration.qml @@ -1,705 +1,705 @@ /* * 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.core 0.2 as LatteCore import org.kde.latte.components 1.0 as LatteComponents import "pages" as Pages import "../controls" as LatteExtraControls FocusScope { id: dialog readonly property bool basicLevel: !advancedLevel readonly property bool advancedLevel: viewConfig.inAdvancedMode readonly property bool inConfigureAppletsMode: plasmoid.configuration.inConfigureAppletsMode || !LatteCore.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.advancedLevel ? 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 === LatteCore.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) onAdvancedLevelChanged: { //! switch to appearancePage when effectsPage becomes hidden because //! advancedLevel was disabled by the user if (!advancedLevel && 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" enabledBorders: viewConfig.enabledBorders onEnabledBordersChanged: 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.advancedLevel && ctrlModifier); updatingHeightScale = dialog.basicLevel && 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 LatteCore.IconItem { id: logo width: Math.round(1.4 * latteTxtMetrics.font.pixelSize) height: width smooth: true source: "latte-dock" usesPlasmaTheme: false } 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() } } } Item{ id: headerSpacer Layout.minimumHeight: advancedSettings.height + 2*units.smallSpacing } ColumnLayout { PlasmaComponents3.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 * 1.5 //!avoid editMode box shadow Layout.topMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing icon.name: "window-pin" checkable: true width: 7 * units.smallSpacing 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: advancedSettings 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: advancedLbl 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: advancedMouseArea anchors.fill: parent hoverEnabled: true onClicked: { advancedSwitch.checked = !advancedSwitch.checked; } } } LatteComponents.Switch { id: advancedSwitch checked: viewConfig.inAdvancedMode onCheckedChanged: viewConfig.inAdvancedMode = checked; } } } } 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.advancedLevel } Repeater { id: tasksTabButtonRepeater model: latteView.extendedInterface.tasksModel PlasmaComponents.TabButton { text: index >= 1 ? i18nc("tasks header and index","Tasks <%0>").arg(index+1) : i18n("Tasks") tab: tasksRepeater.itemAt(index) } } } 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 } } } Repeater { id: tasksRepeater //! needs to be out of TabGroup otherwise the Repeater is consider as TabGroup direct children //! and thus only the first Tasks tab is shown model: latteView.extendedInterface.tasksModel //! Reparent TasksPages when all of them are loaded //! this way we avoid warnings from ::stackAfter //! After startup any new TasksPages can be added directly property bool isReady: false property int pages: 0 Pages.TasksConfig { id: tasksPage Component.onCompleted: { if (tasksRepeater.isReady) { parent = tabGroup; } else { tasksRepeater.pages = tasksRepeater.pages + 1; } } } onPagesChanged: { if (pages === latteView.extendedInterface.tasksModel.rowCount()) { //! Reparent TasksPages when all of them are loaded //! this way we avoid warnings from ::stackAfter for(var i=0; i 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: !LatteCore.WindowSystem.isPlatformWayland && LatteCore.WindowSystem.compositingActive && latteView.effects.settingsMaskSubtracted + visible: !LatteCore.WindowSystem.isPlatformWayland && LatteCore.WindowSystem.compositingActive readonly property real maxOpacity: LatteCore.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 b67d37f1..8fcb8f8f 100644 --- a/shell/package/contents/configuration/LatteDockSecondaryConfiguration.qml +++ b/shell/package/contents/configuration/LatteDockSecondaryConfiguration.qml @@ -1,92 +1,92 @@ /* * 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.core 0.2 as LatteCore import "../controls" as LatteExtraControls FocusScope { id: dialog 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" enabledBorders: viewConfig.enabledBorders onEnabledBordersChanged: 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: !LatteCore.WindowSystem.isPlatformWayland && LatteCore.WindowSystem.compositingActive && latteView.effects.settingsMaskSubtracted + visible: !LatteCore.WindowSystem.isPlatformWayland && LatteCore.WindowSystem.compositingActive readonly property real maxOpacity: LatteCore.WindowSystem.compositingActive && !plasmoid.configuration.inConfigureAppletsMode ? plasmoid.configuration.editBackgroundOpacity : 1 } }