diff options
Diffstat (limited to 'src/plugins/platforms/windows/qwindowssystemtrayicon.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowssystemtrayicon.cpp | 78 |
1 files changed, 51 insertions, 27 deletions
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index cf150b5772..6f0680ac23 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -1,13 +1,7 @@ // Copyright (C) 2017 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#ifndef WINVER -# define WINVER 0x0A00 // required for NOTIFYICONDATA_V2_SIZE, ChangeWindowMessageFilterEx() (MinGW 5.3) -#endif - -#ifndef NTDDI_VERSION -# define NTDDI_VERSION 0x0A00000B // required for Shell_NotifyIconGetRect (MinGW 5.3) -#endif +#include <QtCore/qt_windows.h> #include "qwindowssystemtrayicon.h" #include "qwindowscontext.h" @@ -23,7 +17,6 @@ #include <QtCore/qsettings.h> #include <qpa/qwindowsysteminterface.h> -#include <qt_windows.h> #include <commctrl.h> #include <shellapi.h> #include <shlobj.h> @@ -31,6 +24,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::Literals::StringLiterals; + static const UINT q_uNOTIFYICONID = 0; static uint MYWM_TASKBARCREATED = 0; @@ -123,7 +118,7 @@ static inline HWND createTrayIconMessageWindow() return nullptr; // Register window class in the platform plugin. const QString className = - ctx->registerWindowClass(QWindowsContext::classNamePrefix() + QStringLiteral("TrayIconMessageWindowClass"), + ctx->registerWindowClass(QWindowsContext::classNamePrefix() + "TrayIconMessageWindowClass"_L1, qWindowsTrayIconWndProc); const wchar_t windowName[] = L"QTrayIconMessageWindow"; return CreateWindowEx(0, reinterpret_cast<const wchar_t *>(className.utf16()), @@ -169,8 +164,7 @@ void QWindowsSystemTrayIcon::cleanup() void QWindowsSystemTrayIcon::updateIcon(const QIcon &icon) { qCDebug(lcQpaTrayIcon) << __FUNCTION__ << '(' << icon << ')' << this; - if (icon.cacheKey() == m_icon.cacheKey()) - return; + m_icon = icon; const HICON hIconToDestroy = createIcon(icon); if (ensureInstalled()) sendTrayMessage(NIM_MODIFY); @@ -190,6 +184,9 @@ void QWindowsSystemTrayIcon::updateToolTip(const QString &tooltip) QRect QWindowsSystemTrayIcon::geometry() const { + if (!isIconVisible()) + return QRect(); + NOTIFYICONIDENTIFIER nid; memset(&nid, 0, sizeof(nid)); nid.cbSize = sizeof(nid); @@ -223,25 +220,19 @@ void QWindowsSystemTrayIcon::showMessage(const QString &title, const QString &me qStringToLimitedWCharArray(title, tnd.szInfoTitle, 64); tnd.uID = q_uNOTIFYICONID; - tnd.dwInfoFlags = NIIF_USER; - - QSize size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); - const QSize largeIcon(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); - const QSize more = icon.actualSize(largeIcon); - if (more.height() > (largeIcon.height() * 3/4) || more.width() > (largeIcon.width() * 3/4)) { - tnd.dwInfoFlags |= NIIF_LARGE_ICON; - size = largeIcon; - } + + const auto size = icon.actualSize(QSize(256, 256)); QPixmap pm = icon.pixmap(size); + if (m_hMessageIcon) { + DestroyIcon(m_hMessageIcon); + m_hMessageIcon = nullptr; + } if (pm.isNull()) { tnd.dwInfoFlags = NIIF_INFO; } else { - if (pm.size() != size) { - qWarning("QSystemTrayIcon::showMessage: Wrong icon size (%dx%d), please add standard one: %dx%d", - pm.size().width(), pm.size().height(), size.width(), size.height()); - pm = pm.scaled(size, Qt::IgnoreAspectRatio); - } - tnd.hBalloonIcon = qt_pixmapToWinHICON(pm); + tnd.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; + m_hMessageIcon = qt_pixmapToWinHICON(pm); + tnd.hBalloonIcon = m_hMessageIcon; } tnd.hWnd = m_hwnd; tnd.uTimeout = msecsIn <= 0 ? UINT(10000) : UINT(msecsIn); // 10s default @@ -299,7 +290,10 @@ void QWindowsSystemTrayIcon::ensureCleanup() } if (m_hIcon != nullptr) DestroyIcon(m_hIcon); + if (m_hMessageIcon != nullptr) + DestroyIcon(m_hMessageIcon); m_hIcon = nullptr; + m_hMessageIcon = nullptr; m_menu = nullptr; // externally owned m_toolTip.clear(); } @@ -316,6 +310,29 @@ bool QWindowsSystemTrayIcon::setIconVisible(bool visible) return Shell_NotifyIcon(NIM_MODIFY, &tnd) == TRUE; } +bool QWindowsSystemTrayIcon::isIconVisible() const +{ + NOTIFYICONIDENTIFIER nid; + memset(&nid, 0, sizeof(nid)); + nid.cbSize = sizeof(nid); + nid.hWnd = m_hwnd; + nid.uID = q_uNOTIFYICONID; + RECT rect; + const HRESULT hr = Shell_NotifyIconGetRect(&nid, &rect); + // Windows 10 returns S_FALSE if the icon is hidden + if (FAILED(hr) || hr == S_FALSE) + return false; + + HMONITOR monitor = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST); + MONITORINFO info; + info.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(monitor, &info); + // Windows 11 seems to return a geometry outside of the current monitor's geometry in case of + // the icon being hidden. As it's impossible to change the alignment of the task bar on Windows + // 11 this check should be fine. + return rect.bottom <= info.rcMonitor.bottom; +} + bool QWindowsSystemTrayIcon::sendTrayMessage(DWORD msg) { NOTIFYICONDATA tnd; @@ -409,8 +426,15 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result) QWindowsPopupMenu::notifyTriggered(LOWORD(message.wParam)); break; default: - if (message.message == MYWM_TASKBARCREATED) // self-registered message id (tray crashed) + if (message.message == MYWM_TASKBARCREATED) { + // self-registered message id to handle that + // - screen resolution/DPR changed + const QIcon oldIcon = m_icon; + m_icon = QIcon(); // updateIcon is a no-op if the icon doesn't change + updateIcon(oldIcon); + // - or tray crashed sendTrayMessage(NIM_ADD); + } break; } return false; |