/* * Copyright 2021 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 "widgetexplorerview.h" // local #include "../panelshadows_p.h" #include "../view.h" #include "../../lattecorona.h" #include "../../wm/abstractwindowinterface.h" // Qt #include #include // KDE #include #include #include // Plasma #include namespace Latte { namespace ViewPart { WidgetExplorerView::WidgetExplorerView(Latte::View *view) : SubConfigView(view, QString("#widgetexplorerview#"), true) { setResizeMode(QQuickView::SizeRootObjectToView); connect(this, &QQuickView::widthChanged, this, &WidgetExplorerView::updateEffects); connect(this, &QQuickView::heightChanged, this, &WidgetExplorerView::updateEffects); connect(this, &QQuickView::statusChanged, [&](QQuickView::Status status) { if (status == QQuickView::Ready) { updateEffects(); } }); setParentView(view); init(); } void WidgetExplorerView::init() { SubConfigView::init(); QByteArray tempFilePath = "widgetexplorerui"; updateEnabledBorders(); auto source = QUrl::fromLocalFile(m_latteView->containment()->corona()->kPackage().filePath(tempFilePath)); setSource(source); syncGeometry(); } bool WidgetExplorerView::hideOnWindowDeactivate() const { return m_hideOnWindowDeactivate; } void WidgetExplorerView::setHideOnWindowDeactivate(bool hide) { if (m_hideOnWindowDeactivate == hide) { return; } m_hideOnWindowDeactivate = hide; emit hideOnWindowDeactivateChanged(); } Qt::WindowFlags WidgetExplorerView::wFlags() const { return (flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); } QRect WidgetExplorerView::geometryWhenVisible() const { return m_geometryWhenVisible; } void WidgetExplorerView::initParentView(Latte::View *view) { SubConfigView::initParentView(view); rootContext()->setContextProperty(QStringLiteral("containmentFromView"), m_latteView->containment()); updateEnabledBorders(); syncGeometry(); } QRect WidgetExplorerView::availableScreenGeometry() const { int currentScrId = m_latteView->positioner()->currentScreenId(); QList ignoreModes{Latte::Types::SidebarOnDemand,Latte::Types::SidebarAutoHide}; if (m_latteView->visibility() && m_latteView->visibility()->isSidebar()) { ignoreModes.removeAll(Latte::Types::SidebarOnDemand); ignoreModes.removeAll(Latte::Types::SidebarAutoHide); } QString activityid = m_latteView->layout()->lastUsedActivity(); return m_corona->availableScreenRectWithCriteria(currentScrId, activityid, ignoreModes, {}, false, true); } void WidgetExplorerView::syncGeometry() { if (!m_latteView || !m_latteView->layout() || !m_latteView->containment() || !rootObject()) { return; } const QSize size(rootObject()->width(), rootObject()->height()); auto availGeometry = availableScreenGeometry(); int margin = availGeometry.height() == m_latteView->screenGeometry().height() ? 100 : 0; auto geometry = QRect(availGeometry.x(), availGeometry.y(), size.width(), availGeometry.height()-margin); updateEnabledBorders(); if (m_geometryWhenVisible == geometry) { return; } m_geometryWhenVisible = geometry; setPosition(geometry.topLeft()); if (m_shellSurface) { m_shellSurface->setPosition(geometry.topLeft()); } setMaximumSize(geometry.size()); setMinimumSize(geometry.size()); resize(geometry.size()); } void WidgetExplorerView::showEvent(QShowEvent *ev) { if (m_shellSurface) { //! under wayland it needs to be set again after its hiding m_shellSurface->setPosition(m_geometryWhenVisible.topLeft()); } SubConfigView::showEvent(ev); if (!m_latteView) { return; } syncGeometry(); requestActivate(); m_screenSyncTimer.start(); QTimer::singleShot(400, this, &WidgetExplorerView::syncGeometry); emit showSignal(); } void WidgetExplorerView::focusOutEvent(QFocusEvent *ev) { Q_UNUSED(ev); if (!m_latteView) { return; } hideConfigWindow(); } void WidgetExplorerView::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); } } void WidgetExplorerView::hideConfigWindow() { if (!m_hideOnWindowDeactivate) { return; } QTimer::singleShot(100, [this]() { //! avoid crashes under wayland because some mouse events are sended after the surface is destroyed if (m_shellSurface) { //!NOTE: Avoid crash in wayland environment with qt5.9 close(); } else { hide(); } }); } void WidgetExplorerView::syncSlideEffect() { if (!m_latteView || !m_latteView->containment()) { return; } auto slideLocation = WindowSystem::AbstractWindowInterface::Slide::Left; m_corona->wm()->slideWindow(*this, slideLocation); } //!BEGIN borders void WidgetExplorerView::updateEnabledBorders() { if (!this->screen()) { return; } Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; if (!m_geometryWhenVisible.isEmpty()) { if (m_geometryWhenVisible.x() == m_latteView->screenGeometry().x()) { borders &= ~Plasma::FrameSvg::LeftBorder; } if (m_geometryWhenVisible.y() == m_latteView->screenGeometry().y()) { borders &= ~Plasma::FrameSvg::TopBorder; } if (m_geometryWhenVisible.height() == m_latteView->screenGeometry().height()) { borders &= ~Plasma::FrameSvg::BottomBorder; } } if (m_enabledBorders != borders) { if (isVisible()) { m_enabledBorders = borders; } m_corona->dialogShadows()->addWindow(this, m_enabledBorders); emit enabledBordersChanged(); } } //!END borders } }