dde-dock/frame/display/displaymanager.cpp

368 lines
12 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2018 ~ 2020 Uniontech Technology Co., Ltd.
*
* Author: fanpengcheng <fanpengcheng@uniontech.com>
*
* Maintainer: fanpengcheng <fanpengcheng@uniontech.com>
*
* This program 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 3 of the License, or
* any later version.
*
* This program 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 "displaymanager.h"
#include "utils.h"
#include <QScreen>
#include <QApplication>
#include <QDBusConnection>
#include <QDesktopWidget>
DisplayManager::DisplayManager(QObject *parent)
: QObject(parent)
, m_gsettings(Utils::SettingsPtr("com.deepin.dde.dock.mainwindow", "/com/deepin/dde/dock/mainwindow/", this))
, m_onlyInPrimary(Utils::SettingValue("com.deepin.dde.dock.mainwindow", "/com/deepin/dde/dock/mainwindow/", "onlyShowPrimary", false).toBool())
{
connect(qApp, &QApplication::primaryScreenChanged, this, &DisplayManager::primaryScreenChanged);
connect(qApp, &QGuiApplication::screenAdded, this, &DisplayManager::screenCountChanged);
connect(qApp, &QGuiApplication::screenRemoved, this, &DisplayManager::screenCountChanged);
if (m_gsettings)
connect(m_gsettings, &QGSettings::changed, this, &DisplayManager::onGSettingsChanged);
screenCountChanged();
QTimer::singleShot(0, this, &DisplayManager::screenInfoChanged);
}
/**
* @brief DisplayManager::screens
* @return QScreen指针列表
*/
QList<QScreen *> DisplayManager::screens() const
{
return m_screens;
}
/**
* @brief DisplayManager::screen
* @param screenName
* @return screenName参数找到对应的QScreen指针返回nullptr
*/
QScreen *DisplayManager::screen(const QString &screenName) const
{
for (auto s : m_screens) {
if (s->name() == screenName)
return s;
}
return nullptr;
}
/**
* @brief DisplayManager::primary
* @return
*/
QString DisplayManager::primary() const
{
return qApp->primaryScreen() ? qApp->primaryScreen()->name() : QString();
}
/**
* @brief Display::screenWidth
* @return
*/
int DisplayManager::screenRawWidth() const
{
int width = 0;
for (auto s : m_screens) {
width = qMax(width, s->geometry().x() + int(s->geometry().width() * s->devicePixelRatio()));
}
return width;
}
/**
* @brief Display::screenHeight
* @return
*/
int DisplayManager::screenRawHeight() const
{
int height = 0;
for (auto s : m_screens) {
height = qMax(height, s->geometry().y() + int(s->geometry().height() * s->devicePixelRatio()));
}
return height;
}
/**
* @brief DisplayManager::canDock
* @param s QScreen指针
* @param pos
* @return s屏幕上pos位置任务栏位置是否允许停靠
*/
bool DisplayManager::canDock(QScreen *s, Position pos) const
{
return s ? m_screenPositionMap[s].value(pos) : false;
}
/**
* @brief DisplayManager::updateScreenDockInfo
*
*/
void DisplayManager::updateScreenDockInfo()
{
// TODO 目前仅仅支持双屏,如果超过双屏,会出现异常,这里可以考虑做成通用的处理规则
// 先清除原先的数据,然后再更新
m_screenPositionMap.clear();
if (m_screens.isEmpty())
return;
// reset map
for (auto s : m_screens) {
QMap <Position, bool> map;
map.insert(Position::Top, true);
map.insert(Position::Bottom, true);
map.insert(Position::Left, true);
map.insert(Position::Right, true);
m_screenPositionMap.insert(s, map);
}
// 仅显示在主屏时的处理
if (m_onlyInPrimary) {
for (auto s : m_screens) {
if (s != qApp->primaryScreen()) {
QMap <Position, bool> map;
map.insert(Position::Top, false);
map.insert(Position::Bottom, false);
map.insert(Position::Left, false);
map.insert(Position::Right, false);
m_screenPositionMap.insert(s, map);
}
}
return;
}
if (m_screens.size() == 1) {
return;
}
// 最多支持双屏,这里只计算双屏,单屏默认四边均可停靠任务栏
if (m_screens.size() == 2) {
QRect s0 = m_screens.at(0)->geometry();
s0.setSize(s0.size() * m_screens.at(0)->devicePixelRatio());
QRect s1 = m_screens.at(1)->geometry();
s1.setSize(s1.size() * m_screens.at(1)->devicePixelRatio());
qInfo() << "monitor info changed" << m_screens.at(0)->name() << s0 << m_screens.at(1)->name() << s1;
int s0top = s0.y();
int s0bottom = s0.y() + s0.height();
int s0left = s0.x();
int s0Right = s0.x() + s0.width();
int s1top = s1.y();
int s1bottom = s1.y() + s1.height();
int s1left = s1.x();
int s1Right = s1.x() + s1.width();
QPoint s0topLeft = QPoint(s0.x(), s0.y());
QPoint s0topRight = QPoint(s0.x()+ s0.width(), s0.y());
QPoint s0bottomRight = QPoint(s0.x()+ s0.width(), s0.y() + s0.height());
QPoint s0bottomLeft = QPoint(s0.x(), s0.y() + s0.height());
QPoint s1topLeft = QPoint(s1.x(), s1.y());
QPoint s1topRight = QPoint(s1.x() + s1.width(), s1.y());
QPoint s1bottomRight = QPoint(s1.x() + s1.width(), s1.y() + s1.height());
QPoint s1bottomLeft = QPoint(s1.x(), s1.y() + s1.height());
/*
*
--------- ---------
| | | |
| s0 | | s1 |
| | | |
----------------- -----------------
| | | |
| s1 | s0 |
| | | |
--------- ---------
*/
if (s0bottomRight == s1topLeft
|| s0topLeft == s1bottomRight) {
return;
}
/*
* s0左s1右
--------------------- -------------
| | | | |
| | s1 | | |--------
| s0 | | | s0 | |
| |-------- | | s1 |
| | | | |
------------- ---------------------
*/
if (s0Right == s1left
&& (s0topRight == s1topLeft || s0bottomRight == s1bottomLeft)) {
m_screenPositionMap[m_screens.at(0)].insert(Position::Right, false);
m_screenPositionMap[m_screens.at(1)].insert(Position::Left, false);
return;
}
/*
* s1左s0右
--------------------- -------------
| | | | |
| | s0 | | |--------
| s1 | | | s1 | |
| |-------- | | s0 |
| | | | |
------------- ---------------------
*/
if (s0left== s1Right
&& (s0topLeft == s1topRight || s0bottomLeft == s1bottomRight)) {
m_screenPositionMap[m_screens.at(0)].insert(Position::Left, false);
m_screenPositionMap[m_screens.at(1)].insert(Position::Right, false);
return;
}
/*
* s0上s1下
--------- ---------
| | | |
| s0 | | s0 |
| | | |
------------- -------------
| | | |
| | | |
| s1 | | s1 |
| | | |
| | | |
------------- -------------
*/
if (s0bottom == s1top
&& (s0bottomLeft == s1topLeft || s0bottomRight == s1topRight)) {
m_screenPositionMap[m_screens.at(0)].insert(Position::Bottom, false);
m_screenPositionMap[m_screens.at(1)].insert(Position::Top, false);
return;
}
/*
* s1上s0下
--------- ---------
| | | |
| s1 | | s1 |
| | | |
------------- -------------
| | | |
| | | |
| s0 | | s0 |
| | | |
| | | |
------------- -------------
*/
if (s0top == s1bottom
&& (s0topLeft == s1bottomLeft || s0topRight == s1bottomRight)) {
m_screenPositionMap[m_screens.at(0)].insert(Position::Top, false);
m_screenPositionMap[m_screens.at(1)].insert(Position::Bottom, false);
return;
}
return;
}
// 目前不支持链接超过两个以上的显示器
Q_UNREACHABLE();
}
/**
* @brief DisplayManager::screenCountChanged
*
* @note
*/
void DisplayManager::screenCountChanged()
{
// 找到过期的screen指针
QList<QScreen *> to_remove_list;
for (auto s : m_screens) {
if (!qApp->screens().contains(s))
to_remove_list.append(s);
}
// 找出新增的screen指针
QList<QScreen *> to_add_list;
for (auto s : qApp->screens()) {
if (!m_screens.contains(s)) {
to_add_list.append(s);
}
}
// 取消关联
for (auto s : to_remove_list) {
disconnect(s);
m_screens.removeOne(s);
}
// 创建关联
for (auto s : to_add_list) {
s->setOrientationUpdateMask(Qt::PrimaryOrientation
| Qt::LandscapeOrientation
| Qt::PortraitOrientation
| Qt::InvertedLandscapeOrientation
| Qt::InvertedPortraitOrientation);
// 显示器信息发生任何变化时,都应该重新刷新一次任务栏的显示位置
connect(s, &QScreen::geometryChanged, this, &DisplayManager::dockInfoChanged);
connect(s, &QScreen::availableGeometryChanged, this, &DisplayManager::dockInfoChanged);
connect(s, &QScreen::physicalSizeChanged, this, &DisplayManager::dockInfoChanged);
connect(s, &QScreen::physicalDotsPerInchChanged, this, &DisplayManager::dockInfoChanged);
connect(s, &QScreen::logicalDotsPerInchChanged, this, &DisplayManager::dockInfoChanged);
connect(s, &QScreen::virtualGeometryChanged, this, &DisplayManager::dockInfoChanged);
connect(s, &QScreen::primaryOrientationChanged, this, &DisplayManager::dockInfoChanged);
connect(s, &QScreen::orientationChanged, this, &DisplayManager::dockInfoChanged);
connect(s, &QScreen::refreshRateChanged, this, &DisplayManager::dockInfoChanged);
m_screens.append(s);
}
// 屏幕数量发生变化,应该刷新一下任务栏的显示
dockInfoChanged();
}
void DisplayManager::dockInfoChanged()
{
updateScreenDockInfo();
#ifdef QT_DEBUG
qInfo() << m_screenPositionMap;
#endif
Q_EMIT screenInfoChanged();
}
/**
* @brief DisplayManager::onGSettingsChanged
* @param key
* onlyShowPrimary配置的变化
*/
void DisplayManager::onGSettingsChanged(const QString &key)
{
if (key == "onlyShowPrimary") {
m_onlyInPrimary = Utils::SettingValue("com.deepin.dde.dock.mainwindow", "/com/deepin/dde/dock/mainwindow/", "onlyShowPrimary", false).toBool();
dockInfoChanged();
}
}