diff --git a/debian/control b/debian/control index 5fdcdc40..be956330 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,9 @@ Build-Depends: debhelper (>= 11), libglib2.0-dev, libdtk6gui-dev, libdtk6core-dev, + libx11-dev, + libxcb-randr0-dev, + libxcb1-dev, Standards-Version: 4.1.3 Homepage: https://github.com/linuxdeepin diff --git a/src/plugin-qt/xsettings/CMakeLists.txt b/src/plugin-qt/xsettings/CMakeLists.txt index ae68a7bf..b8a1cc97 100644 --- a/src/plugin-qt/xsettings/CMakeLists.txt +++ b/src/plugin-qt/xsettings/CMakeLists.txt @@ -14,10 +14,9 @@ file(GLOB_RECURSE SRCS "*.h" "*.cpp") find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core DBus) find_package(Dtk${DTK_VERSION_MAJOR} REQUIRED COMPONENTS Gui Core) -find_package(PkgConfig REQUIRED) - -pkg_check_modules(X11 REQUIRED IMPORTED_TARGET x11) -pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb) +find_package(X11 REQUIRED) +find_package(XCB REQUIRED) +find_package(XCB REQUIRED COMPONENTS RANDR) add_library(${BIN_NAME} MODULE ${SRCS} @@ -26,8 +25,9 @@ add_library(${BIN_NAME} MODULE target_link_libraries(${BIN_NAME} Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::DBus - PkgConfig::X11 - PkgConfig::XCB + X11::X11 + XCB::XCB + XCB::RANDR Dtk${DTK_VERSION_MAJOR}::Core ) macro(install_user_symlink filepath wantsdir) diff --git a/src/plugin-qt/xsettings/impl/xsettingsmanager.cpp b/src/plugin-qt/xsettings/impl/xsettingsmanager.cpp index 03249840..7648eb5d 100644 --- a/src/plugin-qt/xsettings/impl/xsettingsmanager.cpp +++ b/src/plugin-qt/xsettings/impl/xsettingsmanager.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,10 @@ XSettingsManager::XSettingsManager(QObject *parent) , m_xcbUtils(XcbUtils::getInstance()) { connect(m_settingDconfig, &DTK_CORE_NAMESPACE::DConfig::valueChanged, this, &XSettingsManager::handleDConfigChangedCb); + setScreenScaleFactors(getScreenScaleFactors(), false); + adjustScaleFactor(getRecommendedScaleFactor()); setSettings(getSettingsInSchema()); + updateDPI(); updateXResources(); QThreadPool::globalInstance()->start([this]() { @@ -231,6 +235,123 @@ void XSettingsManager::handleDConfigChangedCb(const QString &key) setSettings(xsSetting); } +double toListedScaleFactor(double s) +{ + const double min = 1.0; + const double max = 3.0; + const double step = 0.25; + + if (s <= min) { + return min; + } else if (s >= max) { + return max; + } + + for (double i = min; i <= max; i += step) { + if (i > s) { + double ii = i - step; + double d1 = s - ii; + double d2 = i - s; + + if (d1 >= d2) { + return i; + } else { + return ii; + } + } + } + return max; +} + +// calcRecommendedScaleFactor 计算推荐的缩放比 +double calcRecommendedScaleFactor(double widthPx, double heightPx, double widthMm, double heightMm) +{ + if (widthMm == 0.0 || heightMm == 0.0) { + return 1.0; + } + double lenPx = std::sqrt(std::pow(widthPx, 2) + std::pow(heightPx, 2)); + double lenMm = std::sqrt(std::pow(widthMm, 2) + std::pow(heightMm, 2)); + + double lenPxStd = std::sqrt(std::pow(1920, 2) + std::pow(1080, 2)); // 标准分辨率对角线长度 + double lenMmStd = std::sqrt(std::pow(477, 2) + std::pow(268, 2)); // 标准物理尺寸对角线长度 + + const double a = 0.00158; + double fix = (lenMm - lenMmStd) * (lenPx / lenPxStd) * a; + double scaleFactor = (lenPx / lenMm) / (lenPxStd / lenMmStd) + fix; + + return toListedScaleFactor(scaleFactor); +} + +double XSettingsManager::getRecommendedScaleFactor() +{ + QList monitors = XcbUtils::getInstance().getMonitorSizeInfos(); + if (monitors.isEmpty()) { + return 1.0; + } + // 允许用户通过 force-scale-factor.ini 强制设置全局缩放 + double forceScaleFactor = getForceScaleFactor(); + if (forceScaleFactor > 0.0) { + return forceScaleFactor; + } + double minScaleFactor = 3.0; + for (auto &&monitor : monitors) { + double scaleFactor = calcRecommendedScaleFactor(monitor.width, monitor.height, monitor.mmWidth, monitor.mmHeight); + if (minScaleFactor > scaleFactor) { + minScaleFactor = scaleFactor; + } + } + return minScaleFactor; +} + +// GetForceScaleFactor 允许用户通过 force-scale-factor.ini 强制设置全局缩放 +double XSettingsManager::getForceScaleFactor() +{ + QString fileName = Utils::GetUserConfigDir() + "/deepin/force-scale-factor.ini"; + KeyFile keyFile; + bool bSuccess = keyFile.loadFile(fileName); + if (bSuccess) { + bool ok = false; + double forceScaleFactor = keyFile.getStr("ForceScaleFactor", "scale").toDouble(&ok); + if (ok && forceScaleFactor >= 1.0 && forceScaleFactor <= 3.0) { + return forceScaleFactor; + } + qWarning() << "invalid forceScaleFactor:" << keyFile.getStr("ForceScaleFactor", "scale"); + } + return -1.0; +} + +void XSettingsManager::adjustScaleFactor(double recommendedScaleFactor) +{ + qDebug() << "recommended scale factor:" << recommendedScaleFactor; + double value = m_settingDconfig->value("scale-factor").toDouble(); + if (value <= 0) { + ScaleFactors map; + map.insert("ALL", value); + setScreenScaleFactors(map, false); + // m_restartOSD = true; + } + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + if (!env.value("STARTDDE_MIGRATE_SCALE_FACTOR").isEmpty()) { + double scaleFactor = getScaleFactor(); + if (scaleFactor > 0.0) { + ScaleFactors map; + map.insert("", scaleFactor); + setScreenScaleFactorsForQt(map); + } + cleanUpDdeEnv(); + return; + } + if (!QFile::exists("/etc/lightdm/deepin/qt-theme.ini")) { + // lightdm-deepin-greeter does not have the qt-theme.ini file yet. + double scaleFactor = getScaleFactor(); + if (scaleFactor > 0.0) { + ScaleFactors map; + map.insert("", scaleFactor); + setScreenScaleFactorsForQt(map); + } + } +} + void XSettingsManager::updateDPI() { double scale = 1; diff --git a/src/plugin-qt/xsettings/impl/xsettingsmanager.h b/src/plugin-qt/xsettings/impl/xsettingsmanager.h index c62910f3..9437a2b8 100644 --- a/src/plugin-qt/xsettings/impl/xsettingsmanager.h +++ b/src/plugin-qt/xsettings/impl/xsettingsmanager.h @@ -42,6 +42,9 @@ protected Q_SLOTS: void handleDConfigChangedCb(const QString &key); private: + double getRecommendedScaleFactor(); + double getForceScaleFactor(); + void adjustScaleFactor(double recommendedScaleFactor); void updateDPI(); void updateXResources(); void updateFirefoxDPI(); diff --git a/src/plugin-qt/xsettings/modules/api/xcbutils.cpp b/src/plugin-qt/xsettings/modules/api/xcbutils.cpp index 8213ad10..3cd65bd8 100644 --- a/src/plugin-qt/xsettings/modules/api/xcbutils.cpp +++ b/src/plugin-qt/xsettings/modules/api/xcbutils.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -181,6 +182,72 @@ QString XcbUtils::getXcbAtomName(xcb_atom_t atom) return ""; } +QList XcbUtils::getMonitorSizeInfos() +{ + // 获取XCB版本信息 + const xcb_setup_t *setup = xcb_get_setup(connection); + int majorVersion = setup->protocol_major_version; + int minorVersion = setup->protocol_minor_version; + qInfo() << QString("randr version %1.%2").arg(majorVersion).arg(minorVersion); + if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 2)) { + return {}; + } + xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(setup); + xcb_window_t root = screen_iter.data->root; + xcb_randr_get_screen_resources_cookie_t cookie = xcb_randr_get_screen_resources(connection, root); + xcb_generic_error_t *error = nullptr; + xcb_randr_get_screen_resources_reply_t *resources = xcb_randr_get_screen_resources_reply(connection, cookie, &error); + if (error) { + qWarning() << "Error getting screen resources: " << error->error_code; + free(error); + return {}; + } + + xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_outputs(resources); + int output_count = xcb_randr_get_screen_resources_outputs_length(resources); + QList monitors; + for (int i = 0; i < output_count; i++) { + xcb_randr_output_t output = outputs[i]; + xcb_randr_get_output_info_cookie_t info_cookie = xcb_randr_get_output_info(connection, output, resources->config_timestamp); + + xcb_randr_get_output_info_reply_t *output_info = xcb_randr_get_output_info_reply(connection, info_cookie, nullptr); + + if (!output_info) + continue; + + // 检查输出是否连接 + if (output_info->connection != XCB_RANDR_CONNECTION_CONNECTED) { + free(output_info); + continue; + } + + if (output_info->crtc == XCB_NONE) { + free(output_info); + continue; + } + xcb_randr_get_crtc_info_cookie_t crtc_cookie = xcb_randr_get_crtc_info(connection, output_info->crtc, resources->config_timestamp); + + xcb_randr_get_crtc_info_reply_t *crtc_info = xcb_randr_get_crtc_info_reply(connection, crtc_cookie, nullptr); + + if (crtc_info) { + MonitorSizeInfo monitor; + monitor.width = crtc_info->width; + monitor.height = crtc_info->height; + monitor.mmWidth = output_info->mm_width; + monitor.mmHeight = output_info->mm_height; + + monitors.push_back(monitor); + + free(crtc_info); + } + + free(output_info); + } + + free(resources); + return monitors; +} + // 获取 _XSETTINGS_SETTINGS 属性 QByteArray XcbUtils::getXcbAtomProperty(xcb_atom_t atom) { diff --git a/src/plugin-qt/xsettings/modules/api/xcbutils.h b/src/plugin-qt/xsettings/modules/api/xcbutils.h index ecf1d024..f75c39eb 100644 --- a/src/plugin-qt/xsettings/modules/api/xcbutils.h +++ b/src/plugin-qt/xsettings/modules/api/xcbutils.h @@ -14,6 +14,14 @@ class XcbUtils : public QObject { Q_OBJECT public: + struct MonitorSizeInfo + { + uint16_t width; + uint16_t height; + uint32_t mmWidth; + uint32_t mmHeight; + }; + static XcbUtils &getInstance(); xcb_window_t createWindows(); xcb_atom_t getAtom(const char *name, bool exist = false); @@ -28,6 +36,7 @@ class XcbUtils : public QObject QByteArray getXcbAtomProperty(xcb_atom_t atom); QByteArray xcbPropertyReplyDataToArray(xcb_get_property_reply_t *reply); QString getXcbAtomName(xcb_atom_t atom); + QList getMonitorSizeInfos(); private: XcbUtils(QObject *parent = nullptr);