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