8#ifndef QT_NO_SYSTEMTRAYICON
18#include "private/qlabel_p.h"
20#if QT_CONFIG(pushbutton)
21#include "qpushbutton.h"
30#include <private/qhighdpiscaling_p.h>
31#include <qpa/qplatformscreen.h>
33using namespace std::chrono_literals;
37static QIcon messageIcon2qIcon(QSystemTrayIcon::MessageIcon icon)
39 QStyle::StandardPixmap stdIcon = QStyle::SP_CustomBase;
41 case QSystemTrayIcon::Information:
42 stdIcon = QStyle::SP_MessageBoxInformation;
44 case QSystemTrayIcon::Warning:
45 stdIcon = QStyle::SP_MessageBoxWarning;
47 case QSystemTrayIcon::Critical:
48 stdIcon = QStyle::SP_MessageBoxCritical;
50 case QSystemTrayIcon::NoIcon:
53 return QApplication::style()->standardIcon(stdIcon);
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
106
107
108
109
110
111
112
113
114
115
116
119
120
121
122
123
124
125QSystemTrayIcon::QSystemTrayIcon(QObject *parent)
126: QObject(*
new QSystemTrayIconPrivate(), parent)
131
132
133
134
135
136
137QSystemTrayIcon::QSystemTrayIcon(
const QIcon &icon, QObject *parent)
138 : QSystemTrayIcon(parent)
144
145
146QSystemTrayIcon::~QSystemTrayIcon()
148 Q_D(QSystemTrayIcon);
155
156
157
158
159
160
161
162
163
164void QSystemTrayIcon::setContextMenu(QMenu *menu)
166 Q_D(QSystemTrayIcon);
167 QMenu *oldMenu = d->menu.data();
176 if (oldMenu && !oldMenu->platformMenu())
177 QObject::disconnect(d->qpa_sys, &QPlatformSystemTrayIcon::contextMenuRequested, oldMenu,
nullptr);
178 if (menu && !menu->platformMenu()) {
179 QObject::connect(d->qpa_sys, &QPlatformSystemTrayIcon::contextMenuRequested,
181 [menu](QPoint globalNativePos,
const QPlatformScreen *platformScreen)
183 QScreen *screen = platformScreen ? platformScreen->screen() :
nullptr;
184 menu->popup(QHighDpi::fromNativePixels(globalNativePos, screen),
nullptr);
191
192
193QMenu* QSystemTrayIcon::contextMenu()
const
195 Q_D(
const QSystemTrayIcon);
202
203
204
205
206
207
208void QSystemTrayIcon::setIcon(
const QIcon &icon)
210 Q_D(QSystemTrayIcon);
215QIcon QSystemTrayIcon::icon()
const
217 Q_D(
const QSystemTrayIcon);
222
223
224
225
226
227
228void QSystemTrayIcon::setToolTip(
const QString &tooltip)
230 Q_D(QSystemTrayIcon);
231 d->toolTip = tooltip;
232 d->updateToolTip_sys();
235QString QSystemTrayIcon::toolTip()
const
237 Q_D(
const QSystemTrayIcon);
242
243
244
245
246
247
250
251
252
253
254
255
258
259
260
261
262
263QRect QSystemTrayIcon::geometry()
const
265 Q_D(
const QSystemTrayIcon);
268 return d->geometry_sys();
272
273
274
275
276
277
278void QSystemTrayIcon::setVisible(
bool visible)
280 Q_D(QSystemTrayIcon);
281 if (visible == d->visible)
283 if (Q_UNLIKELY(visible && d->icon.isNull()))
284 qWarning(
"QSystemTrayIcon::setVisible: No Icon set");
285 d->visible = visible;
292bool QSystemTrayIcon::isVisible()
const
294 Q_D(
const QSystemTrayIcon);
299
300
301bool QSystemTrayIcon::event(QEvent *e)
303 return QObject::event(e);
307
308
309
310
311
312
313
314
315
316
317
318
319
320
323
324
325
326
327
328
329
330
333
334
335
336
337
338
339
340
341
342
343
347
348
349
350
351
352
354bool QSystemTrayIcon::isSystemTrayAvailable()
356 return QSystemTrayIconPrivate::isSystemTrayAvailable_sys();
360
361
362
363
364bool QSystemTrayIcon::supportsMessages()
366 return QSystemTrayIconPrivate::supportsMessages_sys();
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391void QSystemTrayIcon::showMessage(
const QString& title,
const QString& msg,
392 QSystemTrayIcon::MessageIcon msgIcon,
int msecs)
394 Q_D(QSystemTrayIcon);
396 d->showMessage_sys(title, msg, messageIcon2qIcon(msgIcon), msgIcon, msecs);
400
401
402
403
404
405
406
407
408
409void QSystemTrayIcon::showMessage(
const QString &title,
const QString &msg,
410 const QIcon &icon,
int msecs)
412 Q_D(QSystemTrayIcon);
414 d->showMessage_sys(title, msg, icon, QSystemTrayIcon::NoIcon, msecs);
419 Q_Q(QSystemTrayIcon);
420 emit q->activated(
static_cast<QSystemTrayIcon::ActivationReason>(reason));
426void QBalloonTip::showBalloon(
const QIcon &icon,
const QString &title,
427 const QString &message, QSystemTrayIcon *trayIcon,
428 const QPoint &pos,
int timeout,
bool showArrow)
431 if (message.isEmpty() && title.isEmpty())
462QBalloonTip::QBalloonTip(
const QIcon &icon,
const QString &title,
463 const QString &message, QSystemTrayIcon *ti)
464 : QWidget(
nullptr, Qt::ToolTip),
468 setAttribute(Qt::WA_DeleteOnClose);
469 QObject::connect(ti, SIGNAL(destroyed()),
this, SLOT(close()));
472 QLabel *titleLabel =
new QLabel;
473 titleLabel->installEventFilter(
this);
474 titleLabel->setText(title);
475 QFont f = titleLabel->font();
477 titleLabel->setFont(f);
478 titleLabel->setTextFormat(Qt::PlainText);
481 const int iconSize = 18;
482 const int closeButtonSize = 15;
484#if QT_CONFIG(pushbutton)
485 QPushButton *closeButton =
new QPushButton;
486 closeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
487 closeButton->setIconSize(QSize(closeButtonSize, closeButtonSize));
488 closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
489 closeButton->setFixedSize(closeButtonSize, closeButtonSize);
490 QObject::connect(closeButton, SIGNAL(clicked()),
this, SLOT(close()));
492 Q_UNUSED(closeButtonSize);
496 QLabel *msgLabel =
new QLabel;
497 msgLabel->installEventFilter(
this);
498 msgLabel->setText(message);
499 msgLabel->setTextFormat(Qt::PlainText);
500 msgLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
503 int limit = QWidgetPrivate::availableScreenGeometry(msgLabel).width() / 3;
504 if (msgLabel->sizeHint().width() > limit) {
505 msgLabel->setWordWrap(
true);
506 if (msgLabel->sizeHint().width() > limit) {
507 msgLabel->d_func()->ensureTextControl();
508 if (QWidgetTextControl *control = msgLabel->d_func()->control) {
509 QTextOption opt = control->document()->defaultTextOption();
510 opt.setWrapMode(QTextOption::WrapAnywhere);
511 control->document()->setDefaultTextOption(opt);
516 msgLabel->setFixedSize(limit, msgLabel->heightForWidth(limit));
520 QGridLayout *layout =
new QGridLayout;
522 if (!icon.isNull()) {
523 QLabel *iconLabel =
new QLabel;
524 iconLabel->setPixmap(icon.pixmap(QSize(iconSize, iconSize), devicePixelRatio()));
525 iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
526 iconLabel->setMargin(2);
527 layout->addWidget(iconLabel, 0, 0);
528 layout->addWidget(titleLabel, 0, 1);
530 layout->addWidget(titleLabel, 0, 0, 1, 2);
534#if QT_CONFIG(pushbutton)
535 layout->addWidget(closeButton, 0, 2);
539 layout->addWidget(msgLabel, 1, 0, 1, 3);
541 layout->setSizeConstraint(QLayout::SetFixedSize);
542 layout->setContentsMargins(3, 3, 3, 3);
545 QPalette pal = palette();
546 pal.setColor(QPalette::Window, QColor(0xff, 0xff, 0xe1));
547 pal.setColor(QPalette::WindowText, Qt::black);
558 QPainter painter(
this);
559 painter.drawPixmap(rect(), pixmap);
564 QWidget::resizeEvent(ev);
569 this->showArrow = showArrow;
570 QScreen *screen = QGuiApplication::screenAt(pos);
572 screen = QGuiApplication::primaryScreen();
573 QRect screenRect = screen->geometry();
574 QSize sh = sizeHint();
575 const int border = 1;
576 const int ah = 18, ao = 18, aw = 18, rc = 7;
577 bool arrowAtTop = (pos.y() + sh.height() + ah < screenRect.height());
578 bool arrowAtLeft = (pos.x() + sh.width() - ao < screenRect.width());
579 setContentsMargins(border + 3, border + (arrowAtTop ? ah : 0) + 2, border + 3, border + (arrowAtTop ? 0 : ah) + 2);
584 QSize sz = sizeHint();
588 mb = sz.height() - ah - 1;
593 mb = sz.height() - 1;
597 path.moveTo(ml + rc, mt);
598 if (arrowAtTop && arrowAtLeft) {
600 path.lineTo(ml + ao, mt);
601 path.lineTo(ml + ao, mt - ah);
602 path.lineTo(ml + ao + aw, mt);
604 move(qMax(pos.x() - ao, screenRect.left() + 2), pos.y());
605 }
else if (arrowAtTop && !arrowAtLeft) {
607 path.lineTo(mr - ao - aw, mt);
608 path.lineTo(mr - ao, mt - ah);
609 path.lineTo(mr - ao, mt);
611 move(qMin(pos.x() - sh.width() + ao, screenRect.right() - sh.width() - 2), pos.y());
613 path.lineTo(mr - rc, mt);
614 path.arcTo(QRect(mr - rc*2, mt, rc*2, rc*2), 90, -90);
615 path.lineTo(mr, mb - rc);
616 path.arcTo(QRect(mr - rc*2, mb - rc*2, rc*2, rc*2), 0, -90);
617 if (!arrowAtTop && !arrowAtLeft) {
619 path.lineTo(mr - ao, mb);
620 path.lineTo(mr - ao, mb + ah);
621 path.lineTo(mr - ao - aw, mb);
623 move(qMin(pos.x() - sh.width() + ao, screenRect.right() - sh.width() - 2),
624 pos.y() - sh.height());
625 }
else if (!arrowAtTop && arrowAtLeft) {
627 path.lineTo(ao + aw, mb);
628 path.lineTo(ao, mb + ah);
631 move(qMax(pos.x() - ao, screenRect.x() + 2), pos.y() - sh.height());
633 path.lineTo(ml + rc, mb);
634 path.arcTo(QRect(ml, mb - rc*2, rc*2, rc*2), -90, -90);
635 path.lineTo(ml, mt + rc);
636 path.arcTo(QRect(ml, mt, rc*2, rc*2), 180, -90);
639 QBitmap bitmap = QBitmap(sizeHint());
640 bitmap.fill(Qt::color0);
642 painter1.setPen(QPen(Qt::color1, border));
643 painter1.setBrush(QBrush(Qt::color1));
644 painter1.drawPath(path);
648 pixmap = QPixmap(sz);
650 painter2.setPen(QPen(palette().color(QPalette::Window).darker(160), border));
651 painter2.setBrush(palette().color(QPalette::Window));
652 painter2.drawPath(path);
655 timer.start(msecs * 1ms,
this);
662 if (e->button() == Qt::LeftButton)
663 emit trayIcon->messageClicked();
668 if (e->id() == timer.id()) {
674 QWidget::timerEvent(e);
681 QObject::connect(qpa_sys, SIGNAL(activated(QPlatformSystemTrayIcon::ActivationReason)),
682 q_func(), SLOT(_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason)));
683 QObject::connect(qpa_sys, &QPlatformSystemTrayIcon::messageClicked,
684 q_func(), &QSystemTrayIcon::messageClicked);
692 QObject::disconnect(qpa_sys, SIGNAL(activated(QPlatformSystemTrayIcon::ActivationReason)),
693 q_func(), SLOT(_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason)));
694 QObject::disconnect(qpa_sys, &QPlatformSystemTrayIcon::messageClicked,
695 q_func(), &QSystemTrayIcon::messageClicked);
702 if (menu->platformMenu())
707 const auto actions = menu->actions();
708 for (QAction *action : actions) {
710 addPlatformMenu(action->menu());
715 QPlatformMenu *platformMenu = qpa_sys->createMenu();
717 menu->setPlatformMenu(platformMenu);
727#include "moc_qsystemtrayicon.cpp"
728#include "moc_qsystemtrayicon_p.cpp"
static void hideBalloon()
static bool isBalloonVisible()
static void updateBalloonPosition(const QPoint &pos)
void timerEvent(QTimerEvent *e) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
void mousePressEvent(QMouseEvent *e) override
This event handler, for event event, can be reimplemented in a subclass to receive mouse press events...
QPainter(QPaintDevice *)
Constructs a painter that begins painting the paint device immediately.
\inmodule QtCore\reentrant
void _q_emitActivated(QPlatformSystemTrayIcon::ActivationReason reason)
QPlatformSystemTrayIcon * qpa_sys
static QBalloonTip * theSolitaryBalloonTip