commit c51d6447fd0d124903d16bf5952efccbf9e1ca92 Author: Tom Anderson Date: Wed May 24 22:53:20 2023 +0000 [Qt] Handle scale factor changes This is a speculative fix for https://crbug.com/1439149. I suspect the scale factor is not set immediately on QT initialization, but is set asynchronously shortly after. This CL adds a listener for QT scale changes. R=thestig Low-Coverage-Reason: No QT tests currently Change-Id: I7dea23e16a6bb26237564af2dc4e43480f6aea9f Bug: 1439149 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4559732 Reviewed-by: Lei Zhang Commit-Queue: Thomas Anderson Auto-Submit: Thomas Anderson Cr-Commit-Position: refs/heads/main@{#1148805} diff --git a/ui/qt/qt5_shim_moc.cc b/ui/qt/qt5_shim_moc.cc index 8f8b6b57784a8..6e504f23c603a 100644 --- a/ui/qt/qt5_shim_moc.cc +++ b/ui/qt/qt5_shim_moc.cc @@ -23,8 +23,8 @@ QT_BEGIN_MOC_NAMESPACE struct qt_meta_stringdata_qt__QtShim_t { - QByteArrayData data[6]; - char stringdata[52]; + QByteArrayData data[13]; + char stringdata[151]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET( \ @@ -33,9 +33,16 @@ struct qt_meta_stringdata_qt__QtShim_t { static const qt_meta_stringdata_qt__QtShim_t qt_meta_stringdata_qt__QtShim = { {QT_MOC_LITERAL(0, 0, 10), QT_MOC_LITERAL(1, 11, 11), QT_MOC_LITERAL(2, 23, 0), QT_MOC_LITERAL(3, 24, 4), - QT_MOC_LITERAL(4, 29, 14), QT_MOC_LITERAL(5, 44, 7)}, + QT_MOC_LITERAL(4, 29, 14), QT_MOC_LITERAL(5, 44, 7), + QT_MOC_LITERAL(6, 52, 11), QT_MOC_LITERAL(7, 64, 8), + QT_MOC_LITERAL(8, 73, 6), QT_MOC_LITERAL(9, 80, 13), + QT_MOC_LITERAL(10, 94, 25), QT_MOC_LITERAL(11, 120, 3), + QT_MOC_LITERAL(12, 124, 26)}, "qt::QtShim\0FontChanged\0\0font\0" - "PaletteChanged\0palette"}; + "PaletteChanged\0palette\0ScreenAdded\0" + "QScreen*\0screen\0ScreenRemoved\0" + "LogicalDotsPerInchChanged\0dpi\0" + "PhysicalDotsPerInchChanged"}; #undef QT_MOC_LITERAL static const uint qt_meta_data_qt__QtShim[] = { @@ -44,7 +51,7 @@ static const uint qt_meta_data_qt__QtShim[] = { 7, // revision 0, // classname 0, 0, // classinfo - 2, 14, // methods + 6, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors @@ -52,11 +59,15 @@ static const uint qt_meta_data_qt__QtShim[] = { 0, // signalCount // slots: name, argc, parameters, tag, flags - 1, 1, 24, 2, 0x08 /* Private */, 4, 1, 27, 2, 0x08 /* Private */, + 1, 1, 44, 2, 0x08 /* Private */, 4, 1, 47, 2, 0x08 /* Private */, 6, 1, 50, + 2, 0x08 /* Private */, 9, 1, 53, 2, 0x08 /* Private */, 10, 1, 56, 2, + 0x08 /* Private */, 12, 1, 59, 2, 0x08 /* Private */, // slots: parameters QMetaType::Void, QMetaType::QFont, 3, QMetaType::Void, QMetaType::QPalette, - 5, + 5, QMetaType::Void, 0x80000000 | 7, 8, QMetaType::Void, 0x80000000 | 7, 8, + QMetaType::Void, QMetaType::QReal, 11, QMetaType::Void, QMetaType::QReal, + 11, 0 // eod }; @@ -74,6 +85,18 @@ void qt::QtShim::qt_static_metacall(QObject* _o, case 1: _t->PaletteChanged((*reinterpret_cast(_a[1]))); break; + case 2: + _t->ScreenAdded((*reinterpret_cast(_a[1]))); + break; + case 3: + _t->ScreenRemoved((*reinterpret_cast(_a[1]))); + break; + case 4: + _t->LogicalDotsPerInchChanged((*reinterpret_cast(_a[1]))); + break; + case 5: + _t->PhysicalDotsPerInchChanged((*reinterpret_cast(_a[1]))); + break; default:; } } @@ -107,15 +130,15 @@ int qt::QtShim::qt_metacall(QMetaObject::Call _c, int _id, void** _a) { return _id; } if (_c == QMetaObject::InvokeMetaMethod) { - if (_id < 2) { + if (_id < 6) { qt_static_metacall(this, _c, _id, _a); } - _id -= 2; + _id -= 6; } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { - if (_id < 2) { + if (_id < 6) { *reinterpret_cast(_a[0]) = -1; } - _id -= 2; + _id -= 6; } return _id; } diff --git a/ui/qt/qt6_shim_moc.cc b/ui/qt/qt6_shim_moc.cc index 6d02ca317b65d..a16515008d892 100644 --- a/ui/qt/qt6_shim_moc.cc +++ b/ui/qt/qt6_shim_moc.cc @@ -26,8 +26,8 @@ QT_BEGIN_MOC_NAMESPACE QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED struct qt_meta_stringdata_qt__QtShim_t { - const uint offsetsAndSize[12]; - char stringdata0[52]; + const uint offsetsAndSize[26]; + char stringdata0[151]; }; #define QT_MOC_LITERAL(ofs, len) \ uint(offsetof(qt_meta_stringdata_qt__QtShim_t, stringdata0) + ofs), len @@ -38,11 +38,21 @@ static const qt_meta_stringdata_qt__QtShim_t qt_meta_stringdata_qt__QtShim = { QT_MOC_LITERAL(23, 0), // "" QT_MOC_LITERAL(24, 4), // "font" QT_MOC_LITERAL(29, 14), // "PaletteChanged" - QT_MOC_LITERAL(44, 7) // "palette" + QT_MOC_LITERAL(44, 7), // "palette" + QT_MOC_LITERAL(52, 11), // "ScreenAdded" + QT_MOC_LITERAL(64, 8), // "QScreen*" + QT_MOC_LITERAL(73, 6), // "screen" + QT_MOC_LITERAL(80, 13), // "ScreenRemoved" + QT_MOC_LITERAL(94, 25), // "LogicalDotsPerInchChanged" + QT_MOC_LITERAL(120, 3), // "dpi" + QT_MOC_LITERAL(124, 26) // "PhysicalDotsPerInchChanged" }, "qt::QtShim\0FontChanged\0\0font\0" - "PaletteChanged\0palette"}; + "PaletteChanged\0palette\0ScreenAdded\0" + "QScreen*\0screen\0ScreenRemoved\0" + "LogicalDotsPerInchChanged\0dpi\0" + "PhysicalDotsPerInchChanged"}; #undef QT_MOC_LITERAL static const uint qt_meta_data_qt__QtShim[] = { @@ -51,7 +61,7 @@ static const uint qt_meta_data_qt__QtShim[] = { 10, // revision 0, // classname 0, 0, // classinfo - 2, 14, // methods + 6, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors @@ -59,11 +69,15 @@ static const uint qt_meta_data_qt__QtShim[] = { 0, // signalCount // slots: name, argc, parameters, tag, flags, initial metatype offsets - 1, 1, 26, 2, 0x08, 1 /* Private */, 4, 1, 29, 2, 0x08, 3 /* Private */, + 1, 1, 50, 2, 0x08, 1 /* Private */, 4, 1, 53, 2, 0x08, 3 /* Private */, 6, + 1, 56, 2, 0x08, 5 /* Private */, 9, 1, 59, 2, 0x08, 7 /* Private */, 10, 1, + 62, 2, 0x08, 9 /* Private */, 12, 1, 65, 2, 0x08, 11 /* Private */, // slots: parameters QMetaType::Void, QMetaType::QFont, 3, QMetaType::Void, QMetaType::QPalette, - 5, + 5, QMetaType::Void, 0x80000000 | 7, 8, QMetaType::Void, 0x80000000 | 7, 8, + QMetaType::Void, QMetaType::QReal, 11, QMetaType::Void, QMetaType::QReal, + 11, 0 // eod }; @@ -83,6 +97,22 @@ void qt::QtShim::qt_static_metacall(QObject* _o, _t->PaletteChanged( (*reinterpret_cast>(_a[1]))); break; + case 2: + _t->ScreenAdded( + (*reinterpret_cast>(_a[1]))); + break; + case 3: + _t->ScreenRemoved( + (*reinterpret_cast>(_a[1]))); + break; + case 4: + _t->LogicalDotsPerInchChanged( + (*reinterpret_cast>(_a[1]))); + break; + case 5: + _t->PhysicalDotsPerInchChanged( + (*reinterpret_cast>(_a[1]))); + break; default:; } } @@ -98,7 +128,15 @@ const QMetaObject qt::QtShim::staticMetaObject = { QtPrivate::TypeAndForceComplete, QtPrivate::TypeAndForceComplete, QtPrivate::TypeAndForceComplete, - QtPrivate::TypeAndForceComplete + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete, + QtPrivate::TypeAndForceComplete >, nullptr}}; @@ -127,15 +165,15 @@ int qt::QtShim::qt_metacall(QMetaObject::Call _c, int _id, void** _a) { return _id; } if (_c == QMetaObject::InvokeMetaMethod) { - if (_id < 2) { + if (_id < 6) { qt_static_metacall(this, _c, _id, _a); } - _id -= 2; + _id -= 6; } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { - if (_id < 2) { + if (_id < 6) { *reinterpret_cast(_a[0]) = QMetaType(); } - _id -= 2; + _id -= 6; } return _id; } diff --git a/ui/qt/qt_interface.h b/ui/qt/qt_interface.h index 6a362bc66c0e3..28dfc6603544f 100644 --- a/ui/qt/qt_interface.h +++ b/ui/qt/qt_interface.h @@ -118,6 +118,7 @@ class QtInterface { virtual void FontChanged() = 0; virtual void ThemeChanged() = 0; + virtual void ScaleFactorMaybeChanged() = 0; }; QtInterface() = default; diff --git a/ui/qt/qt_shim.cc b/ui/qt/qt_shim.cc index 74d34ad196f18..0aec9c3aed4ad 100644 --- a/ui/qt/qt_shim.cc +++ b/ui/qt/qt_shim.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -52,8 +53,9 @@ FontHinting QtHintingToFontHinting(QFont::HintingPreference hinting) { // Obtain the average color of a gradient. SkColor GradientColor(const QGradient& gradient) { QGradientStops stops = gradient.stops(); - if (stops.empty()) + if (stops.empty()) { return qRgba(0, 0, 0, 0); + } float a = 0; float r = 0; @@ -86,11 +88,13 @@ SkColor GradientColor(const QGradient& gradient) { // Obtain the average color of a texture. SkColor TextureColor(QImage image) { size_t size = image.width() * image.height(); - if (!size) + if (!size) { return qRgba(0, 0, 0, 0); + } - if (image.format() != QImage::Format_ARGB32_Premultiplied) + if (image.format() != QImage::Format_ARGB32_Premultiplied) { image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } size_t a = 0; size_t r = 0; @@ -203,6 +207,13 @@ QtShim::QtShim(QtInterface::Delegate* delegate, int* argc, char** argv) SLOT(FontChanged(const QFont&))); connect(&app_, SIGNAL(paletteChanged(const QPalette&)), this, SLOT(PaletteChanged(const QPalette&))); + connect(&app_, SIGNAL(screenAdded(QScreen*)), this, + SLOT(ScreenAdded(QScreen*))); + connect(&app_, SIGNAL(screenRemoved(QScreen*)), this, + SLOT(ScreenRemoved(QScreen*))); + for (QScreen* screen : app_.screens()) { + ScreenAdded(screen); + } } QtShim::~QtShim() = default; @@ -241,8 +252,9 @@ Image QtShim::GetIconForContentType(const String& content_type, auto icon = QIcon::fromTheme(name); auto pixmap = icon.pixmap(size); auto image = pixmap.toImage(); - if (image.format() != QImage::Format_ARGB32_Premultiplied) + if (image.format() != QImage::Format_ARGB32_Premultiplied) { image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } if (auto bytes = image.sizeInBytes()) { return {image.width(), image.height(), static_cast(image.devicePixelRatio()), @@ -283,6 +295,30 @@ void QtShim::PaletteChanged(const QPalette& palette) { delegate_->ThemeChanged(); } +DISABLE_CFI_VCALL +void QtShim::ScreenAdded(QScreen* screen) { + connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)), this, + SLOT(LogicalDotsPerInchChanged(qreal))); + connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)), this, + SLOT(PhysicalDotsPerInchChanged(qreal))); + delegate_->ScaleFactorMaybeChanged(); +} + +DISABLE_CFI_VCALL +void QtShim::ScreenRemoved(QScreen* screen) { + delegate_->ScaleFactorMaybeChanged(); +} + +DISABLE_CFI_VCALL +void QtShim::LogicalDotsPerInchChanged(qreal dpi) { + delegate_->ScaleFactorMaybeChanged(); +} + +DISABLE_CFI_VCALL +void QtShim::PhysicalDotsPerInchChanged(qreal dpi) { + delegate_->ScaleFactorMaybeChanged(); +} + Image QtShim::DrawHeader(int width, int height, SkColor default_color, @@ -309,8 +345,9 @@ QImage QtShim::DrawHeaderImpl(int width, QStyleOptionTitleBar opt; opt.rect = QRect(-kBorderWidth, -kBorderWidth, width + 2 * kBorderWidth, height + 2 * kBorderWidth); - if (state == ColorState::kNormal) + if (state == ColorState::kNormal) { opt.titleBarState = QStyle::State_Active; + } app_.style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &painter, nullptr); } else { diff --git a/ui/qt/qt_shim.h b/ui/qt/qt_shim.h index 607e6fe22dfc0..d979c47d589d4 100644 --- a/ui/qt/qt_shim.h +++ b/ui/qt/qt_shim.h @@ -42,6 +42,10 @@ class QtShim : public QObject, public QtInterface { private slots: void FontChanged(const QFont& font); void PaletteChanged(const QPalette& palette); + void ScreenAdded(QScreen* screen); + void ScreenRemoved(QScreen* screen); + void LogicalDotsPerInchChanged(qreal dpi); + void PhysicalDotsPerInchChanged(qreal dpi); private: QImage DrawHeaderImpl(int width, diff --git a/ui/qt/qt_ui.cc b/ui/qt/qt_ui.cc index 6a3b58e9f930b..bac5245a069f9 100644 --- a/ui/qt/qt_ui.cc +++ b/ui/qt/qt_ui.cc @@ -19,6 +19,7 @@ #include "base/nix/xdg_util.h" #include "base/notreached.h" #include "base/path_service.h" +#include "base/task/single_thread_task_runner.h" #include "base/time/time.h" #include "cc/paint/paint_canvas.h" #include "chrome/browser/themes/theme_properties.h" // nogncheck @@ -36,6 +37,7 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/image/image_skia_source.h" +#include "ui/linux/device_scale_factor_observer.h" #include "ui/linux/linux_ui.h" #include "ui/linux/nav_button_provider.h" #include "ui/native_theme/native_theme_aura.h" @@ -194,16 +196,21 @@ void QtUi::GetDefaultFontDescription(std::string* family_out, int* style_out, int* weight_out, gfx::FontRenderParams* params_out) const { - if (family_out) + if (family_out) { *family_out = font_family_; - if (size_pixels_out) + } + if (size_pixels_out) { *size_pixels_out = font_size_pixels_; - if (style_out) + } + if (style_out) { *style_out = font_style_; - if (weight_out) + } + if (weight_out) { *weight_out = font_weight_; - if (params_out) + } + if (params_out) { *params_out = font_params_; + } } ui::SelectFileDialog* QtUi::CreateSelectFileDialog( @@ -236,6 +245,7 @@ bool QtUi::Initialize() { ui::ColorProviderManager::Get().AppendColorProviderInitializer( base::BindRepeating(&QtUi::AddNativeColorMixer, base::Unretained(this))); FontChanged(); + scale_factor_ = shim_->GetScaleFactor(); return true; } @@ -246,8 +256,9 @@ ui::NativeTheme* QtUi::GetNativeTheme() const { bool QtUi::GetColor(int id, SkColor* color, bool use_custom_frame) const { auto value = GetColor(id, use_custom_frame); - if (value) + if (value) { *color = *value; + } return value.has_value(); } @@ -297,8 +308,9 @@ gfx::Image QtUi::GetIconForContentType(const std::string& content_type, float scale) const { Image image = shim_->GetIconForContentType(String(content_type.c_str()), size * scale); - if (!image.data_argb.size()) + if (!image.data_argb.size()) { return {}; + } SkImageInfo image_info = SkImageInfo::Make( image.width, image.height, kBGRA_8888_SkColorType, kPremul_SkAlphaType); @@ -345,14 +357,16 @@ bool QtUi::AnimationsEnabled() const { void QtUi::AddWindowButtonOrderObserver( ui::WindowButtonOrderObserver* observer) { - if (fallback_linux_ui_) + if (fallback_linux_ui_) { fallback_linux_ui_->AddWindowButtonOrderObserver(observer); + } } void QtUi::RemoveWindowButtonOrderObserver( ui::WindowButtonOrderObserver* observer) { - if (fallback_linux_ui_) + if (fallback_linux_ui_) { fallback_linux_ui_->RemoveWindowButtonOrderObserver(observer); + } } std::unique_ptr QtUi::CreateNavButtonProvider() { @@ -441,11 +455,24 @@ void QtUi::ThemeChanged() { native_theme_->ThemeChanged(PreferDarkTheme()); } +void QtUi::ScaleFactorMaybeChanged() { + // This gets called whenever the monitor configuration changes. Handle the + // scale change asynchronously to allow the change to propagate to QT's scale + // factor. This also coalesces scale change events together. + if (!scale_factor_task_active_) { + scale_factor_task_active_ = true; + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, base::BindOnce(&QtUi::ScaleFactorMaybeChangedImpl, + weak_factory_.GetWeakPtr())); + } +} + DISABLE_CFI_VCALL void QtUi::AddNativeColorMixer(ui::ColorProvider* provider, const ui::ColorProviderManager::Key& key) { - if (key.system_theme != ui::SystemTheme::kQt) + if (key.system_theme != ui::SystemTheme::kQt) { return; + } ui::ColorMixer& mixer = provider->AddMixer(); // These color constants are required by native_chrome_color_mixer_linux.cc @@ -494,8 +521,9 @@ void QtUi::AddNativeColorMixer(ui::ColorProvider* provider, ColorState::kInactive}, {ui::kColorNativeToolbarBackground, ColorType::kButtonBg}, }; - for (const auto& map : kMaps) + for (const auto& map : kMaps) { mixer[map.id] = {shim_->GetColor(map.role, map.state)}; + } const bool use_custom_frame = key.frame_type == ui::ColorProviderManager::FrameType::kChromium; @@ -578,6 +606,20 @@ absl::optional QtUi::GetColor(int id, bool use_custom_frame) const { } } +DISABLE_CFI_VCALL +void QtUi::ScaleFactorMaybeChangedImpl() { + scale_factor_task_active_ = false; + double scale = shim_->GetScaleFactor(); + if (scale == scale_factor_) { + return; + } + scale_factor_ = scale; + for (ui::DeviceScaleFactorObserver& observer : + device_scale_factor_observer_list()) { + observer.OnDeviceScaleFactorChanged(); + } +} + std::unique_ptr CreateQtUi( ui::LinuxUi* fallback_linux_ui) { return std::make_unique(fallback_linux_ui); diff --git a/ui/qt/qt_ui.h b/ui/qt/qt_ui.h index b53ed93240708..3319edf1ea9bc 100644 --- a/ui/qt/qt_ui.h +++ b/ui/qt/qt_ui.h @@ -8,6 +8,7 @@ #include #include "base/component_export.h" +#include "base/memory/weak_ptr.h" #include "printing/buildflags/buildflags.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/color/color_provider.h" @@ -88,11 +89,14 @@ class QtUi : public ui::LinuxUiAndTheme, QtInterface::Delegate { // QtInterface::Delegate: void FontChanged() override; void ThemeChanged() override; + void ScaleFactorMaybeChanged() override; private: void AddNativeColorMixer(ui::ColorProvider* provider, const ui::ColorProviderManager::Key& key); + void ScaleFactorMaybeChangedImpl(); + absl::optional GetColor(int id, bool use_custom_frame) const; // TODO(https://crbug.com/1317782): This is a fallback for any unimplemented @@ -114,6 +118,11 @@ class QtUi : public ui::LinuxUiAndTheme, QtInterface::Delegate { std::unique_ptr shim_; std::unique_ptr native_theme_; + + bool scale_factor_task_active_ = false; + double scale_factor_ = 1.0; + + base::WeakPtrFactory weak_factory_{this}; }; // This should be the only symbol exported from this component.