1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsystemtrayicon.h"
5#include "qsystemtrayicon_p.h"
6
7#ifndef QT_NO_SYSTEMTRAYICON
8
9#if QT_CONFIG(menu)
10#include "qmenu.h"
11#endif
12#include "qlist.h"
13#include "qevent.h"
14#include "qpoint.h"
15#if QT_CONFIG(label)
16#include "qlabel.h"
17#include "private/qlabel_p.h"
18#endif
19#if QT_CONFIG(pushbutton)
20#include "qpushbutton.h"
21#endif
22#include "qpainterpath.h"
23#include "qpainter.h"
24#include "qstyle.h"
25#include "qgridlayout.h"
26#include "qapplication.h"
27#include "qbitmap.h"
28
29#include <private/qhighdpiscaling_p.h>
30#include <qpa/qplatformscreen.h>
31
32using namespace std::chrono_literals;
33
34QT_BEGIN_NAMESPACE
35
36static QIcon messageIcon2qIcon(QSystemTrayIcon::MessageIcon icon)
37{
38 QStyle::StandardPixmap stdIcon = QStyle::SP_CustomBase; // silence gcc 4.9.0 about uninited variable
39 switch (icon) {
40 case QSystemTrayIcon::Information:
41 stdIcon = QStyle::SP_MessageBoxInformation;
42 break;
43 case QSystemTrayIcon::Warning:
44 stdIcon = QStyle::SP_MessageBoxWarning;
45 break;
46 case QSystemTrayIcon::Critical:
47 stdIcon = QStyle::SP_MessageBoxCritical;
48 break;
49 case QSystemTrayIcon::NoIcon:
50 return QIcon();
51 }
52 return QApplication::style()->standardIcon(standardIcon: stdIcon);
53}
54
55/*!
56 \class QSystemTrayIcon
57 \brief The QSystemTrayIcon class provides an icon for an application in the system tray.
58 \since 4.2
59 \ingroup desktop
60 \inmodule QtWidgets
61
62 Modern operating systems usually provide a special area on the desktop,
63 called the \e{system tray} or \e{notification area}, where long-running
64 applications can display icons and short messages.
65
66 \image system-tray.webp The system tray on Windows 10.
67
68 The QSystemTrayIcon class can be used on the following platforms:
69
70 \list
71 \li All supported versions of Windows.
72 \li All Linux desktop environments that implement the D-Bus
73 \l{http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierItem}
74 {StatusNotifierItem specification}, including KDE, Gnome, Xfce, LXQt, and DDE.
75 \li All window managers and independent tray implementations for X11 that implement the
76 \l{http://standards.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html}
77 {freedesktop.org XEmbed system tray specification}.
78 \li All supported versions of \macos.
79 \endlist
80
81 To check whether a system tray is present on the user's desktop,
82 call the QSystemTrayIcon::isSystemTrayAvailable() static function.
83
84 To add a system tray entry, create a QSystemTrayIcon object, call setContextMenu()
85 to provide a context menu for the icon, and call show() to make it visible in the
86 system tray. Status notification messages ("balloon messages") can be displayed at
87 any time using showMessage().
88
89 If the system tray is unavailable when a system tray icon is constructed, but
90 becomes available later, QSystemTrayIcon will automatically add an entry for the
91 application in the system tray if the icon is \l visible.
92
93 The activated() signal is emitted when the user activates the icon.
94
95 Only on X11, when a tooltip is requested, the QSystemTrayIcon receives a QHelpEvent
96 of type QEvent::ToolTip. Additionally, the QSystemTrayIcon receives wheel events of
97 type QEvent::Wheel. These are not supported on any other platform. Note: Since GNOME
98 Shell version 3.26, not all QSystemTrayIcon::ActivationReason are supported by the
99 system without shell extensions installed.
100
101 \sa QDesktopServices, {Desktop Integration}, {System Tray Icon Example}
102*/
103
104/*!
105 \enum QSystemTrayIcon::MessageIcon
106
107 This enum describes the icon that is shown when a balloon message is displayed.
108
109 \value NoIcon No icon is shown.
110 \value Information An information icon is shown.
111 \value Warning A standard warning icon is shown.
112 \value Critical A critical warning icon is shown.
113
114 \sa QMessageBox
115*/
116
117/*!
118 Constructs a QSystemTrayIcon object with the given \a parent.
119
120 The icon is initially invisible.
121
122 \sa visible
123*/
124QSystemTrayIcon::QSystemTrayIcon(QObject *parent)
125: QObject(*new QSystemTrayIconPrivate(), parent)
126{
127}
128
129/*!
130 Constructs a QSystemTrayIcon object with the given \a icon and \a parent.
131
132 The icon is initially invisible.
133
134 \sa visible
135*/
136QSystemTrayIcon::QSystemTrayIcon(const QIcon &icon, QObject *parent)
137 : QSystemTrayIcon(parent)
138{
139 setIcon(icon);
140}
141
142/*!
143 Removes the icon from the system tray and frees all allocated resources.
144*/
145QSystemTrayIcon::~QSystemTrayIcon()
146{
147 Q_D(QSystemTrayIcon);
148 d->remove_sys();
149}
150
151#if QT_CONFIG(menu)
152
153/*!
154 Sets the specified \a menu to be the context menu for the system tray icon.
155
156 The menu will pop up when the user requests the context menu for the system
157 tray icon by clicking the mouse button.
158
159 \note The system tray icon does not take ownership of the menu. You must
160 ensure that it is deleted at the appropriate time by, for example, creating
161 the menu with a suitable parent object.
162*/
163void QSystemTrayIcon::setContextMenu(QMenu *menu)
164{
165 Q_D(QSystemTrayIcon);
166 QMenu *oldMenu = d->menu.data();
167 if (oldMenu == menu)
168 return;
169
170 d->menu = menu;
171 d->updateMenu_sys();
172
173 if (d->qpa_sys) {
174 // Show the QMenu-based menu for QPA plugins that do not provide native menus
175 if (oldMenu && !oldMenu->platformMenu())
176 QObject::disconnect(sender: d->qpa_sys, signal: &QPlatformSystemTrayIcon::contextMenuRequested, receiver: oldMenu, zero: nullptr);
177 if (menu && !menu->platformMenu()) {
178 QObject::connect(sender: d->qpa_sys, signal: &QPlatformSystemTrayIcon::contextMenuRequested,
179 context: menu,
180 slot: [menu](QPoint globalNativePos, const QPlatformScreen *platformScreen)
181 {
182 QScreen *screen = platformScreen ? platformScreen->screen() : nullptr;
183 menu->popup(pos: QHighDpi::fromNativePixels(value: globalNativePos, context: screen), at: nullptr);
184 });
185 }
186 }
187}
188
189/*!
190 Returns the current context menu for the system tray entry.
191*/
192QMenu* QSystemTrayIcon::contextMenu() const
193{
194 Q_D(const QSystemTrayIcon);
195 return d->menu;
196}
197
198#endif // QT_CONFIG(menu)
199
200/*!
201 \property QSystemTrayIcon::icon
202 \brief the system tray icon
203
204 On Windows, the system tray icon size is 16x16; on X11, the preferred size is
205 22x22. The icon will be scaled to the appropriate size as necessary.
206*/
207void QSystemTrayIcon::setIcon(const QIcon &icon)
208{
209 Q_D(QSystemTrayIcon);
210 d->icon = icon;
211 d->updateIcon_sys();
212}
213
214QIcon QSystemTrayIcon::icon() const
215{
216 Q_D(const QSystemTrayIcon);
217 return d->icon;
218}
219
220/*!
221 \property QSystemTrayIcon::toolTip
222 \brief the tooltip for the system tray entry
223
224 On some systems, the tooltip's length is limited. The tooltip will be truncated
225 if necessary.
226*/
227void QSystemTrayIcon::setToolTip(const QString &tooltip)
228{
229 Q_D(QSystemTrayIcon);
230 d->toolTip = tooltip;
231 d->updateToolTip_sys();
232}
233
234QString QSystemTrayIcon::toolTip() const
235{
236 Q_D(const QSystemTrayIcon);
237 return d->toolTip;
238}
239
240/*!
241 \fn void QSystemTrayIcon::show()
242
243 Shows the icon in the system tray.
244
245 \sa hide(), visible
246*/
247
248/*!
249 \fn void QSystemTrayIcon::hide()
250
251 Hides the system tray entry.
252
253 \sa show(), visible
254*/
255
256/*!
257 \since 4.3
258 Returns the geometry of the system tray icon in screen coordinates.
259
260 \sa visible
261*/
262QRect QSystemTrayIcon::geometry() const
263{
264 Q_D(const QSystemTrayIcon);
265 if (!d->visible)
266 return QRect();
267 return d->geometry_sys();
268}
269
270/*!
271 \property QSystemTrayIcon::visible
272 \brief whether the system tray entry is visible
273
274 Setting this property to true or calling show() makes the system tray icon
275 visible; setting this property to false or calling hide() hides it.
276*/
277void QSystemTrayIcon::setVisible(bool visible)
278{
279 Q_D(QSystemTrayIcon);
280 if (visible == d->visible)
281 return;
282 if (Q_UNLIKELY(visible && d->icon.isNull()))
283 qWarning(msg: "QSystemTrayIcon::setVisible: No Icon set");
284 d->visible = visible;
285 if (d->visible)
286 d->install_sys();
287 else
288 d->remove_sys();
289}
290
291bool QSystemTrayIcon::isVisible() const
292{
293 Q_D(const QSystemTrayIcon);
294 return d->visible;
295}
296
297/*!
298 \reimp
299*/
300bool QSystemTrayIcon::event(QEvent *e)
301{
302 return QObject::event(event: e);
303}
304
305/*!
306 \enum QSystemTrayIcon::ActivationReason
307
308 This enum describes the reason the system tray was activated.
309
310 \value Unknown Unknown reason
311 \value Context The context menu for the system tray entry was requested
312 \value DoubleClick The system tray entry was double clicked. \note On macOS, a
313 double click will only be emitted if no context menu is set, since the menu
314 opens on mouse press
315 \value Trigger The system tray entry was clicked
316 \value MiddleClick The system tray entry was clicked with the middle mouse button
317
318 \sa activated()
319*/
320
321/*!
322 \fn void QSystemTrayIcon::activated(QSystemTrayIcon::ActivationReason reason)
323
324 This signal is emitted when the user activates the system tray icon. \a reason
325 specifies the reason for activation. QSystemTrayIcon::ActivationReason enumerates
326 the various reasons.
327
328 \sa QSystemTrayIcon::ActivationReason
329*/
330
331/*!
332 \fn void QSystemTrayIcon::messageClicked()
333
334 This signal is emitted when the message displayed using showMessage()
335 was clicked by the user.
336
337 \note We follow Microsoft Windows behavior, so the
338 signal is also emitted when the user clicks on a tray icon with
339 a balloon message displayed.
340
341 \sa activated()
342*/
343
344
345/*!
346 Returns \c true if the system tray is available; otherwise returns \c false.
347
348 If the system tray is currently unavailable but becomes available later,
349 QSystemTrayIcon will automatically add an entry in the system tray if it
350 is \l visible.
351*/
352
353bool QSystemTrayIcon::isSystemTrayAvailable()
354{
355 return QSystemTrayIconPrivate::isSystemTrayAvailable_sys();
356}
357
358/*!
359 Returns \c true if the system tray supports balloon messages; otherwise returns \c false.
360
361 \sa showMessage()
362*/
363bool QSystemTrayIcon::supportsMessages()
364{
365 return QSystemTrayIconPrivate::supportsMessages_sys();
366}
367
368/*!
369 \fn void QSystemTrayIcon::showMessage(const QString &title, const QString &message, MessageIcon icon, int millisecondsTimeoutHint)
370 \since 4.3
371
372 Shows a balloon message for the entry with the given \a title, \a message and
373 \a icon for the time specified in \a millisecondsTimeoutHint. \a title and \a message
374 must be plain text strings.
375
376 Message can be clicked by the user; the messageClicked() signal will emitted when
377 this occurs.
378
379 Note that display of messages are dependent on the system configuration and user
380 preferences, and that messages may not appear at all. Hence, it should not be
381 relied upon as the sole means for providing critical information.
382
383 On Windows, the \a millisecondsTimeoutHint is usually ignored by the system
384 when the application has focus.
385
386 Has been turned into a slot in Qt 5.2.
387
388 \sa show(), supportsMessages()
389 */
390void QSystemTrayIcon::showMessage(const QString& title, const QString& msg,
391 QSystemTrayIcon::MessageIcon msgIcon, int msecs)
392{
393 Q_D(QSystemTrayIcon);
394 if (d->visible)
395 d->showMessage_sys(title, msg, icon: messageIcon2qIcon(icon: msgIcon), msgIcon, msecs);
396}
397
398/*!
399 \fn void QSystemTrayIcon::showMessage(const QString &title, const QString &message, const QIcon &icon, int millisecondsTimeoutHint)
400
401 \overload showMessage()
402
403 Shows a balloon message for the entry with the given \a title, \a message,
404 and custom icon \a icon for the time specified in \a millisecondsTimeoutHint.
405
406 \since 5.9
407*/
408void QSystemTrayIcon::showMessage(const QString &title, const QString &msg,
409 const QIcon &icon, int msecs)
410{
411 Q_D(QSystemTrayIcon);
412 if (d->visible)
413 d->showMessage_sys(title, msg, icon, msgIcon: QSystemTrayIcon::NoIcon, msecs);
414}
415
416void QSystemTrayIconPrivate::_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason reason)
417{
418 Q_Q(QSystemTrayIcon);
419 emit q->activated(reason: static_cast<QSystemTrayIcon::ActivationReason>(reason));
420}
421
422//////////////////////////////////////////////////////////////////////
423static QBalloonTip *theSolitaryBalloonTip = nullptr;
424
425void QBalloonTip::showBalloon(const QIcon &icon, const QString &title,
426 const QString &message, QSystemTrayIcon *trayIcon,
427 const QPoint &pos, int timeout, bool showArrow)
428{
429 hideBalloon();
430 if (message.isEmpty() && title.isEmpty())
431 return;
432
433 theSolitaryBalloonTip = new QBalloonTip(icon, title, message, trayIcon);
434 if (timeout < 0)
435 timeout = 10000; //10 s default
436 theSolitaryBalloonTip->balloon(pos, timeout, showArrow);
437}
438
439void QBalloonTip::hideBalloon()
440{
441 if (!theSolitaryBalloonTip)
442 return;
443 theSolitaryBalloonTip->hide();
444 delete theSolitaryBalloonTip;
445 theSolitaryBalloonTip = nullptr;
446}
447
448void QBalloonTip::updateBalloonPosition(const QPoint& pos)
449{
450 if (!theSolitaryBalloonTip)
451 return;
452 theSolitaryBalloonTip->hide();
453 theSolitaryBalloonTip->balloon(pos, 0, theSolitaryBalloonTip->showArrow);
454}
455
456bool QBalloonTip::isBalloonVisible()
457{
458 return theSolitaryBalloonTip;
459}
460
461QBalloonTip::QBalloonTip(const QIcon &icon, const QString &title,
462 const QString &message, QSystemTrayIcon *ti)
463 : QWidget(nullptr, Qt::ToolTip),
464 trayIcon(ti),
465 showArrow(true)
466{
467 setAttribute(Qt::WA_DeleteOnClose);
468 QObject::connect(sender: ti, SIGNAL(destroyed()), receiver: this, SLOT(close()));
469
470#if QT_CONFIG(label)
471 QLabel *titleLabel = new QLabel;
472 titleLabel->installEventFilter(filterObj: this);
473 titleLabel->setText(title);
474 QFont f = titleLabel->font();
475 f.setBold(true);
476 titleLabel->setFont(f);
477 titleLabel->setTextFormat(Qt::PlainText); // to maintain compat with windows
478#endif
479
480 const int iconSize = 18;
481 const int closeButtonSize = 15;
482
483#if QT_CONFIG(pushbutton)
484 QPushButton *closeButton = new QPushButton;
485 closeButton->setIcon(style()->standardIcon(standardIcon: QStyle::SP_TitleBarCloseButton));
486 closeButton->setIconSize(QSize(closeButtonSize, closeButtonSize));
487 closeButton->setSizePolicy(hor: QSizePolicy::Fixed, ver: QSizePolicy::Fixed);
488 closeButton->setFixedSize(w: closeButtonSize, h: closeButtonSize);
489 QObject::connect(sender: closeButton, SIGNAL(clicked()), receiver: this, SLOT(close()));
490#else
491 Q_UNUSED(closeButtonSize);
492#endif
493
494#if QT_CONFIG(label)
495 QLabel *msgLabel = new QLabel;
496 msgLabel->installEventFilter(filterObj: this);
497 msgLabel->setText(message);
498 msgLabel->setTextFormat(Qt::PlainText);
499 msgLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
500
501 // smart size for the message label
502 int limit = QWidgetPrivate::availableScreenGeometry(widget: msgLabel).width() / 3;
503 if (msgLabel->sizeHint().width() > limit) {
504 msgLabel->setWordWrap(true);
505 if (msgLabel->sizeHint().width() > limit) {
506 msgLabel->d_func()->ensureTextControl();
507 if (QWidgetTextControl *control = msgLabel->d_func()->control) {
508 QTextOption opt = control->document()->defaultTextOption();
509 opt.setWrapMode(QTextOption::WrapAnywhere);
510 control->document()->setDefaultTextOption(opt);
511 }
512 }
513 // Here we allow the text being much smaller than the balloon widget
514 // to emulate the weird standard windows behavior.
515 msgLabel->setFixedSize(w: limit, h: msgLabel->heightForWidth(limit));
516 }
517#endif
518
519 QGridLayout *layout = new QGridLayout;
520#if QT_CONFIG(label)
521 if (!icon.isNull()) {
522 QLabel *iconLabel = new QLabel;
523 iconLabel->setPixmap(icon.pixmap(size: QSize(iconSize, iconSize), devicePixelRatio: devicePixelRatio()));
524 iconLabel->setSizePolicy(hor: QSizePolicy::Fixed, ver: QSizePolicy::Fixed);
525 iconLabel->setMargin(2);
526 layout->addWidget(iconLabel, row: 0, column: 0);
527 layout->addWidget(titleLabel, row: 0, column: 1);
528 } else {
529 layout->addWidget(titleLabel, row: 0, column: 0, rowSpan: 1, columnSpan: 2);
530 }
531#endif
532
533#if QT_CONFIG(pushbutton)
534 layout->addWidget(closeButton, row: 0, column: 2);
535#endif
536
537#if QT_CONFIG(label)
538 layout->addWidget(msgLabel, row: 1, column: 0, rowSpan: 1, columnSpan: 3);
539#endif
540 layout->setSizeConstraint(QLayout::SetFixedSize);
541 layout->setContentsMargins(left: 3, top: 3, right: 3, bottom: 3);
542 setLayout(layout);
543
544 QPalette pal = palette();
545 pal.setColor(acr: QPalette::Window, acolor: QColor(0xff, 0xff, 0xe1));
546 pal.setColor(acr: QPalette::WindowText, acolor: Qt::black);
547 setPalette(pal);
548}
549
550QBalloonTip::~QBalloonTip()
551{
552 theSolitaryBalloonTip = nullptr;
553}
554
555void QBalloonTip::paintEvent(QPaintEvent *)
556{
557 QPainter painter(this);
558 painter.drawPixmap(r: rect(), pm: pixmap);
559}
560
561void QBalloonTip::resizeEvent(QResizeEvent *ev)
562{
563 QWidget::resizeEvent(event: ev);
564}
565
566void QBalloonTip::balloon(const QPoint& pos, int msecs, bool showArrow)
567{
568 this->showArrow = showArrow;
569 QScreen *screen = QGuiApplication::screenAt(point: pos);
570 if (!screen)
571 screen = QGuiApplication::primaryScreen();
572 QRect screenRect = screen->geometry();
573 QSize sh = sizeHint();
574 const int border = 1;
575 const int ah = 18, ao = 18, aw = 18, rc = 7;
576 bool arrowAtTop = (pos.y() + sh.height() + ah < screenRect.height());
577 bool arrowAtLeft = (pos.x() + sh.width() - ao < screenRect.width());
578 setContentsMargins(left: border + 3, top: border + (arrowAtTop ? ah : 0) + 2, right: border + 3, bottom: border + (arrowAtTop ? 0 : ah) + 2);
579 updateGeometry();
580 sh = sizeHint();
581
582 int ml, mr, mt, mb;
583 QSize sz = sizeHint();
584 if (!arrowAtTop) {
585 ml = mt = 0;
586 mr = sz.width() - 1;
587 mb = sz.height() - ah - 1;
588 } else {
589 ml = 0;
590 mt = ah;
591 mr = sz.width() - 1;
592 mb = sz.height() - 1;
593 }
594
595 QPainterPath path;
596 path.moveTo(x: ml + rc, y: mt);
597 if (arrowAtTop && arrowAtLeft) {
598 if (showArrow) {
599 path.lineTo(x: ml + ao, y: mt);
600 path.lineTo(x: ml + ao, y: mt - ah);
601 path.lineTo(x: ml + ao + aw, y: mt);
602 }
603 move(ax: qMax(a: pos.x() - ao, b: screenRect.left() + 2), ay: pos.y());
604 } else if (arrowAtTop && !arrowAtLeft) {
605 if (showArrow) {
606 path.lineTo(x: mr - ao - aw, y: mt);
607 path.lineTo(x: mr - ao, y: mt - ah);
608 path.lineTo(x: mr - ao, y: mt);
609 }
610 move(ax: qMin(a: pos.x() - sh.width() + ao, b: screenRect.right() - sh.width() - 2), ay: pos.y());
611 }
612 path.lineTo(x: mr - rc, y: mt);
613 path.arcTo(rect: QRect(mr - rc*2, mt, rc*2, rc*2), startAngle: 90, arcLength: -90);
614 path.lineTo(x: mr, y: mb - rc);
615 path.arcTo(rect: QRect(mr - rc*2, mb - rc*2, rc*2, rc*2), startAngle: 0, arcLength: -90);
616 if (!arrowAtTop && !arrowAtLeft) {
617 if (showArrow) {
618 path.lineTo(x: mr - ao, y: mb);
619 path.lineTo(x: mr - ao, y: mb + ah);
620 path.lineTo(x: mr - ao - aw, y: mb);
621 }
622 move(ax: qMin(a: pos.x() - sh.width() + ao, b: screenRect.right() - sh.width() - 2),
623 ay: pos.y() - sh.height());
624 } else if (!arrowAtTop && arrowAtLeft) {
625 if (showArrow) {
626 path.lineTo(x: ao + aw, y: mb);
627 path.lineTo(x: ao, y: mb + ah);
628 path.lineTo(x: ao, y: mb);
629 }
630 move(ax: qMax(a: pos.x() - ao, b: screenRect.x() + 2), ay: pos.y() - sh.height());
631 }
632 path.lineTo(x: ml + rc, y: mb);
633 path.arcTo(rect: QRect(ml, mb - rc*2, rc*2, rc*2), startAngle: -90, arcLength: -90);
634 path.lineTo(x: ml, y: mt + rc);
635 path.arcTo(rect: QRect(ml, mt, rc*2, rc*2), startAngle: 180, arcLength: -90);
636
637 // Set the mask
638 QBitmap bitmap = QBitmap(sizeHint());
639 bitmap.fill(fillColor: Qt::color0);
640 QPainter painter1(&bitmap);
641 painter1.setPen(QPen(Qt::color1, border));
642 painter1.setBrush(QBrush(Qt::color1));
643 painter1.drawPath(path);
644 setMask(bitmap);
645
646 // Draw the border
647 pixmap = QPixmap(sz);
648 QPainter painter2(&pixmap);
649 painter2.setPen(QPen(palette().color(cr: QPalette::Window).darker(f: 160), border));
650 painter2.setBrush(palette().color(cr: QPalette::Window));
651 painter2.drawPath(path);
652
653 if (msecs > 0)
654 timer.start(duration: msecs * 1ms, obj: this);
655 show();
656}
657
658void QBalloonTip::mousePressEvent(QMouseEvent *e)
659{
660 close();
661 if (e->button() == Qt::LeftButton)
662 emit trayIcon->messageClicked();
663}
664
665void QBalloonTip::timerEvent(QTimerEvent *e)
666{
667 if (e->id() == timer.id()) {
668 timer.stop();
669 if (!underMouse())
670 close();
671 return;
672 }
673 QWidget::timerEvent(event: e);
674}
675
676//////////////////////////////////////////////////////////////////////
677void QSystemTrayIconPrivate::install_sys_qpa()
678{
679 qpa_sys->init();
680 QObject::connect(sender: qpa_sys, SIGNAL(activated(QPlatformSystemTrayIcon::ActivationReason)),
681 receiver: q_func(), SLOT(_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason)));
682 QObject::connect(sender: qpa_sys, signal: &QPlatformSystemTrayIcon::messageClicked,
683 context: q_func(), slot: &QSystemTrayIcon::messageClicked);
684 updateMenu_sys();
685 updateIcon_sys();
686 updateToolTip_sys();
687}
688
689void QSystemTrayIconPrivate::remove_sys_qpa()
690{
691 QObject::disconnect(sender: qpa_sys, SIGNAL(activated(QPlatformSystemTrayIcon::ActivationReason)),
692 receiver: q_func(), SLOT(_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason)));
693 QObject::disconnect(sender: qpa_sys, signal: &QPlatformSystemTrayIcon::messageClicked,
694 receiver: q_func(), slot: &QSystemTrayIcon::messageClicked);
695 qpa_sys->cleanup();
696}
697
698void QSystemTrayIconPrivate::addPlatformMenu(QMenu *menu) const
699{
700#if QT_CONFIG(menu)
701 if (menu->platformMenu())
702 return; // The platform menu already exists.
703
704 // The recursion depth is the same as menu depth, so should not
705 // be higher than 3 levels.
706 const auto actions = menu->actions();
707 for (QAction *action : actions) {
708 if (action->menu())
709 addPlatformMenu(menu: action->menu());
710 }
711
712 // This menu should be processed *after* its children, otherwise
713 // setMenu() is not called on respective QPlatformMenuItems.
714 QPlatformMenu *platformMenu = qpa_sys->createMenu();
715 if (platformMenu)
716 menu->setPlatformMenu(platformMenu);
717#else
718 Q_UNUSED(menu);
719#endif // QT_CONFIG(menu)
720}
721
722QT_END_NAMESPACE
723
724#endif // QT_NO_SYSTEMTRAYICON
725
726#include "moc_qsystemtrayicon.cpp"
727#include "moc_qsystemtrayicon_p.cpp"
728

source code of qtbase/src/widgets/util/qsystemtrayicon.cpp