Skip to content
Snippets Groups Projects

contrib: qtbase: add patch to fix pixelated notification icon

2 files
+ 62
0
Compare changes
  • Side-by-side
  • Inline
Files
2
From 241f6e9dcf1bba7c384f7f9752b9281122540589 Mon Sep 17 00:00:00 2001
From: Fatih Uzunoglu <fuzun54@outlook.com>
Date: Sat, 22 Feb 2025 20:37:29 +0200
Subject: [PATCH] QWindowsSystemTrayIcon: fix notification icon dpi handling
Using fixed 256x256 does not make any sense. It is not recommended,
and Windows downscales the bitmap without linear transformation
leading to pixelated results.
We should use the recommended `SM_CXICON`x`SM_CYICON`, which is
expected to be scaled as per the screen DPI since the application
is made DPI aware.
---
.../windows/qwindowssystemtrayicon.cpp | 31 +++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
index 11eb3507f9f..df3e35f21b0 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
@@ -226,8 +226,35 @@ void QWindowsSystemTrayIcon::showMessage(const QString &title, const QString &me
tnd.uID = q_uNOTIFYICONID;
- const auto size = icon.actualSize(QSize(256, 256));
- QPixmap pm = icon.pixmap(size);
+ // Qt makes the application DPI aware, `GetSystemMetrics()` is expected to take the screen
+ // dpi into account:
+ QSize size(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
+
+ // This is not official, but Windows 11 seems to display the icon at 50x50 with standard DPI,
+ // which is contrary to the recommended `SM_CXICON`/`SM_CYICON` that is 32x32 with standard
+ // DPI. We can pick the higher of 50x50 and `SM_CXICON`/`SMCYICON` to prevent upscaling.
+ const int min = std::ceil(50 * std::max((size.width() / 32.0), (size.height() / 32.0)));
+ if (size.width() < min || size.height() < min) {
+ const auto ratio = static_cast<qreal>(size.width()) / size.height();
+ // Do not spoil the aspect ratio:
+ if (ratio > 1.0) {
+ size.setWidth(std::ceil(min * ratio));
+ size.setHeight(min);
+ } else if (ratio < 1.0) {
+ size.setHeight(std::ceil(min / ratio));
+ size.setWidth(min);
+ } else {
+ size.setHeight(min);
+ size.setWidth(min);
+ }
+ }
+
+ // Use 1.0 as the DPR, because `QIcon` uses the screen (application) DPR (if not supplied),
+ // and we don't want the size to be manipulated based on that because the fed size already
+ // considers the screen DPR (as explained in the note above): `QIcon::pixmap()`: "The pixmap
+ // might be smaller than requested, but never larger, unless the device-pixel ratio of the
+ // returned pixmap is larger than 1."
+ QPixmap pm = icon.pixmap(size, 1.0);
if (m_hMessageIcon) {
DestroyIcon(m_hMessageIcon);
m_hMessageIcon = nullptr;
--
2.48.1
Loading