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

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