From df74226b34a2bafacb564200c9f8f69aa5edfe7b Mon Sep 17 00:00:00 2001 From: ssk Date: Thu, 11 Aug 2022 19:35:19 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E6=A0=8F=E6=A6=82=E7=8E=87=E6=80=A7=E6=98=BE=E7=A4=BA=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98=20(#559)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过QScreen::handle获取缩放前的屏幕尺寸出错,导致显示位置错误,目前任务栏换了一个获取尺寸的函数 Log: 修复任务栏概率性显示位置错误的问题 Influence: 设置显示器仅A屏到仅B屏,小概率 Bug: https://pms.uniontech.com/bug-view-126025.html Change-Id: I465bf033c441bc0c31de741da51fe6c83ff177b1 Co-authored-by: 范朋程 --- frame/util/multiscreenworker.cpp | 57 +++++++++++++++++++++++++------- frame/util/multiscreenworker.h | 3 +- frame/window/mainwindow.cpp | 1 + 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/frame/util/multiscreenworker.cpp b/frame/util/multiscreenworker.cpp index 77ab4035a..b17fd77d3 100644 --- a/frame/util/multiscreenworker.cpp +++ b/frame/util/multiscreenworker.cpp @@ -714,6 +714,40 @@ bool MultiScreenWorker::isCopyMode() return true; } +/** + * @brief MultiScreenWorker::getScreenRect + * @param s + * @param ratio + * @return 返回屏幕 \s 的原始尺寸,\ratio 为屏幕 \s 的当前缩放值 + */ +QRect MultiScreenWorker::getScreenRect(QScreen *s) +{ + if (!s) + return QRect(); + + auto geo = s->geometry(); + QRect screenRect; + screenRect.setX(geo.x()); + screenRect.setY(geo.y()); + screenRect.setWidth(static_cast(geo.width() * s->devicePixelRatio())); + screenRect.setHeight(static_cast(geo.height() * s->devicePixelRatio())); + + /* QScreen的handle会返回显示器缩放之前的分辨率 + * 比如1920*1080,调整缩放为1.25,那么QScreen::geometry返回的为QSize(1536, 864),QScreen::handle()->geometry()返回的为QSize(1920, 1080); + * + * @note 但在特殊情况下,比如频繁插拔显示器时,小概率出现handle返回的值并不等于缩放前的分辨率的情况,从而导致任务栏位置设置出错, + * 这里仍然直接使用geometry*ratio的方式,去获取缩放前的分辨率 + * 但考虑到缩放值类型为double,可能在高分屏下计算得到的尺寸和通过handle函数的原始尺寸有1像素的误差, + * 所以计算完毕后和handle比对一下,如果存在1像素的误差,则仍然使用handle函数,否则使用QScreen::geometry() * ratio + */ + auto size = s->handle()->geometry().size() - screenRect.size(); + if (Q_LIKELY(size.width() <= 1 && size.height() <= 1)) { + screenRect = s->handle()->geometry(); + } + + return screenRect; +} + /** * @brief 这里用到xcb去设置任务栏的高度,比较特殊,参考_NET_WM_STRUT_PARTIAL属性 * 在屏幕旋转后,所有参数以控制中心自定义设置里主屏显示的图示为准(旋转不用特殊处理) @@ -1476,18 +1510,21 @@ void MultiScreenWorker::checkXEventMonitorService() } } -QRect MultiScreenWorker::getDockShowMinGeometry(const QString &screenName, bool withoutScale) +/** + * @brief MultiScreenWorker::getDockShowMinGeometry + * @param screenName + * @return 如果dock在当前screenName对应的屏幕上显示,返回其在最小 高/宽 度(也就是40,最大值为100)的rect区域 + */ +QRect MultiScreenWorker::getDockShowMinGeometry(const QString &screenName) { QRect rect; - const double ratio = withoutScale ? 1 : qApp->devicePixelRatio(); - const int margin = static_cast((m_displayMode == DisplayMode::Fashion ? 10 : 0) * (withoutScale ? qApp->devicePixelRatio() : 1)); + const double ratio = qApp->devicePixelRatio(); + const int margin = static_cast((m_displayMode == DisplayMode::Fashion ? 10 : 0) * qApp->devicePixelRatio()); const int dockSize = 40; for (auto s : DIS_INS->screens()) { if (s->name() == screenName) { - // 拿到当前显示器缩放之前的分辨率 - QRect screenRect = s->handle()->geometry(); - + const QRect screenRect = getScreenRect(s); switch (m_position) { case Position::Top: rect.setX(static_cast(screenRect.x() + margin)); @@ -1549,9 +1586,7 @@ QRect MultiScreenWorker::getDockShowGeometry(const QString &screenName, const Po for (auto s : DIS_INS->screens()) { if (s->name() == screenName) { - // 拿到当前显示器缩放之前的分辨率 - QRect screenRect = s->handle()->geometry(); - + const QRect screenRect = getScreenRect(s); switch (pos) { case Position::Top: rect.setX(static_cast(screenRect.x() + margin)); @@ -1600,9 +1635,7 @@ QRect MultiScreenWorker::getDockHideGeometry(const QString &screenName, const Po for (auto s : DIS_INS->screens()) { if (s->name() == screenName) { - // 拿到当前显示器缩放之前的分辨率 - QRect screenRect = s->handle()->geometry(); - + const QRect screenRect = getScreenRect(s); switch (pos) { case Position::Top: rect.setX(static_cast(screenRect.x() + margin)); diff --git a/frame/util/multiscreenworker.h b/frame/util/multiscreenworker.h index b9554ffb2..aa8ac7582 100644 --- a/frame/util/multiscreenworker.h +++ b/frame/util/multiscreenworker.h @@ -147,7 +147,7 @@ public: QRect dockRect(const QString &screenName, const Position &pos, const HideMode &hideMode, const DisplayMode &displayMode); QRect dockRect(const QString &screenName); - QRect getDockShowMinGeometry(const QString &screenName, bool withoutScale = false); + QRect getDockShowMinGeometry(const QString &screenName); bool launcherVisible(); void setLauncherVisble(bool isVisible); @@ -248,6 +248,7 @@ private: bool onScreenEdge(const QString &screenName, const QPoint &point); const QPoint rawXPosition(const QPoint &scaledPos); static bool isCopyMode(); + QRect getScreenRect(QScreen *s); private: QWidget *m_parent; diff --git a/frame/window/mainwindow.cpp b/frame/window/mainwindow.cpp index 1a92e56d8..c08c92ada 100755 --- a/frame/window/mainwindow.cpp +++ b/frame/window/mainwindow.cpp @@ -504,6 +504,7 @@ void MainWindow::resizeDock(int offset, bool dragging) { qApp->setProperty(DRAG_STATE_PROP, dragging); + // 以任务栏的最小高度区域为参照,通过offset设置其高度或宽度 const QRect &rect = m_multiScreenWorker->getDockShowMinGeometry(m_multiScreenWorker->deskScreen()); QRect newRect; switch (m_multiScreenWorker->position()) {