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

590 lines
15 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"
#include "visibilitymanager_p.h"
#include "windowinfowrap.h"
2016-12-31 00:27:39 +03:00
#include "dockview.h"
#include "dockcorona.h"
#include "../liblattedock/extras.h"
#include <QDebug>
2016-12-31 03:26:48 +03:00
namespace Latte {
//! BEGIN: VisiblityManagerPrivate implementation
VisibilityManagerPrivate::VisibilityManagerPrivate(PlasmaQuick::ContainmentView *view, VisibilityManager *q)
2017-03-13 04:52:31 +03:00
: QObject(nullptr), q(q), view(view), wm(&WindowSystem::self())
{
2016-12-31 00:27:39 +03:00
DockView *dockView = qobject_cast<DockView *>(view);
2017-01-16 22:07:49 +03:00
if (dockView) {
2016-12-31 00:27:39 +03:00
connect(dockView, &DockView::eventTriggered, this, &VisibilityManagerPrivate::event);
2017-02-11 06:12:17 +03:00
connect(dockView, &DockView::absGeometryChanged, this, &VisibilityManagerPrivate::setDockGeometry);
}
2017-01-16 22:07:49 +03:00
timerCheckWindows.setInterval(350);
timerCheckWindows.setSingleShot(true);
timerShow.setSingleShot(true);
timerHide.setSingleShot(true);
connect(&timerCheckWindows, &QTimer::timeout, this, &VisibilityManagerPrivate::checkAllWindows);
connect(&timerShow, &QTimer::timeout, this, [this]() {
if (isHidden) {
2017-01-28 20:34:03 +03:00
// qDebug() << "must be shown";
emit this->q->mustBeShown(VisibilityManager::QPrivateSignal{});
}
});
connect(&timerHide, &QTimer::timeout, this, [this]() {
if (!blockHiding && !isHidden && !dragEnter) {
2017-01-28 20:34:03 +03:00
// qDebug() << "must be hide";
emit this->q->mustBeHide(VisibilityManager::QPrivateSignal{});
}
});
wm->setDockExtraFlags(*view);
wm->addDock(view->winId());
2017-02-27 02:43:48 +03:00
restoreConfig();
}
VisibilityManagerPrivate::~VisibilityManagerPrivate()
{
2017-03-13 04:52:31 +03:00
qDebug() << "VisibilityManagerPrivate deleting...";
wm->removeDockStruts(view->winId());
wm->removeDock(view->winId());
}
inline void VisibilityManagerPrivate::setMode(Dock::Visibility mode)
{
if (this->mode == mode)
return;
2017-01-16 22:07:49 +03:00
2017-02-27 02:43:48 +03:00
Q_ASSERT_X(mode != Dock::None, q->staticMetaObject.className(), "set visibility to Dock::None");
// clear mode
for (auto &c : connections) {
disconnect(c);
}
2017-01-16 22:07:49 +03:00
if (this->mode == Dock::AlwaysVisible) {
wm->removeDockStruts(view->winId());
} else {
connections[3] = connect(wm, &WindowSystem::currentDesktopChanged
2017-03-12 23:14:30 +03:00
, this, [&] {
if (raiseOnDesktopChange)
raiseDockTemporarily();
});
connections[4] = connect(wm, &WindowSystem::currentActivityChanged
2017-03-12 23:14:30 +03:00
, this, [&]() {
if (raiseOnActivityChange)
raiseDockTemporarily();
else
updateHiddenState();
});
}
timerShow.stop();
timerHide.stop();
timerCheckWindows.stop();
this->mode = mode;
2017-01-16 22:07:49 +03:00
switch (this->mode) {
2016-12-30 10:24:04 +03:00
case Dock::AlwaysVisible: {
if (view->containment() && !view->containment()->isUserConfiguring())
wm->setDockStruts(view->winId(), dockGeometry, view->location());
2017-01-16 22:07:49 +03:00
connections[0] = connect(view->containment(), &Plasma::Containment::locationChanged
2017-01-16 21:24:46 +03:00
, this, [&]() {
if (view->containment()->isUserConfiguring())
wm->removeDockStruts(view->winId());
});
connections[1] = connect(view->containment(), &Plasma::Containment::userConfiguringChanged
2017-01-16 21:24:46 +03:00
, this, [&](bool configuring) {
if (!configuring)
wm->setDockStruts(view->winId(), dockGeometry, view->containment()->location());
});
2016-12-30 10:24:04 +03:00
raiseDock(true);
}
break;
2017-01-16 22:07:49 +03:00
2016-12-30 10:24:04 +03:00
case Dock::AutoHide: {
raiseDock(containsMouse);
2016-12-30 10:24:04 +03:00
}
break;
2017-01-16 22:07:49 +03:00
2016-12-30 10:24:04 +03:00
case Dock::DodgeActive: {
connections[0] = connect(wm, &WindowSystem::activeWindowChanged
2016-12-30 10:24:04 +03:00
, this, &VisibilityManagerPrivate::dodgeActive);
connections[1] = connect(wm, &WindowSystem::windowChanged
2016-12-30 10:24:04 +03:00
, this, &VisibilityManagerPrivate::dodgeActive);
dodgeActive(wm->activeWindow());
}
2016-12-30 10:24:04 +03:00
break;
2017-01-16 22:07:49 +03:00
2016-12-30 10:24:04 +03:00
case Dock::DodgeMaximized: {
connections[0] = connect(wm, &WindowSystem::activeWindowChanged
2016-12-30 10:24:04 +03:00
, this, &VisibilityManagerPrivate::dodgeMaximized);
connections[1] = connect(wm, &WindowSystem::windowChanged
2017-03-12 23:14:30 +03:00
, this, &VisibilityManagerPrivate::dodgeMaximized);
dodgeMaximized(wm->activeWindow());
2016-12-30 10:24:04 +03:00
}
break;
2017-01-16 22:07:49 +03:00
2016-12-30 10:24:04 +03:00
case Dock::DodgeAllWindows: {
for (const auto &wid : wm->windows()) {
windows.insert({wid, wm->requestInfo(wid)});
}
2017-01-16 22:07:49 +03:00
connections[0] = connect(wm, &WindowSystem::windowChanged
2016-12-30 10:24:04 +03:00
, this, &VisibilityManagerPrivate::dodgeWindows);
connections[1] = connect(wm, &WindowSystem::windowRemoved
2016-12-30 10:24:04 +03:00
, this, [&](WId wid) {
windows.erase(wid);
timerCheckWindows.start();
2016-12-30 10:24:04 +03:00
});
connections[2] = connect(wm, &WindowSystem::windowAdded
2016-12-30 10:24:04 +03:00
, this, [&](WId wid) {
windows.insert({wid, wm->requestInfo(wid)});
timerCheckWindows.start();
2016-12-30 10:24:04 +03:00
});
timerCheckWindows.start();
2016-12-30 10:24:04 +03:00
}
break;
}
2017-01-16 22:07:49 +03:00
2016-12-30 22:03:46 +03:00
emit q->modeChanged();
}
void VisibilityManagerPrivate::setRaiseOnDesktop(bool enable)
{
if (enable == raiseOnDesktopChange)
return;
raiseOnDesktopChange = enable;
emit q->raiseOnDesktopChanged();
}
void VisibilityManagerPrivate::setRaiseOnActivity(bool enable)
{
if (enable == raiseOnActivityChange)
return;
raiseOnActivityChange = enable;
emit q->raiseOnActivityChanged();
}
inline void VisibilityManagerPrivate::setIsHidden(bool isHidden)
{
if (this->isHidden == isHidden)
return;
2017-01-16 22:07:49 +03:00
if (blockHiding) {
qWarning() << "isHidden property is blocked, ignoring update";
return;
}
2017-01-16 22:07:49 +03:00
this->isHidden = isHidden;
emit q->isHiddenChanged();
}
void VisibilityManagerPrivate::setBlockHiding(bool blockHiding)
{
if (this->blockHiding == blockHiding)
return;
2017-01-16 22:07:49 +03:00
this->blockHiding = blockHiding;
2017-01-28 20:34:03 +03:00
// qDebug() << "blockHiding:" << blockHiding;
2017-01-16 22:07:49 +03:00
if (this->blockHiding) {
timerHide.stop();
2017-01-16 22:07:49 +03:00
if (isHidden) {
isHidden = false;
emit q->isHiddenChanged();
emit q->mustBeShown(VisibilityManager::QPrivateSignal{});
}
} else {
updateHiddenState();
}
2017-01-16 22:07:49 +03:00
emit q->blockHidingChanged();
}
inline void VisibilityManagerPrivate::setTimerShow(int msec)
{
timerShow.setInterval(msec);
emit q->timerShowChanged();
}
inline void VisibilityManagerPrivate::setTimerHide(int msec)
{
timerHide.setInterval(msec);
emit q->timerHideChanged();
}
inline void VisibilityManagerPrivate::raiseDock(bool raise)
{
if (blockHiding)
return;
if (raise) {
timerHide.stop();
2017-01-16 22:07:49 +03:00
if (!timerShow.isActive()) {
timerShow.start();
}
} else if (!dragEnter) {
timerShow.stop();
2017-01-16 22:07:49 +03:00
if (hideNow) {
hideNow = false;
emit q->mustBeHide(VisibilityManager::QPrivateSignal{});
} else if (!timerHide.isActive())
timerHide.start();
}
}
void VisibilityManagerPrivate::raiseDockTemporarily()
{
if (raiseTemporarily)
return;
raiseTemporarily = true;
timerHide.stop();
timerShow.stop();
if (isHidden)
emit q->mustBeShown(VisibilityManager::QPrivateSignal{});
QTimer::singleShot(qBound(1800, 2 * timerHide.interval(), 3000), this, [&]() {
raiseTemporarily = false;
hideNow = true;
updateHiddenState();
});
}
void VisibilityManagerPrivate::updateHiddenState()
{
if (dragEnter)
return;
2017-01-16 22:07:49 +03:00
switch (mode) {
case Dock::AutoHide:
raiseDock(containsMouse);
break;
2017-01-16 22:07:49 +03:00
case Dock::DodgeActive:
dodgeActive(wm->activeWindow());
break;
2017-01-16 22:07:49 +03:00
case Dock::DodgeMaximized:
dodgeMaximized(wm->activeWindow());
break;
2017-01-16 22:07:49 +03:00
case Dock::DodgeAllWindows:
dodgeWindows(wm->activeWindow());
break;
}
}
2017-02-11 06:12:17 +03:00
inline void VisibilityManagerPrivate::setDockGeometry(const QRect &geometry)
{
2017-02-11 06:12:17 +03:00
if (!view->containment() || this->dockGeometry == geometry)
return;
2017-01-16 22:07:49 +03:00
2017-02-11 06:12:17 +03:00
this->dockGeometry = geometry;
2017-01-16 22:07:49 +03:00
2017-01-14 01:01:30 +03:00
if (mode == Dock::AlwaysVisible && !view->containment()->isUserConfiguring()) {
wm->setDockStruts(view->winId(), this->dockGeometry, view->containment()->location());
}
}
void VisibilityManagerPrivate::dodgeActive(WId wid)
{
if (raiseTemporarily)
return;
auto winfo = wm->requestInfo(wid);
2017-01-16 22:07:49 +03:00
if (!winfo.isValid())
return;
2017-01-16 22:07:49 +03:00
if (!winfo.isActive()) {
if (winfo.isPlasmaDesktop())
raiseDock(true);
2017-01-16 22:07:49 +03:00
winfo = wm->requestInfo(wm->activeWindow());
}
2017-01-16 22:07:49 +03:00
if (wm->isOnCurrentDesktop(wid))
raiseDock(!intersects(winfo));
}
void VisibilityManagerPrivate::dodgeMaximized(WId wid)
{
if (raiseTemporarily)
return;
auto winfo = wm->requestInfo(wid);
2017-01-16 22:07:49 +03:00
if (!winfo.isValid())
return;
2017-01-16 22:07:49 +03:00
if (!winfo.isActive()) {
if (winfo.isPlasmaDesktop())
raiseDock(true);
2017-01-16 22:07:49 +03:00
winfo = wm->requestInfo(wm->activeWindow());
}
2017-01-16 22:07:49 +03:00
if (wm->isOnCurrentDesktop(wid) && !winfo.isMinimized())
raiseDock(!(view->formFactor() == Plasma::Types::Vertical
2017-03-12 23:14:30 +03:00
? winfo.isMaxHoriz() : winfo.isMaxVert()));
}
void VisibilityManagerPrivate::dodgeWindows(WId wid)
{
if (raiseTemporarily)
return;
if (windows.find(wid) == std::end(windows))
return;
2017-01-16 22:07:49 +03:00
auto winfo = wm->requestInfo(wid);
windows[wid] = winfo;
2017-01-16 22:07:49 +03:00
if (!winfo.isValid() || !wm->isOnCurrentDesktop(wid))
return;
2017-01-16 22:07:49 +03:00
if (intersects(winfo))
raiseDock(false);
else
timerCheckWindows.start();
}
void VisibilityManagerPrivate::checkAllWindows()
{
if (raiseTemporarily)
return;
bool raise{true};
2017-01-16 22:07:49 +03:00
for (const auto &winfo : windows) {
//! std::pair<WId, WindowInfoWrap>
if (!std::get<1>(winfo).isValid() || !wm->isOnCurrentDesktop(std::get<0>(winfo)))
continue;
2017-01-16 22:07:49 +03:00
if (std::get<1>(winfo).isFullscreen()) {
raise = false;
break;
} else if (intersects(std::get<1>(winfo))) {
raise = false;
break;
}
}
2017-01-16 22:07:49 +03:00
raiseDock(raise);
}
inline bool VisibilityManagerPrivate::intersects(const WindowInfoWrap &winfo)
{
2017-02-11 06:12:17 +03:00
return !winfo.isMinimized() && winfo.geometry().intersects(dockGeometry);
}
inline void VisibilityManagerPrivate::saveConfig()
{
if (!view->containment())
return;
2017-01-16 22:07:49 +03:00
auto config = view->containment()->config();
config.writeEntry("visibility", static_cast<int>(mode));
config.writeEntry("timerShow", timerShow.interval());
config.writeEntry("timerHide", timerHide.interval());
config.writeEntry("raiseOnDesktopChange", raiseOnDesktopChange);
config.writeEntry("raiseOnActivityChange", raiseOnActivityChange);
view->containment()->configNeedsSaving();
}
inline void VisibilityManagerPrivate::restoreConfig()
{
if (!view->containment())
2016-12-30 10:24:04 +03:00
return;
2017-01-16 22:07:49 +03:00
2016-12-30 10:24:04 +03:00
auto config = view->containment()->config();
2017-01-12 14:53:06 +03:00
timerShow.setInterval(config.readEntry("timerShow", 200));
timerHide.setInterval(config.readEntry("timerHide", 700));
2017-01-03 20:01:29 +03:00
auto mode = static_cast<Dock::Visibility>(config.readEntry("visibility", static_cast<int>(Dock::DodgeActive)));
2016-12-30 22:33:42 +03:00
emit q->timerShowChanged();
emit q->timerHideChanged();
if (mode == Dock::AlwaysVisible) {
2017-03-12 23:14:30 +03:00
setMode(mode);
} else {
2017-03-12 23:14:30 +03:00
QTimer::singleShot(5000, this, [ &, mode]() {
setMode(mode);
});
setRaiseOnDesktop(config.readEntry("raiseOnDesktopChange", false));
setRaiseOnActivity(config.readEntry("raiseOnActivityChange", false));
}
qDebug() << config.entryMap();
connect(view->containment(), &Plasma::Containment::userConfiguringChanged
2017-03-12 23:14:30 +03:00
, this, [&](bool configuring) {
2017-03-12 21:30:54 +03:00
if (!configuring)
saveConfig();
});
}
bool VisibilityManagerPrivate::event(QEvent *ev)
{
switch (ev->type()) {
case QEvent::Enter:
if (containsMouse)
break;
2017-01-16 22:07:49 +03:00
containsMouse = true;
emit q->containsMouseChanged();
2017-01-16 22:07:49 +03:00
if (mode != Dock::AlwaysVisible)
raiseDock(true);
2017-01-16 22:07:49 +03:00
break;
2017-01-16 22:07:49 +03:00
case QEvent::Leave:
if (!containsMouse)
break;
2017-01-16 22:07:49 +03:00
containsMouse = false;
emit q->containsMouseChanged();
updateHiddenState();
break;
2017-01-16 22:07:49 +03:00
case QEvent::DragEnter:
dragEnter = true;
2017-03-12 23:14:30 +03:00
if (isHidden)
emit q->mustBeShown(VisibilityManager::QPrivateSignal{});
break;
2017-01-16 22:07:49 +03:00
case QEvent::DragLeave:
case QEvent::Drop:
dragEnter = false;
updateHiddenState();
break;
2017-01-16 22:07:49 +03:00
case QEvent::Show:
wm->setDockExtraFlags(*view);
break;
}
2017-01-16 22:07:49 +03:00
}
2017-01-13 02:53:59 +03:00
//! END: VisibilityManagerPrivate implementation
//! BEGIN: VisiblityManager implementation
VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view)
: d(new VisibilityManagerPrivate(view, this))
{
}
VisibilityManager::~VisibilityManager()
{
qDebug() << "VisibilityManager deleting...";
delete d;
}
Dock::Visibility VisibilityManager::mode() const
{
return d->mode;
}
void VisibilityManager::setMode(Dock::Visibility mode)
{
d->setMode(mode);
}
bool VisibilityManager::raiseOnDesktop() const
{
return d->raiseOnDesktopChange;
}
void VisibilityManager::setRaiseOnDesktop(bool enable)
{
d->setRaiseOnDesktop(enable);
}
bool VisibilityManager::raiseOnActivity() const
{
return d->raiseOnActivityChange;
}
void VisibilityManager::setRaiseOnActivity(bool enable)
{
d->setRaiseOnActivity(enable);
}
bool VisibilityManager::isHidden() const
{
return d->isHidden;
}
void VisibilityManager::setIsHidden(bool isHidden)
{
d->setIsHidden(isHidden);
}
bool VisibilityManager::blockHiding() const
{
return d->blockHiding;
}
void VisibilityManager::setBlockHiding(bool blockHiding)
{
d->setBlockHiding(blockHiding);
}
bool VisibilityManager::containsMouse() const
{
return d->containsMouse;
}
int VisibilityManager::timerShow() const
{
return d->timerShow.interval();
}
void VisibilityManager::setTimerShow(int msec)
{
d->setTimerShow(msec);
}
int VisibilityManager::timerHide() const
{
return d->timerHide.interval();
}
void VisibilityManager::setTimerHide(int msec)
{
d->setTimerHide(msec);
}
//! END: VisibilityManager implementation
}