Support large custom icons for the system tray balloon notification
Modern platforms such as macOS and Windows support large fancy icons in the system balloon notification. We just need to pass the icon into platform plugin. [ChangeLog][QtWidgets][QSystemTrayIcon] Support custom icons in showMessage() Task-number: QTBUG-49283 Change-Id: Iaeca36fe1bf350eae34d105549010ecbedf9c0a1 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
parent
39a2eed039
commit
e8892c7e7a
@ -161,10 +161,16 @@ void Window::iconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
void Window::showMessage()
|
||||
{
|
||||
showIconCheckBox->setChecked(true);
|
||||
QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon(
|
||||
QSystemTrayIcon::MessageIcon msgIcon = QSystemTrayIcon::MessageIcon(
|
||||
typeComboBox->itemData(typeComboBox->currentIndex()).toInt());
|
||||
trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), icon,
|
||||
if (msgIcon == QSystemTrayIcon::NoIcon) {
|
||||
QIcon icon(iconComboBox->itemIcon(iconComboBox->currentIndex()));
|
||||
trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), icon,
|
||||
durationSpinBox->value() * 1000);
|
||||
} else {
|
||||
trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), msgIcon,
|
||||
durationSpinBox->value() * 1000);
|
||||
}
|
||||
}
|
||||
//! [5]
|
||||
|
||||
@ -216,6 +222,8 @@ void Window::createMessageGroupBox()
|
||||
typeComboBox->addItem(style()->standardIcon(
|
||||
QStyle::SP_MessageBoxCritical), tr("Critical"),
|
||||
QSystemTrayIcon::Critical);
|
||||
typeComboBox->addItem(QIcon(), tr("Custom icon"),
|
||||
QSystemTrayIcon::NoIcon);
|
||||
typeComboBox->setCurrentIndex(1);
|
||||
|
||||
durationLabel = new QLabel(tr("Duration:"));
|
||||
|
@ -59,6 +59,25 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static QIcon messageIcon2qIcon(QSystemTrayIcon::MessageIcon icon)
|
||||
{
|
||||
QStyle::StandardPixmap stdIcon;
|
||||
switch (icon) {
|
||||
case QSystemTrayIcon::Information:
|
||||
stdIcon = QStyle::SP_MessageBoxInformation;
|
||||
break;
|
||||
case QSystemTrayIcon::Warning:
|
||||
stdIcon = QStyle::SP_MessageBoxWarning;
|
||||
break;
|
||||
case QSystemTrayIcon::Critical:
|
||||
stdIcon = QStyle::SP_MessageBoxCritical;
|
||||
break;
|
||||
case QSystemTrayIcon::NoIcon:
|
||||
return QIcon();
|
||||
}
|
||||
return QApplication::style()->standardIcon(stdIcon);
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QSystemTrayIcon
|
||||
\brief The QSystemTrayIcon class provides an icon for an application in the system tray.
|
||||
@ -382,11 +401,29 @@ bool QSystemTrayIcon::supportsMessages()
|
||||
\sa show(), supportsMessages()
|
||||
*/
|
||||
void QSystemTrayIcon::showMessage(const QString& title, const QString& msg,
|
||||
QSystemTrayIcon::MessageIcon icon, int msecs)
|
||||
QSystemTrayIcon::MessageIcon msgIcon, int msecs)
|
||||
{
|
||||
Q_D(QSystemTrayIcon);
|
||||
if (d->visible)
|
||||
d->showMessage_sys(title, msg, icon, msecs);
|
||||
d->showMessage_sys(title, msg, messageIcon2qIcon(msgIcon), msgIcon, msecs);
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn void QSystemTrayIcon::showMessage(const QString &title, const QString &message, const QIcon &icon, int millisecondsTimeoutHint)
|
||||
|
||||
\overload showMessage()
|
||||
|
||||
Shows a balloon message for the entry with the given \a title, \a message,
|
||||
and custom icon \a icon for the time specified in \a millisecondsTimeoutHint.
|
||||
|
||||
\since 5.9
|
||||
*/
|
||||
void QSystemTrayIcon::showMessage(const QString &title, const QString &msg,
|
||||
const QIcon &icon, int msecs)
|
||||
{
|
||||
Q_D(QSystemTrayIcon);
|
||||
if (d->visible)
|
||||
d->showMessage_sys(title, msg, icon, QSystemTrayIcon::NoIcon, msecs);
|
||||
}
|
||||
|
||||
void QSystemTrayIconPrivate::_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason reason)
|
||||
@ -398,9 +435,9 @@ void QSystemTrayIconPrivate::_q_emitActivated(QPlatformSystemTrayIcon::Activatio
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
static QBalloonTip *theSolitaryBalloonTip = 0;
|
||||
|
||||
void QBalloonTip::showBalloon(QSystemTrayIcon::MessageIcon icon, const QString& title,
|
||||
const QString& message, QSystemTrayIcon *trayIcon,
|
||||
const QPoint& pos, int timeout, bool showArrow)
|
||||
void QBalloonTip::showBalloon(const QIcon &icon, const QString &title,
|
||||
const QString &message, QSystemTrayIcon *trayIcon,
|
||||
const QPoint &pos, int timeout, bool showArrow)
|
||||
{
|
||||
hideBalloon();
|
||||
if (message.isEmpty() && title.isEmpty())
|
||||
@ -434,8 +471,8 @@ bool QBalloonTip::isBalloonVisible()
|
||||
return theSolitaryBalloonTip;
|
||||
}
|
||||
|
||||
QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title,
|
||||
const QString& message, QSystemTrayIcon *ti)
|
||||
QBalloonTip::QBalloonTip(const QIcon &icon, const QString &title,
|
||||
const QString &message, QSystemTrayIcon *ti)
|
||||
: QWidget(0, Qt::ToolTip), trayIcon(ti), timerId(-1)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
@ -482,26 +519,10 @@ QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title
|
||||
msgLabel->setFixedSize(limit, msgLabel->heightForWidth(limit));
|
||||
}
|
||||
|
||||
QIcon si;
|
||||
switch (icon) {
|
||||
case QSystemTrayIcon::Warning:
|
||||
si = style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
||||
break;
|
||||
case QSystemTrayIcon::Critical:
|
||||
si = style()->standardIcon(QStyle::SP_MessageBoxCritical);
|
||||
break;
|
||||
case QSystemTrayIcon::Information:
|
||||
si = style()->standardIcon(QStyle::SP_MessageBoxInformation);
|
||||
break;
|
||||
case QSystemTrayIcon::NoIcon:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
if (!si.isNull()) {
|
||||
if (!icon.isNull()) {
|
||||
QLabel *iconLabel = new QLabel;
|
||||
iconLabel->setPixmap(si.pixmap(iconSize, iconSize));
|
||||
iconLabel->setPixmap(icon.pixmap(iconSize, iconSize));
|
||||
iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
iconLabel->setMargin(2);
|
||||
layout->addWidget(iconLabel, 0, 0);
|
||||
@ -703,25 +724,12 @@ void QSystemTrayIconPrivate::updateToolTip_sys_qpa()
|
||||
|
||||
void QSystemTrayIconPrivate::showMessage_sys_qpa(const QString &title,
|
||||
const QString &message,
|
||||
QSystemTrayIcon::MessageIcon icon,
|
||||
const QIcon &icon,
|
||||
QSystemTrayIcon::MessageIcon msgIcon,
|
||||
int msecs)
|
||||
{
|
||||
QIcon notificationIcon;
|
||||
switch (icon) {
|
||||
case QSystemTrayIcon::Information:
|
||||
notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
|
||||
break;
|
||||
case QSystemTrayIcon::Warning:
|
||||
notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
||||
break;
|
||||
case QSystemTrayIcon::Critical:
|
||||
notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
qpa_sys->showMessage(title, message, notificationIcon,
|
||||
static_cast<QPlatformSystemTrayIcon::MessageIcon>(icon), msecs);
|
||||
qpa_sys->showMessage(title, message, icon,
|
||||
static_cast<QPlatformSystemTrayIcon::MessageIcon>(msgIcon), msecs);
|
||||
}
|
||||
|
||||
void QSystemTrayIconPrivate::addPlatformMenu(QMenu *menu) const
|
||||
|
@ -101,6 +101,7 @@ public Q_SLOTS:
|
||||
void setVisible(bool visible);
|
||||
inline void show() { setVisible(true); }
|
||||
inline void hide() { setVisible(false); }
|
||||
void showMessage(const QString &title, const QString &msg, const QIcon &icon, int msecs = 10000);
|
||||
void showMessage(const QString &title, const QString &msg,
|
||||
QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 10000);
|
||||
|
||||
|
@ -84,7 +84,8 @@ public:
|
||||
void updateToolTip_sys();
|
||||
void updateMenu_sys();
|
||||
QRect geometry_sys() const;
|
||||
void showMessage_sys(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon, int secs);
|
||||
void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon,
|
||||
QSystemTrayIcon::MessageIcon msgIcon, int msecs);
|
||||
|
||||
static bool isSystemTrayAvailable_sys();
|
||||
static bool supportsMessages_sys();
|
||||
@ -105,7 +106,8 @@ private:
|
||||
void updateToolTip_sys_qpa();
|
||||
void updateMenu_sys_qpa();
|
||||
QRect geometry_sys_qpa() const;
|
||||
void showMessage_sys_qpa(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon, int secs);
|
||||
void showMessage_sys_qpa(const QString &title, const QString &msg, const QIcon &icon,
|
||||
QSystemTrayIcon::MessageIcon msgIcon, int msecs);
|
||||
void addPlatformMenu(QMenu *menu) const;
|
||||
};
|
||||
|
||||
@ -113,16 +115,16 @@ class QBalloonTip : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static void showBalloon(QSystemTrayIcon::MessageIcon icon, const QString& title,
|
||||
const QString& msg, QSystemTrayIcon *trayIcon,
|
||||
const QPoint& pos, int timeout, bool showArrow = true);
|
||||
static void showBalloon(const QIcon &icon, const QString &title,
|
||||
const QString &msg, QSystemTrayIcon *trayIcon,
|
||||
const QPoint &pos, int timeout, bool showArrow = true);
|
||||
static void hideBalloon();
|
||||
static bool isBalloonVisible();
|
||||
static void updateBalloonPosition(const QPoint& pos);
|
||||
|
||||
private:
|
||||
QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title,
|
||||
const QString& msg, QSystemTrayIcon *trayIcon);
|
||||
QBalloonTip(const QIcon &icon, const QString &title,
|
||||
const QString &msg, QSystemTrayIcon *trayIcon);
|
||||
~QBalloonTip();
|
||||
void balloon(const QPoint&, int, bool);
|
||||
|
||||
|
@ -118,10 +118,10 @@ bool QSystemTrayIconPrivate::supportsMessages_sys()
|
||||
}
|
||||
|
||||
void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message,
|
||||
QSystemTrayIcon::MessageIcon icon, int msecs)
|
||||
const QIcon &icon, QSystemTrayIcon::MessageIcon msgIcon, int msecs)
|
||||
{
|
||||
if (qpa_sys)
|
||||
showMessage_sys_qpa(title, message, icon, msecs);
|
||||
showMessage_sys_qpa(title, message, icon, msgIcon, msecs);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -81,11 +81,14 @@ struct Q_NOTIFYICONIDENTIFIER {
|
||||
# define NIN_BALLOONTIMEOUT (WM_USER + 4)
|
||||
# define NIN_BALLOONUSERCLICK (WM_USER + 5)
|
||||
# define NIF_SHOWTIP 0x00000080
|
||||
# define NIIF_LARGE_ICON 0x00000020
|
||||
# define NOTIFYICON_VERSION_4 4
|
||||
#endif
|
||||
|
||||
#define Q_MSGFLT_ALLOW 1
|
||||
|
||||
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
|
||||
|
||||
typedef HRESULT (WINAPI *PtrShell_NotifyIconGetRect)(const Q_NOTIFYICONIDENTIFIER* identifier, RECT* iconLocation);
|
||||
typedef BOOL (WINAPI *PtrChangeWindowMessageFilter)(UINT message, DWORD dwFlag);
|
||||
typedef BOOL (WINAPI *PtrChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD action, void* pChangeFilterStruct);
|
||||
@ -107,7 +110,7 @@ public:
|
||||
~QSystemTrayIconSys();
|
||||
bool trayMessage(DWORD msg);
|
||||
void setIconContents(NOTIFYICONDATA &data);
|
||||
bool showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs);
|
||||
bool showMessage(const QString &title, const QString &message, const QIcon &icon, uint uSecs);
|
||||
QRect findIconGeometry(UINT iconId);
|
||||
HICON createIcon();
|
||||
bool winEvent(MSG *m, long *result);
|
||||
@ -184,7 +187,7 @@ static inline HWND createTrayIconMessageWindow()
|
||||
|
||||
QSystemTrayIconSys::QSystemTrayIconSys(HWND hwnd, QSystemTrayIcon *object)
|
||||
: m_hwnd(hwnd), hIcon(0), q(object)
|
||||
, notifyIconSize(NOTIFYICONDATA_V2_SIZE), version(NOTIFYICON_VERSION)
|
||||
, notifyIconSize(sizeof(NOTIFYICONDATA)), version(NOTIFYICON_VERSION_4)
|
||||
, ignoreNextMouseRelease(false)
|
||||
|
||||
{
|
||||
@ -237,11 +240,7 @@ void QSystemTrayIconSys::setIconContents(NOTIFYICONDATA &tnd)
|
||||
qStringToLimitedWCharArray(tip, tnd.szTip, sizeof(tnd.szTip)/sizeof(wchar_t));
|
||||
}
|
||||
|
||||
#ifndef NIIF_LARGE_ICON
|
||||
# define NIIF_LARGE_ICON 0x00000020
|
||||
#endif
|
||||
|
||||
bool QSystemTrayIconSys::showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs)
|
||||
bool QSystemTrayIconSys::showMessage(const QString &title, const QString &message, const QIcon &icon, uint uSecs)
|
||||
{
|
||||
NOTIFYICONDATA tnd;
|
||||
memset(&tnd, 0, notifyIconSize);
|
||||
@ -249,23 +248,32 @@ bool QSystemTrayIconSys::showMessage(const QString &title, const QString &messag
|
||||
qStringToLimitedWCharArray(title, tnd.szInfoTitle, 64);
|
||||
|
||||
tnd.uID = q_uNOTIFYICONID;
|
||||
switch (type) {
|
||||
case QSystemTrayIcon::Information:
|
||||
tnd.dwInfoFlags = NIIF_INFO;
|
||||
break;
|
||||
case QSystemTrayIcon::Warning:
|
||||
tnd.dwInfoFlags = NIIF_WARNING;
|
||||
break;
|
||||
case QSystemTrayIcon::Critical:
|
||||
tnd.dwInfoFlags = NIIF_ERROR;
|
||||
break;
|
||||
case QSystemTrayIcon::NoIcon:
|
||||
tnd.dwInfoFlags = hIcon ? NIIF_USER : NIIF_NONE;
|
||||
break;
|
||||
tnd.dwInfoFlags = NIIF_USER;
|
||||
|
||||
HICON *phIcon = &tnd.hIcon;
|
||||
QSize size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
|
||||
if (version == NOTIFYICON_VERSION_4) {
|
||||
const QSize largeIcon(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
|
||||
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;
|
||||
}
|
||||
phIcon = &tnd.hBalloonIcon;
|
||||
}
|
||||
QPixmap pm = icon.pixmap(size);
|
||||
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);
|
||||
}
|
||||
*phIcon = qt_pixmapToWinHICON(pm);
|
||||
}
|
||||
if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
|
||||
tnd.dwInfoFlags |= NIIF_LARGE_ICON;
|
||||
tnd.cbSize = notifyIconSize;
|
||||
tnd.uVersion = version;
|
||||
tnd.hWnd = m_hwnd;
|
||||
tnd.uTimeout = uSecs;
|
||||
tnd.uFlags = NIF_INFO | NIF_SHOWTIP;
|
||||
@ -296,8 +304,6 @@ bool QSystemTrayIconSys::trayMessage(DWORD msg)
|
||||
return success;
|
||||
}
|
||||
|
||||
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
|
||||
|
||||
HICON QSystemTrayIconSys::createIcon()
|
||||
{
|
||||
const HICON oldIcon = hIcon;
|
||||
@ -509,7 +515,8 @@ QRect QSystemTrayIconSys::findIconGeometry(UINT iconId)
|
||||
|
||||
void QSystemTrayIconPrivate::showMessage_sys(const QString &title,
|
||||
const QString &messageIn,
|
||||
QSystemTrayIcon::MessageIcon type,
|
||||
const QIcon &icon,
|
||||
QSystemTrayIcon::MessageIcon,
|
||||
int timeOut)
|
||||
{
|
||||
if (!sys || !allowsMessages())
|
||||
@ -522,7 +529,7 @@ void QSystemTrayIconPrivate::showMessage_sys(const QString &title,
|
||||
if (message.isEmpty() && !title.isEmpty())
|
||||
message.append(QLatin1Char(' '));
|
||||
|
||||
sys->showMessage(title, message, type, uSecs);
|
||||
sys->showMessage(title, message, icon, uSecs);
|
||||
}
|
||||
|
||||
QRect QSystemTrayIconPrivate::geometry_sys() const
|
||||
|
@ -357,10 +357,10 @@ bool QSystemTrayIconPrivate::supportsMessages_sys()
|
||||
}
|
||||
|
||||
void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message,
|
||||
QSystemTrayIcon::MessageIcon icon, int msecs)
|
||||
const QIcon &icon, QSystemTrayIcon::MessageIcon msgIcon, int msecs)
|
||||
{
|
||||
if (qpa_sys) {
|
||||
showMessage_sys_qpa(title, message, icon, msecs);
|
||||
showMessage_sys_qpa(title, message, icon, msgIcon, msecs);
|
||||
return;
|
||||
}
|
||||
if (!sys)
|
||||
|
Loading…
x
Reference in New Issue
Block a user