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

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