1
0
mirror of https://github.com/KDE/latte-dock.git synced 2025-01-10 21:18:19 +03:00
latte-dock/app/view/visibilitymanager.cpp

757 lines
20 KiB
C++
Raw Normal View History

2017-01-03 01:05:30 +03:00
/*
* Copyright 2016 Smith AR <audoban@openmailbox.org>
* Michail Vourlakos <mvourlakos@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "visibilitymanager.h"
2018-12-02 03:05:52 +03:00
// local
#include "positioner.h"
#include "screenedgeghostwindow.h"
#include "view.h"
#include "../lattecorona.h"
#include "../layoutmanager.h"
#include "../screenpool.h"
#include "../wm/windowinfowrap.h"
#include "../../liblatte2/extras.h"
2018-12-02 03:05:52 +03:00
// Qt
#include <QDebug>
// KDE
2019-04-12 19:08:00 +03:00
#include <KWindowSystem>
#include <KWayland/Client/plasmashell.h>
#include <KWayland/Client/surface.h>
namespace Latte {
namespace ViewPart {
//! BEGIN: VisiblityManager implementation
VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view)
: QObject(view)
{
qDebug() << "VisibilityManager creating...";
m_latteView = qobject_cast<Latte::View *>(view);
m_corona = qobject_cast<Latte::Corona *>(view->corona());
m_wm = m_corona->wm();
2017-01-16 22:07:49 +03:00
connect(this, &VisibilityManager::slideInFinished, this, &VisibilityManager::updateHiddenState);
if (m_latteView) {
connect(m_latteView, &Latte::View::eventTriggered, this, &VisibilityManager::viewEventManager);
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);
}
2017-01-16 22:07:49 +03:00
if (m_corona) {
2019-04-12 18:55:45 +03:00
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) {
2017-01-28 20:34:03 +03:00
// qDebug() << "must be shown";
emit mustBeShown();
}
});
connect(&m_timerHide, &QTimer::timeout, this, [&]() {
if (!m_blockHiding && !m_isHidden && !m_dragEnter) {
2017-01-28 20:34:03 +03:00
// qDebug() << "must be hide";
emit mustBeHide();
}
});
m_wm->setViewExtraFlags(*m_latteView);
m_wm->addView(m_latteView->winId());
2017-02-27 02:43:48 +03:00
restoreConfig();
}
VisibilityManager::~VisibilityManager()
{
qDebug() << "VisibilityManager deleting...";
m_wm->removeViewStruts(*m_latteView);
m_wm->removeView(m_latteView->winId());
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;
2017-01-16 22:07:49 +03:00
Q_ASSERT_X(mode != Types::None, staticMetaObject.className(), "set visibility to Types::None");
2017-02-27 02:43:48 +03:00
// clear mode
for (auto &c : m_connections) {
disconnect(c);
}
2017-01-16 22:07:49 +03:00
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::currentDesktopChanged, this, [&] {
if (m_raiseOnDesktopChange) {
2018-12-06 17:17:35 +03:00
raiseViewTemporarily();
}
});
m_connections[1] = connect(m_wm, &WindowSystem::currentActivityChanged, this, [&]() {
if (m_raiseOnActivityChange) {
2018-12-06 17:17:35 +03:00
raiseViewTemporarily();
} else {
2017-03-12 23:14:30 +03:00
updateHiddenState();
}
});
base = 2;
} else {
//set wayland visibility mode
if (m_latteView->surface()) {
m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide);
}
}
2017-01-16 22:07:49 +03:00
switch (m_mode) {
case Types::AlwaysVisible: {
if (m_latteView->containment() && m_latteView->screen()) {
updateStrutsBasedOnLayoutsAndActivities();
}
m_connections[base] = connect(m_corona->layoutManager(), &LayoutManager::currentLayoutNameChanged, this, [&]() {
if (m_corona && m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) {
updateStrutsBasedOnLayoutsAndActivities();
}
});
2017-01-16 22:07:49 +03:00
m_connections[base+1] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() {
if (m_corona && m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) {
updateStrutsBasedOnLayoutsAndActivities();
}
});
raiseView(true);
break;
}
2017-01-16 22:07:49 +03:00
case Types::AutoHide: {
m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged, this, [&]() {
raiseView(m_containsMouse);
});
raiseView(m_containsMouse);
break;
}
2017-01-16 22:07:49 +03:00
case Types::DodgeActive: {
m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged
, this, &VisibilityManager::dodgeActive);
m_connections[base+1] = connect(m_latteView->windowsTracker(), &WindowsTracker::activeWindowTouchingChanged
, this, &VisibilityManager::dodgeActive);
2019-04-23 09:58:06 +03:00
dodgeActive();
2016-12-30 10:24:04 +03:00
break;
}
2017-01-16 22:07:49 +03:00
case Types::DodgeMaximized: {
m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged
, this, &VisibilityManager::dodgeMaximized);
m_connections[base+1] = connect(m_latteView->windowsTracker(), &WindowsTracker::activeWindowMaximizedChanged
, this, &VisibilityManager::dodgeActive);
2019-04-23 09:58:06 +03:00
dodgeMaximized();
2016-12-30 10:24:04 +03:00
break;
}
2017-01-16 22:07:49 +03:00
case Types::DodgeAllWindows: {
m_connections[base] = connect(this, &VisibilityManager::containsMouseChanged
, this, &VisibilityManager::dodgeAllWindows);
2017-01-16 22:07:49 +03:00
m_connections[base+1] = connect(m_latteView->windowsTracker(), &WindowsTracker::existsWindowTouchingChanged
, this, &VisibilityManager::dodgeAllWindows);
break;
}
case Types::WindowsGoBelow:
break;
default:
break;
}
2017-01-16 22:07:49 +03:00
m_latteView->containment()->config().writeEntry("visibility", static_cast<int>(m_mode));
updateKWinEdgesSupport();
emit modeChanged();
}
void VisibilityManager::updateStrutsBasedOnLayoutsAndActivities()
{
bool multipleLayoutsAndCurrent = (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts
&& m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation()
2019-04-07 20:15:58 +03:00
&& m_latteView->managedLayout()->isCurrent());
if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || multipleLayoutsAndCurrent) {
2019-05-01 23:04:39 +03:00
QRect computedStruts = acceptableStruts();
if (m_publishedStruts != computedStruts) {
m_publishedStruts = computedStruts;
m_wm->setViewStruts(*m_latteView, m_publishedStruts, m_latteView->location());
}
} else {
m_publishedStruts = QRect();
m_wm->removeViewStruts(*m_latteView);
}
}
2019-05-01 23:04:39 +03:00
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;
2017-01-16 22:07:49 +03:00
if (m_blockHiding && isHidden) {
qWarning() << "isHidden property is blocked, ignoring update";
return;
}
2017-01-16 22:07:49 +03:00
m_isHidden = isHidden;
updateGhostWindowState();
emit isHiddenChanged();
}
bool VisibilityManager::blockHiding() const
{
return m_blockHiding;
}
void VisibilityManager::setBlockHiding(bool blockHiding)
{
if (m_blockHiding == blockHiding) {
return;
}
2017-01-16 22:07:49 +03:00
m_blockHiding = blockHiding;
2017-01-28 20:34:03 +03:00
// qDebug() << "blockHiding:" << blockHiding;
2017-01-16 22:07:49 +03:00
if (m_blockHiding) {
m_timerHide.stop();
2017-01-16 22:07:49 +03:00
if (m_isHidden) {
emit mustBeShown();
}
} else {
updateHiddenState();
}
2017-01-16 22:07:49 +03:00
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->layoutManager()->memoryUsage() == Types::SingleLayout ||
(m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts
&& m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation()
&& m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName()));
if (inCurrentLayout) {
m_wm->setEdgeStateFor(m_edgeGhostWindow, m_isHidden);
} else {
m_wm->setEdgeStateFor(m_edgeGhostWindow, false);
}
}
}
2019-04-12 19:08:00 +03:00
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();
2017-01-16 22:07:49 +03:00
if (!m_timerShow.isActive()) {
m_timerShow.start();
}
} else if (!m_dragEnter) {
m_timerShow.stop();
2017-01-16 22:07:49 +03:00
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;
2017-01-16 22:07:49 +03:00
switch (m_mode) {
case Types::AutoHide:
raiseView(m_containsMouse);
break;
2017-01-16 22:07:49 +03:00
case Types::DodgeActive:
dodgeActive();
break;
2017-01-16 22:07:49 +03:00
case Types::DodgeMaximized:
dodgeMaximized();
break;
2017-01-16 22:07:49 +03:00
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();
}
2019-04-23 09:58:06 +03:00
void VisibilityManager::dodgeActive()
{
if (m_raiseTemporarily)
return;
2018-12-06 17:17:35 +03:00
//!don't send false raiseView signal when containing mouse
if (m_containsMouse) {
2018-12-06 17:17:35 +03:00
raiseView(true);
return;
}
2019-04-23 09:58:06 +03:00
raiseView(!m_latteView->windowsTracker()->activeWindowTouching());
}
2019-04-23 09:58:06 +03:00
void VisibilityManager::dodgeMaximized()
{
if (m_raiseTemporarily)
return;
2018-12-06 17:17:35 +03:00
//!don't send false raiseView signal when containing mouse
if (m_containsMouse) {
2018-12-06 17:17:35 +03:00
raiseView(true);
return;
}
2019-04-23 09:58:06 +03:00
raiseView(!m_latteView->windowsTracker()->activeWindowMaximized());
}
void VisibilityManager::dodgeAllWindows()
{
if (m_raiseTemporarily)
return;
if (m_containsMouse) {
2018-12-06 17:17:35 +03:00
raiseView(true);
}
bool windowIntersects{m_latteView->windowsTracker()->activeWindowTouching() || m_latteView->windowsTracker()->existsWindowTouching()};
2017-01-16 22:07:49 +03:00
raiseView(!windowIntersects);
}
void VisibilityManager::saveConfig()
{
if (!m_latteView->containment())
return;
2017-01-16 22:07:49 +03:00
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()){
2016-12-30 10:24:04 +03:00
return;
}
2017-01-16 22:07:49 +03:00
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();
2017-03-26 00:17:41 +03:00
setRaiseOnDesktop(config.readEntry("raiseOnDesktopChange", false));
setRaiseOnActivity(config.readEntry("raiseOnActivityChange", false));
auto storedMode = static_cast<Types::Visibility>(m_latteView->containment()->config().readEntry("visibility", static_cast<int>(Types::DodgeActive)));
if (storedMode == Types::AlwaysVisible) {
qDebug() << "Loading visibility mode: Always Visible , on startup...";
setMode(Types::AlwaysVisible);
} else {
connect(&m_timerStartUp, &QTimer::timeout, this, [&]() {
auto fMode = static_cast<Types::Visibility>(m_latteView->containment()->config().readEntry("visibility", static_cast<int>(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) {
2017-03-12 21:30:54 +03:00
saveConfig();
}
});
}
bool VisibilityManager::containsMouse() const
{
return m_containsMouse;
}
void VisibilityManager::setContainsMouse(bool contains)
{
if (m_containsMouse == contains) {
return;
}
2017-01-16 22:07:49 +03:00
m_containsMouse = contains;
emit containsMouseChanged();
2017-01-16 22:07:49 +03:00
if (contains && m_mode != Types::AlwaysVisible) {
2018-12-06 17:17:35 +03:00
raiseView(true);
}
}
2017-01-16 22:07:49 +03:00
void VisibilityManager::viewEventManager(QEvent *ev)
{
switch (ev->type()) {
case QEvent::Enter:
setContainsMouse(true);
break;
2017-01-16 22:07:49 +03:00
case QEvent::Leave:
setContainsMouse(false);
break;
2017-01-16 22:07:49 +03:00
case QEvent::DragEnter:
m_dragEnter = true;
2017-03-12 23:14:30 +03:00
if (m_isHidden)
emit mustBeShown();
break;
2017-01-16 22:07:49 +03:00
case QEvent::DragLeave:
case QEvent::Drop:
m_dragEnter = false;
updateHiddenState();
break;
2017-01-16 22:07:49 +03:00
case QEvent::Show:
m_wm->setViewExtraFlags(*m_latteView);
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
|| m_mode == Types::DodgeActive
|| m_mode == Types::DodgeAllWindows
|| m_mode == Types::DodgeMaximized) {
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::currentActivityChanged,
this, [&]() {
bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout ||
(m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts
&& m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation()
&& m_latteView->managedLayout()->name() == m_corona->layoutManager()->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
}
}