|
21 | 21 | #include <QTimer> |
22 | 22 | #include <QWindow> |
23 | 23 |
|
| 24 | +#ifndef ENABLE_DSS_SNIPE |
| 25 | +#include <QX11Info> |
| 26 | +#else |
| 27 | +#include <xcb/xproto.h> |
| 28 | +#endif |
| 29 | +#include <xcb/xcb.h> |
| 30 | + |
24 | 31 | #include "dbusconstant.h" |
25 | 32 |
|
26 | 33 | Q_LOGGING_CATEGORY(DDE_SS, "dss.active") |
@@ -74,9 +81,53 @@ FullScreenBackground::FullScreenBackground(SessionBaseModel *model, QWidget *par |
74 | 81 | connect(m_resetGeometryTimer, &QTimer::timeout, this, [this] { |
75 | 82 | const auto ¤tGeometry = geometry(); |
76 | 83 | if (currentGeometry != m_geometryRect) { |
77 | | - qCDebug(DDE_SHELL) << "Current geometry:" << currentGeometry <<"setGeometry:" << m_geometryRect; |
| 84 | + qCWarning(DDE_SHELL) << "Geometry mismatch detected! Qt cached geometry:" << currentGeometry |
| 85 | + << ", target geometry:" << m_geometryRect << ", this:" << this; |
78 | 86 | setGeometry(m_geometryRect); |
79 | 87 | } |
| 88 | + |
| 89 | + // 通过 XCB 检查窗口在 X Server 中的实际位置 |
| 90 | + // 注意:X11 坐标系中,窗口位置不乘 DPR(与 X RandR 一致),窗口大小乘 DPR |
| 91 | + if (!m_model->isUseWayland() && windowHandle()) { |
| 92 | + xcb_connection_t *connection = nullptr; |
| 93 | +#ifndef ENABLE_DSS_SNIPE |
| 94 | + connection = QX11Info::connection(); |
| 95 | +#else |
| 96 | + auto *x11App = qGuiApp->nativeInterface<QNativeInterface::QX11Application>(); |
| 97 | + if (x11App) |
| 98 | + connection = x11App->connection(); |
| 99 | +#endif |
| 100 | + if (connection) { |
| 101 | + auto cookie = xcb_get_geometry(connection, static_cast<xcb_window_t>(winId())); |
| 102 | + auto *reply = xcb_get_geometry_reply(connection, cookie, nullptr); |
| 103 | + if (reply) { |
| 104 | + QRect xcbGeometry(reply->x, reply->y, reply->width, reply->height); |
| 105 | + const qreal dpr = devicePixelRatioF(); |
| 106 | + QRect expectedPhysical(m_geometryRect.x(), m_geometryRect.y(), |
| 107 | + qRound(m_geometryRect.width() * dpr), |
| 108 | + qRound(m_geometryRect.height() * dpr)); |
| 109 | + if (xcbGeometry != expectedPhysical) { |
| 110 | + qCWarning(DDE_SHELL) << "XCB position mismatch! XCB geometry(physical):" << xcbGeometry |
| 111 | + << ", expected(physical):" << expectedPhysical |
| 112 | + << ", target(logical):" << m_geometryRect |
| 113 | + << ", dpr:" << dpr |
| 114 | + << ", this:" << this |
| 115 | + << ", screen:" << (m_screen ? m_screen->name() : "null"); |
| 116 | + // Qt 的 geometry() 缓存可能已经是正确值,但实际 X 窗口未移动。 |
| 117 | + // 强制重新绑定 screen 并调用 setGeometry,让 Qt 重新发送 XCB configure request。 |
| 118 | + if (!m_screen.isNull() && windowHandle()->screen() != m_screen) { |
| 119 | + windowHandle()->setScreen(m_screen); |
| 120 | + } |
| 121 | + // 先 resize 到 0,0 再设目标值,破坏 Qt 的 "geometry 未变" 优化,强制重新下发 |
| 122 | + setGeometry(0, 0, 0, 0); |
| 123 | + setGeometry(m_geometryRect); |
| 124 | + } else { |
| 125 | + qCInfo(DDE_SHELL) << "XCB position match, no need to set geometry"; |
| 126 | + } |
| 127 | + free(reply); |
| 128 | + } |
| 129 | + } |
| 130 | + } |
80 | 131 | }); |
81 | 132 |
|
82 | 133 | connect(m_model, &SessionBaseModel::shutdownkModeChanged, this, [this] (bool value){ |
@@ -453,14 +504,20 @@ void FullScreenBackground::updateGeometry() |
453 | 504 | } |
454 | 505 |
|
455 | 506 | if (!m_screen.isNull()) { |
456 | | - if(m_model->isUseWayland()) |
| 507 | + // X11 下也需要将 QWindow 关联到正确的 QScreen,否则 Qt 可能将窗口归属到错误的 screen |
| 508 | + if (windowHandle() && windowHandle()->screen() != m_screen) { |
| 509 | + qCInfo(DDE_SHELL) << "bindWindowToScreen, windowHandle screen:" << windowHandle()->screen()->name() |
| 510 | + << ", target screen:" << m_screen->name() << ", this:" << this; |
457 | 511 | windowHandle()->setScreen(m_screen); |
| 512 | + } |
458 | 513 | setddeGeometry(m_screen->geometry()); |
459 | 514 |
|
460 | 515 | qCInfo(DDE_SHELL) << "Update geometry, screen:" << m_screen |
| 516 | + << ", screen name:" << m_screen->name() |
461 | 517 | << ", screen geometry:" << m_screen->geometry() |
462 | 518 | << ", lockFrame:" << this |
463 | | - << ", frame geometry:" << this->geometry(); |
| 519 | + << ", frame geometry:" << this->geometry() |
| 520 | + << ", windowHandle screen:" << (windowHandle() ? windowHandle()->screen()->name() : "null"); |
464 | 521 | } else { |
465 | 522 | qCWarning(DDE_SHELL) << "Screen is nullptr"; |
466 | 523 | } |
@@ -735,6 +792,12 @@ bool FullScreenBackground::getScaledBlurImage(const QString &originPath, QString |
735 | 792 | //增加一个定时器,每隔50ms再设置一次Geometry,避免出现xorg初始化未完成的情况,导致界面显示不全 |
736 | 793 | void FullScreenBackground::setddeGeometry(const QRect &rect) |
737 | 794 | { |
| 795 | + qCInfo(DDE_SHELL) << "setddeGeometry called, this:" << this |
| 796 | + << ", target rect:" << rect |
| 797 | + << ", current geometry:" << geometry() |
| 798 | + << ", screen:" << (m_screen ? m_screen->name() : "null") |
| 799 | + << ", windowHandle screen:" << (windowHandle() ? windowHandle()->screen()->name() : "null") |
| 800 | + << ", dpr:" << devicePixelRatioF(); |
738 | 801 | setGeometry(rect); |
739 | 802 | m_geometryRect = rect; |
740 | 803 | m_resetGeometryTimer->start(200); |
|
0 commit comments