1// Copyright (C) 2017 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 "qquicklabsplatformsystemtrayicon_p.h"
5#include "qquicklabsplatformmenu_p.h"
6#include "qquicklabsplatformiconloader_p.h"
7
8#include <QtCore/qloggingcategory.h>
9#include <QtGui/qpa/qplatformtheme.h>
10#include <QtGui/private/qguiapplication_p.h>
11
12#include "widgets/qwidgetplatform_p.h"
13
14QT_BEGIN_NAMESPACE
15
16/*!
17 \qmltype SystemTrayIcon
18 \inherits QtObject
19//! \instantiates QQuickLabsPlatformSystemTrayIcon
20 \inqmlmodule Qt.labs.platform
21 \since 5.8
22 \brief A system tray icon.
23
24 The SystemTrayIcon type provides an icon for an application in the system tray.
25
26 Many desktop platforms provide a special system tray or notification area,
27 where applications can display icons and notification messages.
28
29 \image qtlabsplatform-systemtrayicon.png
30
31 The following example shows how to create a system tray icon, and how to make
32 use of the \l activated() signal:
33
34 \code
35 SystemTrayIcon {
36 visible: true
37 icon.source: "qrc:/images/tray-icon.png"
38
39 onActivated: {
40 window.show()
41 window.raise()
42 window.requestActivate()
43 }
44 }
45 \endcode
46
47 \section2 Tray menu
48
49 SystemTrayIcon can have a menu that opens when the icon is activated.
50
51 \image qtlabsplatform-systemtrayicon-menu.png
52
53 The following example illustrates how to assign a \l Menu to a system tray icon:
54
55 \code
56 SystemTrayIcon {
57 visible: true
58 icon.source: "qrc:/images/tray-icon.png"
59
60 menu: Menu {
61 MenuItem {
62 text: qsTr("Quit")
63 onTriggered: Qt.quit()
64 }
65 }
66 }
67 \endcode
68
69 \section2 Notification messages
70
71 SystemTrayIcon can display notification messages.
72
73 \image qtlabsplatform-systemtrayicon-message.png
74
75 The following example presents how to show a notification message using
76 \l showMessage(), and how to make use of the \l messageClicked() signal:
77
78 \code
79 SystemTrayIcon {
80 visible: true
81 icon.source: "qrc:/images/tray-icon.png"
82
83 onMessageClicked: console.log("Message clicked")
84 Component.onCompleted: showMessage("Message title", "Something important came up. Click this to know more.")
85 }
86 \endcode
87
88 \section2 Availability
89
90 A native system tray icon is currently \l available on the following platforms:
91
92 \list
93 \li All window managers and independent tray implementations for X11 that implement the
94 \l{http://standards.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html}
95 {freedesktop.org XEmbed system tray specification}.
96 \li All desktop environments that implement the
97 \l{http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierItem}
98 {freedesktop.org D-Bus StatusNotifierItem specification}, including recent versions of KDE and Unity.
99 \li All supported versions of macOS. Note that the Growl notification system must be installed
100 for showMessage() to display messages on OS X prior to 10.8 (Mountain Lion).
101 \endlist
102
103 \input includes/widgets.qdocinc 1
104
105 \labs
106
107 \sa Menu
108*/
109
110/*!
111 \qmlsignal Qt.labs.platform::SystemTrayIcon::activated(ActivationReason reason)
112
113 This signal is emitted when the system tray icon is activated by the user. The
114 \a reason argument specifies how the system tray icon was activated.
115
116 Available reasons:
117
118 \value SystemTrayIcon.Unknown Unknown reason
119 \value SystemTrayIcon.Context The context menu for the system tray icon was requested
120 \value SystemTrayIcon.DoubleClick The system tray icon was double clicked
121 \value SystemTrayIcon.Trigger The system tray icon was clicked
122 \value SystemTrayIcon.MiddleClick The system tray icon was clicked with the middle mouse button
123*/
124
125/*!
126 \qmlsignal Qt.labs.platform::SystemTrayIcon::messageClicked()
127
128 This signal is emitted when a notification message is clicked by the user.
129
130 \sa showMessage()
131*/
132
133Q_LOGGING_CATEGORY(qtLabsPlatformTray, "qt.labs.platform.tray")
134
135QQuickLabsPlatformSystemTrayIcon::QQuickLabsPlatformSystemTrayIcon(QObject *parent)
136 : QObject(parent),
137 m_complete(false),
138 m_visible(false),
139 m_menu(nullptr),
140 m_iconLoader(nullptr),
141 m_handle(nullptr)
142{
143 m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon();
144 if (!m_handle)
145 m_handle = QWidgetPlatform::createSystemTrayIcon(parent: this);
146 qCDebug(qtLabsPlatformTray) << "SystemTrayIcon ->" << m_handle;
147
148 if (m_handle) {
149 connect(sender: m_handle, signal: &QPlatformSystemTrayIcon::activated, context: this, slot: &QQuickLabsPlatformSystemTrayIcon::activated);
150 connect(sender: m_handle, signal: &QPlatformSystemTrayIcon::messageClicked, context: this, slot: &QQuickLabsPlatformSystemTrayIcon::messageClicked);
151 }
152}
153
154QQuickLabsPlatformSystemTrayIcon::~QQuickLabsPlatformSystemTrayIcon()
155{
156 if (m_menu)
157 m_menu->setSystemTrayIcon(nullptr);
158 cleanup();
159 delete m_iconLoader;
160 m_iconLoader = nullptr;
161 delete m_handle;
162 m_handle = nullptr;
163}
164
165QPlatformSystemTrayIcon *QQuickLabsPlatformSystemTrayIcon::handle() const
166{
167 return m_handle;
168}
169
170/*!
171 \readonly
172 \qmlproperty bool Qt.labs.platform::SystemTrayIcon::available
173
174 This property holds whether the system tray is available.
175*/
176bool QQuickLabsPlatformSystemTrayIcon::isAvailable() const
177{
178 return m_handle && m_handle->isSystemTrayAvailable();
179}
180
181/*!
182 \readonly
183 \qmlproperty bool Qt.labs.platform::SystemTrayIcon::supportsMessages
184
185 This property holds whether the system tray icon supports notification messages.
186
187 \sa showMessage()
188*/
189bool QQuickLabsPlatformSystemTrayIcon::supportsMessages() const
190{
191 return m_handle && m_handle->supportsMessages();
192}
193
194/*!
195 \qmlproperty bool Qt.labs.platform::SystemTrayIcon::visible
196
197 This property holds whether the system tray icon is visible.
198
199 The default value is \c false.
200*/
201bool QQuickLabsPlatformSystemTrayIcon::isVisible() const
202{
203 return m_visible;
204}
205
206void QQuickLabsPlatformSystemTrayIcon::setVisible(bool visible)
207{
208 if (m_visible == visible)
209 return;
210
211 if (m_handle && m_complete) {
212 if (visible)
213 init();
214 else
215 cleanup();
216 }
217
218 m_visible = visible;
219 emit visibleChanged();
220}
221
222/*!
223 \qmlproperty string Qt.labs.platform::SystemTrayIcon::tooltip
224
225 This property holds the tooltip of the system tray icon.
226*/
227QString QQuickLabsPlatformSystemTrayIcon::tooltip() const
228{
229 return m_tooltip;
230}
231
232void QQuickLabsPlatformSystemTrayIcon::setTooltip(const QString &tooltip)
233{
234 if (m_tooltip == tooltip)
235 return;
236
237 if (m_handle && m_complete)
238 m_handle->updateToolTip(tooltip);
239
240 m_tooltip = tooltip;
241 emit tooltipChanged();
242}
243
244/*!
245 \qmlproperty Menu Qt.labs.platform::SystemTrayIcon::menu
246
247 This property holds a menu for the system tray icon.
248*/
249QQuickLabsPlatformMenu *QQuickLabsPlatformSystemTrayIcon::menu() const
250{
251 return m_menu;
252}
253
254void QQuickLabsPlatformSystemTrayIcon::setMenu(QQuickLabsPlatformMenu *menu)
255{
256 if (m_menu == menu)
257 return;
258
259 if (m_menu)
260 m_menu->setSystemTrayIcon(nullptr);
261 if (menu) {
262 menu->setSystemTrayIcon(this);
263 if (m_handle && m_complete && menu->create())
264 m_handle->updateMenu(menu: menu->handle());
265 }
266
267 m_menu = menu;
268 emit menuChanged();
269}
270
271/*!
272 \since Qt.labs.platform 1.1 (Qt 5.12)
273 \qmlproperty rect Qt.labs.platform::SystemTrayIcon::geometry
274
275 This property holds the geometry of the system tray icon.
276*/
277QRect QQuickLabsPlatformSystemTrayIcon::geometry() const
278{
279 return m_handle ? m_handle->geometry() : QRect();
280}
281
282/*!
283 \since Qt.labs.platform 1.1 (Qt 5.12)
284 \qmlproperty url Qt.labs.platform::SystemTrayIcon::icon.source
285 \qmlproperty string Qt.labs.platform::SystemTrayIcon::icon.name
286 \qmlproperty bool Qt.labs.platform::SystemTrayIcon::icon.mask
287
288 This property holds the system tray icon.
289
290 \code
291 SystemTrayIcon {
292 icon.mask: true
293 icon.source: "qrc:/images/tray-icon.png"
294 }
295 \endcode
296*/
297QQuickLabsPlatformIcon QQuickLabsPlatformSystemTrayIcon::icon() const
298{
299 if (!m_iconLoader)
300 return QQuickLabsPlatformIcon();
301
302 return m_iconLoader->icon();
303}
304
305void QQuickLabsPlatformSystemTrayIcon::setIcon(const QQuickLabsPlatformIcon &icon)
306{
307 if (iconLoader()->icon() == icon)
308 return;
309
310 iconLoader()->setIcon(icon);
311 emit iconChanged();
312}
313
314/*!
315 \qmlmethod void Qt.labs.platform::SystemTrayIcon::show()
316
317 Shows the system tray icon.
318*/
319void QQuickLabsPlatformSystemTrayIcon::show()
320{
321 setVisible(true);
322}
323
324/*!
325 \qmlmethod void Qt.labs.platform::SystemTrayIcon::hide()
326
327 Hides the system tray icon.
328*/
329void QQuickLabsPlatformSystemTrayIcon::hide()
330{
331 setVisible(false);
332}
333
334/*!
335 \qmlmethod void Qt.labs.platform::SystemTrayIcon::showMessage(string title, string message, MessageIcon icon, int msecs)
336
337 Shows a system tray message with the given \a title, \a message and \a icon
338 for the time specified in \a msecs.
339
340 \note System tray messages are dependent on the system configuration and user preferences,
341 and may not appear at all. Therefore, it should not be relied upon as the sole means for providing
342 critical information.
343
344 \sa supportsMessages, messageClicked()
345*/
346void QQuickLabsPlatformSystemTrayIcon::showMessage(const QString &title, const QString &msg, QPlatformSystemTrayIcon::MessageIcon icon, int msecs)
347{
348 if (m_handle)
349 m_handle->showMessage(title, msg, icon: QIcon(), iconType: icon, msecs);
350}
351
352void QQuickLabsPlatformSystemTrayIcon::init()
353{
354 if (!m_handle)
355 return;
356
357 m_handle->init();
358 if (m_menu && m_menu->create())
359 m_handle->updateMenu(menu: m_menu->handle());
360 m_handle->updateToolTip(tooltip: m_tooltip);
361 if (m_iconLoader)
362 m_iconLoader->setEnabled(true);
363}
364
365void QQuickLabsPlatformSystemTrayIcon::cleanup()
366{
367 if (m_handle)
368 m_handle->cleanup();
369 if (m_iconLoader)
370 m_iconLoader->setEnabled(false);
371}
372
373void QQuickLabsPlatformSystemTrayIcon::classBegin()
374{
375}
376
377void QQuickLabsPlatformSystemTrayIcon::componentComplete()
378{
379 m_complete = true;
380 if (m_visible)
381 init();
382}
383
384QQuickLabsPlatformIconLoader *QQuickLabsPlatformSystemTrayIcon::iconLoader() const
385{
386 if (!m_iconLoader) {
387 QQuickLabsPlatformSystemTrayIcon *that = const_cast<QQuickLabsPlatformSystemTrayIcon *>(this);
388 static int slot = staticMetaObject.indexOfSlot(slot: "updateIcon()");
389 m_iconLoader = new QQuickLabsPlatformIconLoader(slot, that);
390 m_iconLoader->setEnabled(m_complete);
391 }
392 return m_iconLoader;
393}
394
395void QQuickLabsPlatformSystemTrayIcon::updateIcon()
396{
397 if (!m_handle || !m_iconLoader)
398 return;
399
400 const QRect oldGeometry = m_handle->geometry();
401
402 m_handle->updateIcon(icon: m_iconLoader->toQIcon());
403
404 if (oldGeometry != m_handle->geometry())
405 emit geometryChanged();
406}
407
408QT_END_NAMESPACE
409
410#include "moc_qquicklabsplatformsystemtrayicon_p.cpp"
411

source code of qtdeclarative/src/labs/platform/qquicklabsplatformsystemtrayicon.cpp