diff --git a/app/view/visibilitymanager.cpp b/app/view/visibilitymanager.cpp index 5f8afaa1..418ce166 100644 --- a/app/view/visibilitymanager.cpp +++ b/app/view/visibilitymanager.cpp @@ -1,760 +1,762 @@ /* * 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 "visibilitymanager.h" // local #include "positioner.h" #include "screenedgeghostwindow.h" #include "view.h" #include "windowstracker/currentscreentracker.h" #include "../lattecorona.h" #include "../screenpool.h" #include "../layouts/manager.h" #include "../wm/abstractwindowinterface.h" #include "../../liblatte2/extras.h" // Qt #include // KDE #include #include #include namespace Latte { namespace ViewPart { //! BEGIN: VisiblityManager implementation VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view) : QObject(view) { qDebug() << "VisibilityManager creating..."; m_latteView = qobject_cast(view); m_corona = qobject_cast(view->corona()); m_wm = m_corona->wm(); connect(this, &VisibilityManager::slideInFinished, this, &VisibilityManager::updateHiddenState); connect(this, &VisibilityManager::slideOutFinished, this, &VisibilityManager::updateHiddenState); if (m_latteView) { connect(m_latteView, &Latte::View::eventTriggered, this, &VisibilityManager::viewEventManager); + connect(m_latteView, &Latte::View::byPassWMChanged, this, &VisibilityManager::updateKWinEdgesSupport); connect(m_latteView, &Latte::View::absoluteGeometryChanged, this, [&]() { if (m_mode == Types::AlwaysVisible && m_latteView->screen()) { updateStrutsBasedOnLayoutsAndActivities(); } }); connect(m_latteView->windowsTracker(), &WindowsTracker::activeWindowDraggingStarted, this, &VisibilityManager::activeWindowDraggingStarted); } if (m_corona) { connect(this, &VisibilityManager::modeChanged, this, [&]() { emit m_corona->availableScreenRectChangedFrom(m_latteView); }); } m_timerStartUp.setInterval(5000); m_timerStartUp.setSingleShot(true); m_timerShow.setSingleShot(true); m_timerHide.setSingleShot(true); connect(&m_timerShow, &QTimer::timeout, this, [&]() { if (m_isHidden) { // qDebug() << "must be shown"; emit mustBeShown(); } }); connect(&m_timerHide, &QTimer::timeout, this, [&]() { if (!m_blockHiding && !m_isHidden && !m_dragEnter) { // qDebug() << "must be hide"; emit mustBeHide(); } }); restoreConfig(); } VisibilityManager::~VisibilityManager() { qDebug() << "VisibilityManager deleting..."; m_wm->removeViewStruts(*m_latteView); if (m_edgeGhostWindow) { m_edgeGhostWindow->deleteLater(); } } Types::Visibility VisibilityManager::mode() const { return m_mode; } void VisibilityManager::setMode(Latte::Types::Visibility mode) { if (m_mode == mode) return; Q_ASSERT_X(mode != Types::None, staticMetaObject.className(), "set visibility to Types::None"); // clear mode for (auto &c : m_connections) { disconnect(c); } int base{0}; m_publishedStruts = QRect(); if (m_mode == Types::AlwaysVisible) { //! remove struts for old always visible mode m_wm->removeViewStruts(*m_latteView); } m_timerShow.stop(); m_timerHide.stop(); m_mode = mode; if (mode != Types::AlwaysVisible && mode != Types::WindowsGoBelow) { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } m_connections[0] = connect(m_wm, &WindowSystem::AbstractWindowInterface::currentDesktopChanged, this, [&] { if (m_raiseOnDesktopChange) { raiseViewTemporarily(); } }); m_connections[1] = connect(m_wm, &WindowSystem::AbstractWindowInterface::currentActivityChanged, this, [&]() { if (m_raiseOnActivityChange) { raiseViewTemporarily(); } else { updateHiddenState(); } }); base = 2; } else { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } } switch (m_mode) { case Types::AlwaysVisible: { if (m_latteView->containment() && m_latteView->screen()) { updateStrutsBasedOnLayoutsAndActivities(); } m_connections[base] = connect(m_corona->layoutsManager(), &Layouts::Manager::currentLayoutNameChanged, this, [&]() { if (m_corona && m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { updateStrutsBasedOnLayoutsAndActivities(true); } }); m_connections[base+1] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() { if (m_corona && m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { updateStrutsBasedOnLayoutsAndActivities(true); } }); raiseView(true); break; } case Types::AutoHide: { m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged, this, [&]() { raiseView(m_containsMouse); }); raiseView(m_containsMouse); break; } case Types::DodgeActive: { m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged , this, &VisibilityManager::dodgeActive); m_connections[base+1] = connect(m_latteView->windowsTracker()->currentScreen(), &TrackerPart::CurrentScreenTracker::activeWindowTouchingChanged , this, &VisibilityManager::dodgeActive); dodgeActive(); break; } case Types::DodgeMaximized: { m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged , this, &VisibilityManager::dodgeMaximized); m_connections[base+1] = connect(m_latteView->windowsTracker()->currentScreen(), &TrackerPart::CurrentScreenTracker::activeWindowMaximizedChanged , this, &VisibilityManager::dodgeMaximized); dodgeMaximized(); break; } case Types::DodgeAllWindows: { m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged , this, &VisibilityManager::dodgeAllWindows); m_connections[base+1] = connect(m_latteView->windowsTracker()->currentScreen(), &TrackerPart::CurrentScreenTracker::existsWindowTouchingChanged , this, &VisibilityManager::dodgeAllWindows); dodgeAllWindows(); break; } case Types::WindowsGoBelow: break; default: break; } m_latteView->containment()->config().writeEntry("visibility", static_cast(m_mode)); updateKWinEdgesSupport(); emit modeChanged(); } void VisibilityManager::updateStrutsBasedOnLayoutsAndActivities(bool forceUpdate) { bool multipleLayoutsAndCurrent = (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->layout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->layout()->isCurrent()); if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout || multipleLayoutsAndCurrent) { QRect computedStruts = acceptableStruts(); if (m_publishedStruts != computedStruts || forceUpdate) { //! Force update is needed when very important events happen in DE and there is a chance //! that previously even though struts where sent the DE did not accept them. //! Such a case is when STOPPING an Activity and windows faulty become invisible even //! though they should not. In such case setting struts when the windows are hidden //! the struts do not take any effect m_publishedStruts = computedStruts; m_wm->setViewStruts(*m_latteView, m_publishedStruts, m_latteView->location()); } } else { m_publishedStruts = QRect(); m_wm->removeViewStruts(*m_latteView); } } QRect VisibilityManager::acceptableStruts() { QRect calcs; switch (m_latteView->location()) { case Plasma::Types::TopEdge: { calcs = QRect(m_latteView->x(), m_latteView->y(), m_latteView->width(), m_latteView->normalThickness()); break; } case Plasma::Types::BottomEdge: { int y = m_latteView->y() + m_latteView->height() - m_latteView->normalThickness(); calcs = QRect(m_latteView->x(), y, m_latteView->width(), m_latteView->normalThickness()); break; } case Plasma::Types::LeftEdge: { calcs = QRect(m_latteView->x(), m_latteView->y(), m_latteView->normalThickness(), m_latteView->height()); break; } case Plasma::Types::RightEdge: { int x = m_latteView->x() + m_latteView->width() - m_latteView->normalThickness(); calcs = QRect(x, m_latteView->y(), m_latteView->normalThickness(), m_latteView->height()); break; } } return calcs; } bool VisibilityManager::raiseOnDesktop() const { return m_raiseOnDesktopChange; } void VisibilityManager::setRaiseOnDesktop(bool enable) { if (enable == m_raiseOnDesktopChange) return; m_raiseOnDesktopChange = enable; emit raiseOnDesktopChanged(); } bool VisibilityManager::raiseOnActivity() const { return m_raiseOnActivityChange; } void VisibilityManager::setRaiseOnActivity(bool enable) { if (enable == m_raiseOnActivityChange) return; m_raiseOnActivityChange = enable; emit raiseOnActivityChanged(); } bool VisibilityManager::isHidden() const { return m_isHidden; } void VisibilityManager::setIsHidden(bool isHidden) { if (m_isHidden == isHidden) return; if (m_blockHiding && isHidden) { qWarning() << "isHidden property is blocked, ignoring update"; return; } m_isHidden = isHidden; updateGhostWindowState(); emit isHiddenChanged(); } bool VisibilityManager::blockHiding() const { return m_blockHiding; } void VisibilityManager::setBlockHiding(bool blockHiding) { if (m_blockHiding == blockHiding) { return; } m_blockHiding = blockHiding; // qDebug() << "blockHiding:" << blockHiding; if (m_blockHiding) { m_timerHide.stop(); if (m_isHidden) { emit mustBeShown(); } } else { updateHiddenState(); } emit blockHidingChanged(); } int VisibilityManager::timerShow() const { return m_timerShow.interval(); } void VisibilityManager::setTimerShow(int msec) { m_timerShow.setInterval(msec); emit timerShowChanged(); } int VisibilityManager::timerHide() const { return m_timerHide.interval(); } void VisibilityManager::setTimerHide(int msec) { m_timerHide.setInterval(msec); emit timerHideChanged(); } bool VisibilityManager::supportsKWinEdges() const { return (m_edgeGhostWindow != nullptr); } void VisibilityManager::updateGhostWindowState() { if (supportsKWinEdges()) { bool inCurrentLayout = (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout || (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->layout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->layout()->name() == m_corona->layoutsManager()->currentLayoutName())); if (inCurrentLayout) { m_wm->setEdgeStateFor(m_edgeGhostWindow, m_isHidden); } else { m_wm->setEdgeStateFor(m_edgeGhostWindow, false); } } } void VisibilityManager::hide() { if (KWindowSystem::isPlatformX11()) { m_latteView->setVisible(false); } } void VisibilityManager::show() { if (KWindowSystem::isPlatformX11()) { m_latteView->setVisible(true); } } void VisibilityManager::raiseView(bool raise) { if (m_blockHiding) return; if (raise) { m_timerHide.stop(); if (!m_timerShow.isActive()) { m_timerShow.start(); } } else if (!m_dragEnter) { m_timerShow.stop(); if (m_hideNow) { m_hideNow = false; emit mustBeHide(); } else if (!m_timerHide.isActive()) { m_timerHide.start(); } } } void VisibilityManager::raiseViewTemporarily() { if (m_raiseTemporarily) return; m_raiseTemporarily = true; m_timerHide.stop(); m_timerShow.stop(); if (m_isHidden) emit mustBeShown(); QTimer::singleShot(qBound(1800, 2 * m_timerHide.interval(), 3000), this, [&]() { m_raiseTemporarily = false; m_hideNow = true; updateHiddenState(); }); } void VisibilityManager::updateHiddenState() { if (m_dragEnter) return; switch (m_mode) { case Types::AutoHide: raiseView(m_containsMouse); break; case Types::DodgeActive: dodgeActive(); break; case Types::DodgeMaximized: dodgeMaximized(); break; case Types::DodgeAllWindows: dodgeAllWindows(); break; default: break; } } void VisibilityManager::applyActivitiesToHiddenWindows(const QStringList &activities) { if (m_edgeGhostWindow) { m_wm->setWindowOnActivities(*m_edgeGhostWindow, activities); } } void VisibilityManager::activeWindowDraggingStarted() { setContainsMouse(false); updateHiddenState(); } void VisibilityManager::dodgeActive() { if (m_raiseTemporarily) return; //!don't send false raiseView signal when containing mouse if (m_containsMouse) { raiseView(true); return; } raiseView(!m_latteView->windowsTracker()->currentScreen()->activeWindowTouching()); } void VisibilityManager::dodgeMaximized() { if (m_raiseTemporarily) return; //!don't send false raiseView signal when containing mouse if (m_containsMouse) { raiseView(true); return; } raiseView(!m_latteView->windowsTracker()->currentScreen()->activeWindowMaximized()); } void VisibilityManager::dodgeAllWindows() { if (m_raiseTemporarily) return; if (m_containsMouse) { raiseView(true); } bool windowIntersects{m_latteView->windowsTracker()->currentScreen()->activeWindowTouching() || m_latteView->windowsTracker()->currentScreen()->existsWindowTouching()}; raiseView(!windowIntersects); } void VisibilityManager::saveConfig() { if (!m_latteView->containment()) return; auto config = m_latteView->containment()->config(); config.writeEntry("enableKWinEdges", m_enableKWinEdgesFromUser); config.writeEntry("timerShow", m_timerShow.interval()); config.writeEntry("timerHide", m_timerHide.interval()); config.writeEntry("raiseOnDesktopChange", m_raiseOnDesktopChange); config.writeEntry("raiseOnActivityChange", m_raiseOnActivityChange); m_latteView->containment()->configNeedsSaving(); } void VisibilityManager::restoreConfig() { if (!m_latteView || !m_latteView->containment()){ return; } auto config = m_latteView->containment()->config(); m_timerShow.setInterval(config.readEntry("timerShow", 0)); m_timerHide.setInterval(config.readEntry("timerHide", 700)); emit timerShowChanged(); emit timerHideChanged(); m_enableKWinEdgesFromUser = config.readEntry("enableKWinEdges", true); emit enableKWinEdgesChanged(); setRaiseOnDesktop(config.readEntry("raiseOnDesktopChange", false)); setRaiseOnActivity(config.readEntry("raiseOnActivityChange", false)); auto storedMode = static_cast(m_latteView->containment()->config().readEntry("visibility", static_cast(Types::DodgeActive))); if (storedMode == Types::AlwaysVisible) { qDebug() << "Loading visibility mode: Always Visible , on startup..."; setMode(Types::AlwaysVisible); } else { connect(&m_timerStartUp, &QTimer::timeout, this, [&]() { if (!m_latteView || !m_latteView->containment()) { return; } auto fMode = static_cast(m_latteView->containment()->config().readEntry("visibility", static_cast(Types::DodgeActive))); qDebug() << "Loading visibility mode:" << fMode << " on startup..."; setMode(fMode); }); connect(m_latteView->containment(), &Plasma::Containment::userConfiguringChanged , this, [&](bool configuring) { if (configuring && m_timerStartUp.isActive()) m_timerStartUp.start(100); }); m_timerStartUp.start(); } connect(m_latteView->containment(), &Plasma::Containment::userConfiguringChanged , this, [&](bool configuring) { if (!configuring) { saveConfig(); } }); } bool VisibilityManager::containsMouse() const { return m_containsMouse; } void VisibilityManager::setContainsMouse(bool contains) { if (m_containsMouse == contains) { return; } m_containsMouse = contains; emit containsMouseChanged(); if (contains && m_mode != Types::AlwaysVisible) { raiseView(true); } } void VisibilityManager::viewEventManager(QEvent *ev) { switch (ev->type()) { case QEvent::Enter: setContainsMouse(true); break; case QEvent::Leave: setContainsMouse(false); break; case QEvent::DragEnter: m_dragEnter = true; if (m_isHidden) emit mustBeShown(); break; case QEvent::DragLeave: case QEvent::Drop: m_dragEnter = false; updateHiddenState(); break; default: break; } } //! KWin Edges Support functions bool VisibilityManager::enableKWinEdges() const { return m_enableKWinEdgesFromUser; } void VisibilityManager::setEnableKWinEdges(bool enable) { if (m_enableKWinEdgesFromUser == enable) { return; } m_enableKWinEdgesFromUser = enable; emit enableKWinEdgesChanged(); updateKWinEdgesSupport(); } void VisibilityManager::updateKWinEdgesSupport() { - if (m_mode == Types::AutoHide + if ((m_mode == Types::AutoHide || m_mode == Types::DodgeActive || m_mode == Types::DodgeAllWindows - || m_mode == Types::DodgeMaximized) { + || m_mode == Types::DodgeMaximized) + && (!m_latteView->byPassWM()) ) { if (m_enableKWinEdgesFromUser) { createEdgeGhostWindow(); } else if (!m_enableKWinEdgesFromUser) { deleteEdgeGhostWindow(); } } else if (m_mode == Types::AlwaysVisible || m_mode == Types::WindowsGoBelow) { deleteEdgeGhostWindow(); } } void VisibilityManager::createEdgeGhostWindow() { if (!m_edgeGhostWindow) { m_edgeGhostWindow = new ScreenEdgeGhostWindow(m_latteView); m_wm->setViewExtraFlags(*m_edgeGhostWindow); connect(m_edgeGhostWindow, &ScreenEdgeGhostWindow::containsMouseChanged, this, [ = ](bool contains) { if (contains) { raiseView(true); } else { m_timerShow.stop(); updateGhostWindowState(); } }); m_connectionsKWinEdges[0] = connect(m_wm, &WindowSystem::AbstractWindowInterface::currentActivityChanged, this, [&]() { bool inCurrentLayout = (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout || (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->layout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->layout()->name() == m_corona->layoutsManager()->currentLayoutName())); if (m_edgeGhostWindow) { if (inCurrentLayout) { m_wm->setEdgeStateFor(m_edgeGhostWindow, m_isHidden); } else { m_wm->setEdgeStateFor(m_edgeGhostWindow, false); } } }); emit supportsKWinEdgesChanged(); } } void VisibilityManager::deleteEdgeGhostWindow() { if (m_edgeGhostWindow) { m_edgeGhostWindow->deleteLater(); m_edgeGhostWindow = nullptr; for (auto &c : m_connectionsKWinEdges) { disconnect(c); } emit supportsKWinEdgesChanged(); } } //! END: VisibilityManager implementation } } diff --git a/app/view/visibilitymanager.h b/app/view/visibilitymanager.h index 84ed5090..85812fea 100644 --- a/app/view/visibilitymanager.h +++ b/app/view/visibilitymanager.h @@ -1,188 +1,190 @@ /* * 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 VISIBILITYMANAGER_H #define VISIBILITYMANAGER_H // local #include "../plasma/quick/containmentview.h" #include "../../liblatte2/types.h" // Qt #include #include // Plasma #include namespace Latte { class Corona; class View; namespace ViewPart { class ScreenEdgeGhostWindow; } namespace WindowSystem { class AbstractWindowInterface; } } namespace Latte { namespace ViewPart { class VisibilityManager : public QObject { Q_OBJECT Q_PROPERTY(Latte::Types::Visibility mode READ mode WRITE setMode NOTIFY modeChanged) Q_PROPERTY(bool raiseOnDesktop READ raiseOnDesktop WRITE setRaiseOnDesktop NOTIFY raiseOnDesktopChanged) Q_PROPERTY(bool raiseOnActivity READ raiseOnActivity WRITE setRaiseOnActivity NOTIFY raiseOnActivityChanged) Q_PROPERTY(bool isHidden READ isHidden WRITE setIsHidden NOTIFY isHiddenChanged) Q_PROPERTY(bool blockHiding READ blockHiding WRITE setBlockHiding NOTIFY blockHidingChanged) Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged) //! KWin Edges Support Options Q_PROPERTY(bool enableKWinEdges READ enableKWinEdges WRITE setEnableKWinEdges NOTIFY enableKWinEdgesChanged) Q_PROPERTY(bool supportsKWinEdges READ supportsKWinEdges NOTIFY supportsKWinEdgesChanged) Q_PROPERTY(int timerShow READ timerShow WRITE setTimerShow NOTIFY timerShowChanged) Q_PROPERTY(int timerHide READ timerHide WRITE setTimerHide NOTIFY timerHideChanged) public: explicit VisibilityManager(PlasmaQuick::ContainmentView *view); virtual ~VisibilityManager(); Latte::Types::Visibility mode() const; void setMode(Latte::Types::Visibility mode); void applyActivitiesToHiddenWindows(const QStringList &activities); bool raiseOnDesktop() const; void setRaiseOnDesktop(bool enable); bool raiseOnActivity() const; void setRaiseOnActivity(bool enable); bool isHidden() const; void setIsHidden(bool isHidden); bool blockHiding() const; void setBlockHiding(bool blockHiding); bool containsMouse() const; int timerShow() const; void setTimerShow(int msec); int timerHide() const; void setTimerHide(int msec); //! KWin Edges Support functions bool enableKWinEdges() const; void setEnableKWinEdges(bool enable); bool supportsKWinEdges() const; //! called for windowTracker to reset values void activeWindowDraggingStarted(); public slots: Q_INVOKABLE void hide(); Q_INVOKABLE void show(); signals: void mustBeShown(); void mustBeHide(); void slideOutFinished(); void slideInFinished(); void modeChanged(); void raiseOnDesktopChanged(); void raiseOnActivityChanged(); void isHiddenChanged(); void blockHidingChanged(); void containsMouseChanged(); void timerShowChanged(); void timerHideChanged(); //! KWin Edges Support signals void enableKWinEdgesChanged(); void supportsKWinEdgesChanged(); private slots: void saveConfig(); void restoreConfig(); + //! KWin Edges Support functions + void updateKWinEdgesSupport(); + private: void setContainsMouse(bool contains); void raiseView(bool raise); void raiseViewTemporarily(); //! KWin Edges Support functions void createEdgeGhostWindow(); void deleteEdgeGhostWindow(); - void updateKWinEdgesSupport(); void updateGhostWindowState(); void updateStrutsBasedOnLayoutsAndActivities(bool forceUpdate = false); void viewEventManager(QEvent *ev); QRect acceptableStruts(); private slots: void dodgeAllWindows(); void dodgeActive(); void dodgeMaximized(); void updateHiddenState(); private: WindowSystem::AbstractWindowInterface *m_wm; Types::Visibility m_mode{Types::None}; std::array m_connections; QTimer m_timerShow; QTimer m_timerHide; QTimer m_timerStartUp; bool m_isHidden{false}; bool m_dragEnter{false}; bool m_blockHiding{false}; bool m_containsMouse{false}; bool m_raiseTemporarily{false}; bool m_raiseOnDesktopChange{false}; bool m_raiseOnActivityChange{false}; bool m_hideNow{false}; QRect m_publishedStruts; //! KWin Edges bool m_enableKWinEdgesFromUser{true}; std::array m_connectionsKWinEdges; ScreenEdgeGhostWindow *m_edgeGhostWindow{nullptr}; Latte::Corona *m_corona{nullptr}; Latte::View *m_latteView{nullptr}; }; } } #endif // VISIBILITYMANAGER_H diff --git a/shell/package/contents/configuration/pages/BehaviorConfig.qml b/shell/package/contents/configuration/pages/BehaviorConfig.qml index 4857dc28..6f3333ce 100644 --- a/shell/package/contents/configuration/pages/BehaviorConfig.qml +++ b/shell/package/contents/configuration/pages/BehaviorConfig.qml @@ -1,783 +1,784 @@ /* * 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.0 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 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.plasmoid 2.0 import org.kde.latte 0.2 as Latte import org.kde.latte.components 1.0 as LatteComponents import "../../controls" as LatteExtraControls PlasmaComponents.Page { Layout.maximumWidth: content.width + content.Layout.leftMargin * 2 Layout.maximumHeight: content.height + units.smallSpacing * 2 ColumnLayout { id: content width: (dialog.appliedWidth - units.smallSpacing * 2) - Layout.leftMargin * 2 spacing: dialog.subGroupSpacing anchors.horizontalCenter: parent.horizontalCenter Layout.leftMargin: units.smallSpacing * 2 //! BEGIN: Inline Dock/Panel Type, it is used only when the secondary window //! overlaps the main dock config window ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing Layout.topMargin: units.smallSpacing visible: dialog.highLevel && viewConfig.showInlineProperties LatteComponents.Header { text: i18n("Type") } LatteExtraControls.TypeSelection{ id: viewTypeSelection horizontal: true } } //! END: Inline Dock/Panel Type //! BEGIN: Location ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing Layout.topMargin: units.smallSpacing LatteComponents.Header { text: screenRow.visible ? i18n("Screen") : i18n("Location") } Connections { target: universalSettings onScreensCountChanged: screenRow.updateScreens() } RowLayout { id: screenRow Layout.fillWidth: true Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 3 spacing: 2 visible: true function updateScreens() { if (universalSettings.screens.length > 1) { screenRow.visible = true; } else { screenRow.visible = false; } screensModel.clear(); var primary = {name: i18n("On Primary"), icon: 'favorites'}; screensModel.append(primary); //check if the screen exists, it is used in cases Latte is moving //the view automatically to primaryScreen in order for the user //to has always a view with tasks shown var screenExists = false for (var i = 0; i < universalSettings.screens.length; i++) { if (universalSettings.screens[i].name === latteView.positioner.currentScreenName) { screenExists = true; } } if (!screenExists && !latteView.onPrimary) { var scr = {name: latteView.positioner.currentScreenName, icon: 'view-fullscreen'}; screensModel.append(scr); } for (var i = 0; i < universalSettings.screens.length; i++) { var scr = {name: universalSettings.screens[i].name, icon: 'view-fullscreen'}; screensModel.append(scr); } if (latteView.onPrimary) { screenCmb.currentIndex = 0; } else { screenCmb.currentIndex = screenCmb.findScreen(latteView.positioner.currentScreenName); } console.log(latteView.positioner.currentScreenName); } Connections{ target: viewConfig onShowSignal: screenRow.updateScreens(); } ListModel { id: screensModel } LatteComponents.ComboBox { id: screenCmb Layout.fillWidth: true model: screensModel textRole: "name" iconRole: "icon" Component.onCompleted: screenRow.updateScreens(); onActivated: { var succeed = false; if (index === 0) { succeed = latteView.positioner.setCurrentScreen("primary"); if (succeed) { latteView.onPrimary = true; } else if (!latteView.onPrimary){ console.log("the edge is already occupied!!!"); currentIndex = findScreen(latteView.positioner.currentScreenName); } } else if (index>0 && (index !== findScreen(latteView.positioner.currentScreenName) || latteView.onPrimary)) { console.log("current index changed!!! :"+ index); console.log("screen must be changed..."); succeed = latteView.positioner.setCurrentScreen(textAt(index)); if(succeed) { latteView.onPrimary = false; } else { console.log("the edge is already occupied!!!"); currentIndex = findScreen(latteView.positioner.currentScreenName); } } } function findScreen(scrName) { for(var i=0; i=0); topEdgeBtn.edgeIsFree = (edges.indexOf(topEdgeBtn.edge)>=0); leftEdgeBtn.edgeIsFree = (edges.indexOf(leftEdgeBtn.edge)>=0); rightEdgeBtn.edgeIsFree = (edges.indexOf(rightEdgeBtn.edge)>=0); } PlasmaComponents.Button { id: bottomEdgeBtn Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18nc("bottom location", "Bottom") iconSource: "arrow-down" checked: latteView.location === edge checkable: true enabled: checked || edgeIsFree exclusiveGroup: locationGroup property bool edgeIsFree: true readonly property int edge: PlasmaCore.Types.BottomEdge } PlasmaComponents.Button { id: leftEdgeBtn Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18nc("left location", "Left") iconSource: "arrow-left" checked: latteView.location === edge checkable: true enabled: checked || edgeIsFree exclusiveGroup: locationGroup property bool edgeIsFree: true readonly property int edge: PlasmaCore.Types.LeftEdge } PlasmaComponents.Button { id: topEdgeBtn Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18nc("top location", "Top") iconSource: "arrow-up" checked: latteView.location === edge checkable: true enabled: checked || edgeIsFree exclusiveGroup: locationGroup property bool edgeIsFree: true readonly property int edge: PlasmaCore.Types.TopEdge } PlasmaComponents.Button { id: rightEdgeBtn Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18nc("right location", "Right") iconSource: "arrow-right" checked: latteView.location === edge checkable: true enabled: checked || edgeIsFree exclusiveGroup: locationGroup property bool edgeIsFree: true readonly property int edge: PlasmaCore.Types.RightEdge } } } //! END: Location //! BEGIN: Alignment ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing LatteComponents.Header { text: i18n("Alignment") } RowLayout { id: alignmentRow Layout.fillWidth: true Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 LayoutMirroring.enabled: false spacing: 2 readonly property int panelPosition: plasmoid.configuration.panelPosition readonly property int buttonSize: (dialog.optionsWidth - (spacing * 3)) / 4 ExclusiveGroup { id: alignmentGroup onCurrentChanged: { if (current.checked) plasmoid.configuration.panelPosition = current.position } } PlasmaComponents.Button { Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: panelIsVertical ? i18nc("top alignment", "Top") : i18nc("left alignment", "Left") iconSource: panelIsVertical ? "format-align-vertical-top" : "format-justify-left" checked: parent.panelPosition === position checkable: true exclusiveGroup: alignmentGroup property int position: panelIsVertical ? Latte.Types.Top : Latte.Types.Left } PlasmaComponents.Button { Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18nc("center alignment", "Center") iconSource: panelIsVertical ? "format-align-vertical-center" : "format-justify-center" checked: parent.panelPosition === position checkable: true exclusiveGroup: alignmentGroup property int position: Latte.Types.Center } PlasmaComponents.Button { Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: panelIsVertical ? i18nc("bottom alignment", "Bottom") : i18nc("right alignment", "Right") iconSource: panelIsVertical ? "format-align-vertical-bottom" : "format-justify-right" checked: parent.panelPosition === position checkable: true exclusiveGroup: alignmentGroup property int position: panelIsVertical ? Latte.Types.Bottom : Latte.Types.Right } PlasmaComponents.Button { Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18nc("justify alignment", "Justify") iconSource: "format-justify-fill" checked: parent.panelPosition === position checkable: true exclusiveGroup: alignmentGroup property int position: Latte.Types.Justify } } } //! END: Alignment //! BEGIN: Visibility ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing LatteComponents.Header { text: i18n("Visibility") } GridLayout { width: parent.width rowSpacing: 1 columnSpacing: 2 Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 columns: 2 property int mode: latteView.visibility.mode readonly property int buttonSize: (dialog.optionsWidth - (columnSpacing)) / 2 ExclusiveGroup { id: visibilityGroup onCurrentChanged: { if (current.checked) latteView.visibility.mode = current.mode } } PlasmaComponents.Button { Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18n("Always Visible") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.AlwaysVisible } PlasmaComponents.Button { Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18n("Auto Hide") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.AutoHide } PlasmaComponents.Button { Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18n("Dodge Active") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.DodgeActive } PlasmaComponents.Button { Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18n("Dodge Maximized") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.DodgeMaximized } PlasmaComponents.Button { id: dodgeAllWindowsBtn Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18n("Dodge All Windows") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.DodgeAllWindows } PlasmaComponents.Button { id: windowsGoBelowBtn Layout.minimumWidth: parent.buttonSize Layout.maximumWidth: Layout.minimumWidth text: i18n("Windows Go Below") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.WindowsGoBelow } } } //! END: Visibility //! BEGIN: Delay ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing enabled: !(latteView.visibility.mode === Latte.Types.AlwaysVisible || latteView.visibility.mode === Latte.Types.WindowsGoBelow) LatteComponents.Header { text: i18n("Delay") } Flow { width: dialog.optionsWidth Layout.minimumWidth: dialog.optionsWidth Layout.maximumWidth: dialog.optionsWidth Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 Layout.topMargin: units.smallSpacing spacing: 2 readonly property bool overlap: showContainer.overlap || hideContainer.overlap Item { id: showContainer width: parent.overlap ? dialog.optionsWidth : oneLineWidth height: childrenRect.height implicitWidth: width implicitHeight: height readonly property bool overlap: oneLineWidth > dodgeAllWindowsBtn.width readonly property int oneLineWidth: Math.max(dodgeAllWindowsBtn.width, showTimerRow.width) RowLayout{ id: showTimerRow anchors.horizontalCenter: parent.horizontalCenter PlasmaComponents.Label { Layout.leftMargin: Qt.application.layoutDirection === Qt.RightToLeft ? units.smallSpacing : 0 Layout.rightMargin: Qt.application.layoutDirection === Qt.RightToLeft ? 0 : units.smallSpacing text: i18n("Show ") } LatteComponents.TextField { Layout.preferredWidth: width text: latteView.visibility.timerShow onValueChanged: { latteView.visibility.timerShow = value } } } } Item { id: hideContainer width: parent.overlap ? dialog.optionsWidth : oneLineWidth height: childrenRect.height implicitWidth: width implicitHeight: height readonly property bool overlap: oneLineWidth > windowsGoBelowBtn.width readonly property int oneLineWidth: Math.max(windowsGoBelowBtn.width, hideTimerRow.width) RowLayout { id: hideTimerRow anchors.horizontalCenter: parent.horizontalCenter PlasmaComponents.Label { Layout.leftMargin: Qt.application.layoutDirection === Qt.RightToLeft ? units.smallSpacing : 0 Layout.rightMargin: Qt.application.layoutDirection === Qt.RightToLeft ? 0 : units.smallSpacing text: i18n("Hide") } LatteComponents.TextField{ Layout.preferredWidth: width text: latteView.visibility.timerHide onValueChanged: { latteView.visibility.timerHide = value } } } } } } //! END: Delay //! BEGIN: Actions ColumnLayout { spacing: units.smallSpacing visible: dialog.expertLevel LatteComponents.Header { text: i18n("Actions") } ColumnLayout { Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 spacing: 0 LatteComponents.SubHeader { text: i18n("Empty Area") } ColumnLayout { RowLayout { Layout.topMargin: units.smallSpacing PlasmaComponents.Label { id: mouseWheelLbl text: i18n("Mouse wheel") } LatteComponents.ComboBox { id: scrollAction Layout.fillWidth: true model: [i18nc("none scroll actions", "None Action"), i18n("Cycle Through Desktops"), i18n("Cycle Through Activities"), i18n("Cycle Through Tasks")] currentIndex: plasmoid.configuration.scrollAction onCurrentIndexChanged: { switch(currentIndex) { case Latte.Types.ScrollNone: plasmoid.configuration.scrollAction = Latte.Types.ScrollNone; break; case Latte.Types.ScrollDesktops: plasmoid.configuration.scrollAction = Latte.Types.ScrollDesktops; break; case Latte.Types.ScrollActivities: plasmoid.configuration.scrollAction = Latte.Types.ScrollActivities; break; case Latte.Types.ScrollTasks: plasmoid.configuration.scrollAction = Latte.Types.ScrollTasks; break; } } } } } LatteComponents.SubHeader { text: i18n("Active Window") } ColumnLayout { RowLayout { Layout.topMargin: units.smallSpacing PlasmaComponents.Label { Layout.minimumWidth: mouseWheelLbl.width Layout.maximumWidth: mouseWheelLbl.width text: i18n("Track From") } LatteComponents.ComboBox { id: activeWindowFilterCmb Layout.fillWidth: true model: [i18nc("track from current screen", "Current Screen"), i18nc("track from all screens", "All Screens")] currentIndex: plasmoid.configuration.activeWindowFilter onCurrentIndexChanged: { switch(currentIndex) { case Latte.Types.ActiveInCurrentScreen: plasmoid.configuration.activeWindowFilter = Latte.Types.ActiveInCurrentScreen; break; case Latte.Types.ActiveFromAllScreens: plasmoid.configuration.activeWindowFilter = Latte.Types.ActiveFromAllScreens; break; } } } } LatteComponents.CheckBox { Layout.maximumWidth: dialog.optionsWidth Layout.topMargin: units.smallSpacing text: i18n("Drag and maximize/restore active window") checked: plasmoid.configuration.dragActiveWindowEnabled tooltip: i18n("Drag/Maximize/Restore active window with double-click and dragging actions") visible: dialog.highLevel onClicked: { plasmoid.configuration.dragActiveWindowEnabled = !plasmoid.configuration.dragActiveWindowEnabled; } } } LatteComponents.SubHeader { text: i18n("Items") } LatteComponents.CheckBoxesColumn { LatteComponents.CheckBox { id: titleTooltipsChk Layout.maximumWidth: dialog.optionsWidth text: i18n("Show title tooltips on hovering") tooltip: i18n("Show thinner tooltips produced by Latte for items.\nThese tooltips are not drawn when applets zoom effect is disabled"); checked: plasmoid.configuration.titleTooltips enabled: plasmoid.configuration.zoomLevel > 0 onClicked: { plasmoid.configuration.titleTooltips = !plasmoid.configuration.titleTooltips; } } LatteComponents.CheckBox { id: mouseWheelChk Layout.maximumWidth: dialog.optionsWidth text: i18n("Activate through mouse wheel") checked: plasmoid.configuration.mouseWheelActions tooltip: i18n("Enable/Disable the mouse wheel action") visible: dialog.highLevel onClicked: { plasmoid.configuration.mouseWheelActions = checked } } LatteComponents.CheckBox { Layout.maximumWidth: dialog.optionsWidth // Layout.maximumHeight: mouseWheelChk.height text: i18n("🅰 Activate based on position through global shortcuts") checked: latteView.isPreferredForShortcuts || (!latteView.layout.preferredForShortcutsTouched && latteView.isHighestPriorityView()) tooltip: i18n("This view is used for based on position global shortcuts. Take note that only one view can have that option enabled for each layout") onClicked: { latteView.isPreferredForShortcuts = checked if (!latteView.layout.preferredForShortcutsTouched) { latteView.layout.preferredForShortcutsTouched = true } } } } } } //! END: Actions //! BEGIN: Adjust ColumnLayout { spacing: units.smallSpacing visible: dialog.expertLevel enabled: latteView.visibility.mode !== Latte.Types.AlwaysVisible && latteView.visibility.mode !== Latte.Types.WindowsGoBelow LatteComponents.Header { text: i18n("Environment") } LatteComponents.CheckBoxesColumn { Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 LatteComponents.CheckBox { Layout.maximumWidth: dialog.optionsWidth text: i18n("Activate KWin edge after hiding") checked: latteView.visibility.enableKWinEdges tooltip: i18n("After the view becomes hidden, KWin is informed to track user feedback. For example an edge visual hint is shown whenever the mouse approaches the hidden view") + enabled: !latteView.byPassWM onClicked: { latteView.visibility.enableKWinEdges = checked; } } LatteComponents.CheckBox { Layout.maximumWidth: dialog.optionsWidth text: i18n("Can be above fullscreen windows") checked: latteView.byPassWM tooltip: i18n("BypassWindowManagerHint flag for the window. The view will be above all windows even those set as 'Always On Top'") onCheckedChanged: { latteView.byPassWM = checked; } } LatteComponents.CheckBox { Layout.maximumWidth: dialog.optionsWidth text: i18n("Raise on desktop change") checked: latteView.visibility.raiseOnDesktop onClicked: { latteView.visibility.raiseOnDesktop = checked } } LatteComponents.CheckBox { Layout.maximumWidth: dialog.optionsWidth text: i18n("Raise on activity change") checked: latteView.visibility.raiseOnActivity onClicked: { latteView.visibility.raiseOnActivity = checked } } } } //! END: Adjust //! Bottom spacer PlasmaComponents.Label{ id: bottomMarginSpacer text:" " } } }