2023-02-16 13:51:55 +08:00
|
|
|
|
// Copyright (C) 2018 ~ 2020 Uniontech Technology Co., Ltd.
|
|
|
|
|
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
2022-09-06 11:36:55 +08:00
|
|
|
|
//
|
|
|
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
2021-04-12 16:53:03 +08:00
|
|
|
|
|
|
|
|
|
#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);
|
2022-08-03 16:21:05 +08:00
|
|
|
|
connect(qApp, &QApplication::primaryScreenChanged, this, &DisplayManager::dockInfoChanged);
|
2021-04-13 23:46:49 +08:00
|
|
|
|
connect(qApp, &QGuiApplication::screenAdded, this, &DisplayManager::screenCountChanged);
|
|
|
|
|
connect(qApp, &QGuiApplication::screenRemoved, this, &DisplayManager::screenCountChanged);
|
2021-04-12 16:53:03 +08:00
|
|
|
|
|
|
|
|
|
if (m_gsettings)
|
|
|
|
|
connect(m_gsettings, &QGSettings::changed, this, &DisplayManager::onGSettingsChanged);
|
|
|
|
|
|
|
|
|
|
screenCountChanged();
|
2021-05-08 21:35:35 +08:00
|
|
|
|
|
|
|
|
|
QTimer::singleShot(0, this, &DisplayManager::screenInfoChanged);
|
2021-04-12 16:53:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-12 08:13:00 +00:00
|
|
|
|
QScreen *DisplayManager::screenAt(const QPoint &pos) const
|
|
|
|
|
{
|
|
|
|
|
for (QScreen *screen : m_screens) {
|
|
|
|
|
QRect screenGeometry = screen->geometry();
|
|
|
|
|
if (screenGeometry.contains(pos))
|
|
|
|
|
return screen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-12 16:53:03 +08:00
|
|
|
|
/**
|
|
|
|
|
* @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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-23 11:39:52 +08:00
|
|
|
|
/**判断屏幕是否为复制模式的依据,第一个屏幕的X和Y值是否和其他的屏幕的X和Y值相等
|
|
|
|
|
* 对于复制模式,这两个值肯定是相等的,如果不是复制模式,这两个值肯定不等,目前支持双屏
|
|
|
|
|
* @brief DisplayManager::isCopyMode
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
bool DisplayManager::isCopyMode()
|
|
|
|
|
{
|
|
|
|
|
QList<QScreen *> screens = this->screens();
|
|
|
|
|
if (screens.size() < 2)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// 在多个屏幕的情况下,如果所有屏幕的位置的X和Y值都相等,则认为是复制模式
|
|
|
|
|
QRect screenRect = screens[0]->availableGeometry();
|
|
|
|
|
for (int i = 1; i < screens.size(); i++) {
|
|
|
|
|
QRect rect = screens[i]->availableGeometry();
|
|
|
|
|
if (screenRect.x() != rect.x() || screenRect.y() != rect.y())
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-12 16:53:03 +08:00
|
|
|
|
/**
|
|
|
|
|
* @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) {
|
2022-08-03 16:21:05 +08:00
|
|
|
|
if (s != qApp->primaryScreen()) {
|
2021-04-12 16:53:03 +08:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-13 17:03:07 +08:00
|
|
|
|
return;
|
2021-04-12 16:53:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_screens.size() == 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-26 15:02:18 +08:00
|
|
|
|
// 适配多个屏幕的情况
|
|
|
|
|
for(auto s : m_screens) {
|
|
|
|
|
QList<QScreen *> otherScreens = m_screens;
|
|
|
|
|
otherScreens.removeAll(s);
|
|
|
|
|
for (auto other : otherScreens) {
|
|
|
|
|
QRect ourRect = QRect(s->geometry().topLeft(), s->geometry().size() * s->devicePixelRatio());
|
|
|
|
|
int ourBottom = ourRect.top() + ourRect.height();
|
|
|
|
|
int ourTop = ourRect.top();
|
|
|
|
|
int ourLeft = ourRect.left();
|
|
|
|
|
int ourRight = ourRect.left() + ourRect.width();
|
|
|
|
|
QPoint ourLeftBottom = QPoint(ourLeft, ourBottom);
|
|
|
|
|
QPoint ourRightBottom = QPoint(ourRight, ourBottom);
|
|
|
|
|
QPoint ourRightTop = QPoint(ourRight, ourTop);
|
|
|
|
|
|
|
|
|
|
QRect otherRect = QRect(other->geometry().topLeft(), other->geometry().size() * other->devicePixelRatio());
|
|
|
|
|
int otherBottom = otherRect.top() + otherRect.height();
|
|
|
|
|
int otherTop = otherRect.top();
|
|
|
|
|
int otherLeft = otherRect.left();
|
|
|
|
|
int otherRight = otherRect.left() + otherRect.width();
|
|
|
|
|
QPoint otherLeftBottom = QPoint(otherLeft, otherBottom);
|
|
|
|
|
QPoint otherLeftTop = QPoint(otherLeft, otherTop);
|
|
|
|
|
QPoint otherRightTop = QPoint(otherRight, otherTop);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 上下拼接,our屏幕左右移动。
|
|
|
|
|
* our屏幕从other屏幕对角的左上侧向右移动,至other屏幕对角的右上侧位置
|
|
|
|
|
--------- ---------
|
|
|
|
|
| | | |
|
|
|
|
|
| our | ======>>>>> | our |
|
|
|
|
|
| | | |
|
|
|
|
|
--------------- ---------------
|
|
|
|
|
| | | |
|
|
|
|
|
| other | | other |
|
|
|
|
|
| | | |
|
|
|
|
|
--------- ---------
|
|
|
|
|
*/
|
|
|
|
|
// 上下拼接
|
|
|
|
|
if (ourBottom == otherTop
|
|
|
|
|
&& (ourRight >= otherLeft)
|
|
|
|
|
&& (ourLeft <= otherRight)) {
|
|
|
|
|
// 排除对角排列
|
|
|
|
|
if (ourLeftBottom == otherRightTop
|
|
|
|
|
|| ourRightBottom == otherLeftTop)
|
|
|
|
|
continue;
|
|
|
|
|
m_screenPositionMap[s][Position::Bottom] = false;
|
|
|
|
|
m_screenPositionMap[other][Position::Top] = false;
|
|
|
|
|
}
|
2021-04-12 16:53:03 +08:00
|
|
|
|
|
2021-10-26 15:02:18 +08:00
|
|
|
|
/*
|
|
|
|
|
* 左右拼接,our屏幕上下移动。
|
|
|
|
|
* our屏幕从other屏幕对角的左上侧向下移动,至other屏幕对角的最左下侧位置
|
|
|
|
|
--------- ---------
|
|
|
|
|
| | | |
|
|
|
|
|
| our | ======>>>>> ---------| other |
|
|
|
|
|
| |-------- | | |
|
|
|
|
|
--------| | | our |--------
|
|
|
|
|
| other | | |
|
|
|
|
|
| | ----------
|
|
|
|
|
---------
|
|
|
|
|
*/
|
|
|
|
|
// 左右拼接
|
|
|
|
|
if (otherLeft == ourRight
|
|
|
|
|
&& (ourTop <= otherBottom)
|
|
|
|
|
&& (ourBottom >= otherTop)) {
|
|
|
|
|
// 排除对角排列
|
|
|
|
|
if (ourRightTop == otherLeftBottom
|
|
|
|
|
|| ourRightBottom == otherLeftTop)
|
|
|
|
|
continue;
|
|
|
|
|
m_screenPositionMap[s][Position::Right] = false;
|
|
|
|
|
m_screenPositionMap[other][Position::Left] = false;
|
|
|
|
|
}
|
2021-04-12 16:53:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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);
|
|
|
|
|
|
2021-05-08 21:35:35 +08:00
|
|
|
|
// 显示器信息发生任何变化时,都应该重新刷新一次任务栏的显示位置
|
|
|
|
|
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);
|
2021-04-12 16:53:03 +08:00
|
|
|
|
|
|
|
|
|
m_screens.append(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 屏幕数量发生变化,应该刷新一下任务栏的显示
|
2021-05-08 21:35:35 +08:00
|
|
|
|
dockInfoChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DisplayManager::dockInfoChanged()
|
|
|
|
|
{
|
|
|
|
|
updateScreenDockInfo();
|
|
|
|
|
|
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
|
qInfo() << m_screenPositionMap;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Q_EMIT screenInfoChanged();
|
2021-04-12 16:53:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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();
|
|
|
|
|
|
2021-05-08 21:35:35 +08:00
|
|
|
|
dockInfoChanged();
|
2021-04-12 16:53:03 +08:00
|
|
|
|
}
|
|
|
|
|
}
|