From 38164411f02331250d64033360ce5d0bc8c33a7a Mon Sep 17 00:00:00 2001 From: Dan Klishch Date: Fri, 26 Jan 2024 23:14:41 -0500 Subject: [PATCH] Ladybird/Qt: Properly listen for DPI changes on Wayland Some Wayland compositors have support of fractional-scale-v1 protocol. The protocol allows compositor to announce a preferred fractional scale on a per-wl_surface basis. Qt forwards these Wayland events to an application using a usual DevicePixelRatioChange event. However, in contrast to the other platforms, this DevicePixelRatioChange event is issued directly on widgets and not screens. Additionally, the exact fractional scale is stored in QWindow object and not the current screen. Note that in theory it is possible to obtain per-screen fractional scaling on Wayland by interpolating data provided by wl_output and xdg_output events but qtwayland does not do that. If fractional-scale-v1 is not available, qtwayland will still fire per-Widget DevicePixelRatioChange events, but, obviously, with the per-screen possibly larger ceiled scaling. This whole thing makes handling DPI changes on Wayland really simple. All we need to do is to intercept DevicePixelRatioChange events firing on QWindow objects and call the old device_pixel_ratio_changed handler with the window's devicePixelRatio(). The only caveat here is not forget to always set QWidget's parent before calling devicePixelRatio() on it. --- Ladybird/Qt/BrowserWindow.cpp | 36 ++++++++++++++++++++---------- Ladybird/Qt/BrowserWindow.h | 1 + Ladybird/Qt/InspectorWidget.cpp | 39 +++++++++++++++++++++++---------- Ladybird/Qt/InspectorWidget.h | 1 + Ladybird/Qt/Tab.cpp | 2 +- Ladybird/Qt/WebContentView.cpp | 5 +++-- Ladybird/Qt/WebContentView.h | 2 +- 7 files changed, 59 insertions(+), 27 deletions(-) diff --git a/Ladybird/Qt/BrowserWindow.cpp b/Ladybird/Qt/BrowserWindow.cpp index badbc34642..e6e900ec9a 100644 --- a/Ladybird/Qt/BrowserWindow.cpp +++ b/Ladybird/Qt/BrowserWindow.cpp @@ -57,20 +57,22 @@ BrowserWindow::BrowserWindow(Vector const& initial_urls, WebView::CookieJar m_tabs_container->setTabBarAutoHide(true); // Listen for DPI changes - setAttribute(Qt::WA_NativeWindow); - setAttribute(Qt::WA_DontCreateNativeAncestors); m_device_pixel_ratio = devicePixelRatio(); m_current_screen = screen(); - QObject::connect(m_current_screen, &QScreen::logicalDotsPerInchChanged, this, &BrowserWindow::device_pixel_ratio_changed); - QObject::connect(windowHandle(), &QWindow::screenChanged, this, [this](QScreen* screen) { - if (m_device_pixel_ratio != screen->devicePixelRatio()) - device_pixel_ratio_changed(screen->devicePixelRatio()); - - // Listen for logicalDotsPerInchChanged signals on new screen - QObject::disconnect(m_current_screen, &QScreen::logicalDotsPerInchChanged, nullptr, nullptr); - m_current_screen = screen; + if (QT_VERSION < QT_VERSION_CHECK(6, 6, 0) || QGuiApplication::platformName() != "wayland") { + setAttribute(Qt::WA_NativeWindow); + setAttribute(Qt::WA_DontCreateNativeAncestors); QObject::connect(m_current_screen, &QScreen::logicalDotsPerInchChanged, this, &BrowserWindow::device_pixel_ratio_changed); - }); + QObject::connect(windowHandle(), &QWindow::screenChanged, this, [this](QScreen* screen) { + if (m_device_pixel_ratio != devicePixelRatio()) + device_pixel_ratio_changed(devicePixelRatio()); + + // Listen for logicalDotsPerInchChanged signals on new screen + QObject::disconnect(m_current_screen, &QScreen::logicalDotsPerInchChanged, nullptr, nullptr); + m_current_screen = screen; + QObject::connect(m_current_screen, &QScreen::logicalDotsPerInchChanged, this, &BrowserWindow::device_pixel_ratio_changed); + }); + } auto* menu = menuBar()->addMenu("&File"); @@ -737,6 +739,18 @@ void BrowserWindow::copy_selected_text() clipboard->setText(qstring_from_ak_string(text)); } +bool BrowserWindow::event(QEvent* event) +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) + if (event->type() == QEvent::DevicePixelRatioChange) { + if (m_device_pixel_ratio != devicePixelRatio()) + device_pixel_ratio_changed(devicePixelRatio()); + } +#endif + + return QMainWindow::event(event); +} + void BrowserWindow::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); diff --git a/Ladybird/Qt/BrowserWindow.h b/Ladybird/Qt/BrowserWindow.h index 0bd6d79954..0aa634ef29 100644 --- a/Ladybird/Qt/BrowserWindow.h +++ b/Ladybird/Qt/BrowserWindow.h @@ -96,6 +96,7 @@ protected: bool eventFilter(QObject* obj, QEvent* event) override; private: + virtual bool event(QEvent*) override; virtual void resizeEvent(QResizeEvent*) override; virtual void moveEvent(QMoveEvent*) override; virtual void wheelEvent(QWheelEvent*) override; diff --git a/Ladybird/Qt/InspectorWidget.cpp b/Ladybird/Qt/InspectorWidget.cpp index ce8d9df996..d083d081a6 100644 --- a/Ladybird/Qt/InspectorWidget.cpp +++ b/Ladybird/Qt/InspectorWidget.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,7 @@ extern bool is_using_dark_system_theme(QWidget&); InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view) : QWidget(tab, Qt::Window) { - m_inspector_view = new WebContentView({}, {}); + m_inspector_view = new WebContentView(this, {}, {}); if (is_using_dark_system_theme(*this)) m_inspector_view->update_palette(WebContentView::PaletteMode::Dark); @@ -126,20 +127,22 @@ InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view) resize(875, 825); // Listen for DPI changes - setAttribute(Qt::WA_NativeWindow); - setAttribute(Qt::WA_DontCreateNativeAncestors); m_device_pixel_ratio = devicePixelRatio(); m_current_screen = screen(); - QObject::connect(m_current_screen, &QScreen::logicalDotsPerInchChanged, this, &InspectorWidget::device_pixel_ratio_changed); - QObject::connect(windowHandle(), &QWindow::screenChanged, this, [this](QScreen* screen) { - if (m_device_pixel_ratio != screen->devicePixelRatio()) - device_pixel_ratio_changed(screen->devicePixelRatio()); - - // Listen for logicalDotsPerInchChanged signals on new screen - QObject::disconnect(m_current_screen, &QScreen::logicalDotsPerInchChanged, nullptr, nullptr); - m_current_screen = screen; + if (QT_VERSION < QT_VERSION_CHECK(6, 6, 0) || QGuiApplication::platformName() != "wayland") { + setAttribute(Qt::WA_NativeWindow); + setAttribute(Qt::WA_DontCreateNativeAncestors); QObject::connect(m_current_screen, &QScreen::logicalDotsPerInchChanged, this, &InspectorWidget::device_pixel_ratio_changed); - }); + QObject::connect(windowHandle(), &QWindow::screenChanged, this, [this](QScreen* screen) { + if (m_device_pixel_ratio != screen->devicePixelRatio()) + device_pixel_ratio_changed(screen->devicePixelRatio()); + + // Listen for logicalDotsPerInchChanged signals on new screen + QObject::disconnect(m_current_screen, &QScreen::logicalDotsPerInchChanged, nullptr, nullptr); + m_current_screen = screen; + QObject::connect(m_current_screen, &QScreen::logicalDotsPerInchChanged, this, &InspectorWidget::device_pixel_ratio_changed); + }); + } } InspectorWidget::~InspectorWidget() = default; @@ -170,6 +173,18 @@ void InspectorWidget::device_pixel_ratio_changed(qreal dpi) m_inspector_view->set_device_pixel_ratio(m_device_pixel_ratio); } +bool InspectorWidget::event(QEvent* event) +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) + if (event->type() == QEvent::DevicePixelRatioChange) { + if (m_device_pixel_ratio != devicePixelRatio()) + device_pixel_ratio_changed(devicePixelRatio()); + } +#endif + + return QWidget::event(event); +} + void InspectorWidget::closeEvent(QCloseEvent* event) { event->accept(); diff --git a/Ladybird/Qt/InspectorWidget.h b/Ladybird/Qt/InspectorWidget.h index b1400d2ea3..78483ec23c 100644 --- a/Ladybird/Qt/InspectorWidget.h +++ b/Ladybird/Qt/InspectorWidget.h @@ -35,6 +35,7 @@ public slots: void device_pixel_ratio_changed(qreal dpi); private: + bool event(QEvent*) override; void closeEvent(QCloseEvent*) override; QPoint to_widget_position(Gfx::IntPoint) const; diff --git a/Ladybird/Qt/Tab.cpp b/Ladybird/Qt/Tab.cpp index 4521c1e4df..40c8669bc2 100644 --- a/Ladybird/Qt/Tab.cpp +++ b/Ladybird/Qt/Tab.cpp @@ -61,7 +61,7 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St m_layout->setSpacing(0); m_layout->setContentsMargins(0, 0, 0, 0); - m_view = new WebContentView(web_content_options, webdriver_content_ipc_path, parent_client, page_index); + m_view = new WebContentView(this, web_content_options, webdriver_content_ipc_path, parent_client, page_index); m_toolbar = new QToolBar(this); m_location_edit = new LocationEdit(this); diff --git a/Ladybird/Qt/WebContentView.cpp b/Ladybird/Qt/WebContentView.cpp index 78dd6002ad..d4480886da 100644 --- a/Ladybird/Qt/WebContentView.cpp +++ b/Ladybird/Qt/WebContentView.cpp @@ -54,8 +54,9 @@ namespace Ladybird { bool is_using_dark_system_theme(QWidget&); -WebContentView::WebContentView(WebContentOptions const& web_content_options, StringView webdriver_content_ipc_path, RefPtr parent_client, size_t page_index) - : m_web_content_options(web_content_options) +WebContentView::WebContentView(QWidget* window, WebContentOptions const& web_content_options, StringView webdriver_content_ipc_path, RefPtr parent_client, size_t page_index) + : QAbstractScrollArea(window) + , m_web_content_options(web_content_options) , m_webdriver_content_ipc_path(webdriver_content_ipc_path) { m_client_state.client = parent_client; diff --git a/Ladybird/Qt/WebContentView.h b/Ladybird/Qt/WebContentView.h index 1bfe1c61f5..fb6b526657 100644 --- a/Ladybird/Qt/WebContentView.h +++ b/Ladybird/Qt/WebContentView.h @@ -42,7 +42,7 @@ class WebContentView final , public WebView::ViewImplementation { Q_OBJECT public: - WebContentView(WebContentOptions const&, StringView webdriver_content_ipc_path, RefPtr parent_client = nullptr, size_t page_index = 0); + WebContentView(QWidget* window, WebContentOptions const&, StringView webdriver_content_ipc_path, RefPtr parent_client = nullptr, size_t page_index = 0); virtual ~WebContentView() override; Function on_tab_open_request;