diff options
Diffstat (limited to 'src/plugins/platforms/windows/qwindowssystemtrayicon.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowssystemtrayicon.cpp | 129 |
1 files changed, 54 insertions, 75 deletions
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index 7c473e66b6..6f0680ac23 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -1,55 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#if defined(WINVER) && WINVER < 0x0601 -# undef WINVER -#endif -#if !defined(WINVER) -# define WINVER 0x0601 // required for NOTIFYICONDATA_V2_SIZE, ChangeWindowMessageFilterEx() (MinGW 5.3) -#endif - -#if defined(NTDDI_VERSION) && NTDDI_VERSION < 0x06010000 -# undef NTDDI_VERSION -#endif -#if !defined(NTDDI_VERSION) -# define NTDDI_VERSION 0x06010000 // required for Shell_NotifyIconGetRect (MinGW 5.3) -#endif +// 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 + +#include <QtCore/qt_windows.h> #include "qwindowssystemtrayicon.h" #include "qwindowscontext.h" @@ -65,7 +17,6 @@ #include <QtCore/qsettings.h> #include <qpa/qwindowsysteminterface.h> -#include <qt_windows.h> #include <commctrl.h> #include <shellapi.h> #include <shlobj.h> @@ -73,6 +24,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::Literals::StringLiterals; + static const UINT q_uNOTIFYICONID = 0; static uint MYWM_TASKBARCREATED = 0; @@ -136,9 +89,6 @@ static int indexOfHwnd(HWND hwnd) extern "C" LRESULT QT_WIN_CALLBACK qWindowsTrayIconWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - // QTBUG-79248: Trigger screen update if there are no other windows. - if (message == WM_DPICHANGED && QGuiApplication::topLevelWindows().isEmpty()) - QWindowsContext::instance()->screenManager().handleScreenChanges(); if (message == MYWM_TASKBARCREATED || message == MYWM_NOTIFYICON || message == WM_INITMENU || message == WM_INITMENUPOPUP || message == WM_CLOSE || message == WM_COMMAND) { @@ -168,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()), @@ -214,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); @@ -235,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); @@ -268,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 @@ -344,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(); } @@ -361,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; @@ -454,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; |