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 | |
14 | QT_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 | |
133 | Q_LOGGING_CATEGORY(qtLabsPlatformTray, "qt.labs.platform.tray" ) |
134 | |
135 | QQuickLabsPlatformSystemTrayIcon::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 | |
154 | QQuickLabsPlatformSystemTrayIcon::~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 | |
165 | QPlatformSystemTrayIcon *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 | */ |
176 | bool 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 | */ |
189 | bool 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 | */ |
201 | bool QQuickLabsPlatformSystemTrayIcon::isVisible() const |
202 | { |
203 | return m_visible; |
204 | } |
205 | |
206 | void 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 | */ |
227 | QString QQuickLabsPlatformSystemTrayIcon::tooltip() const |
228 | { |
229 | return m_tooltip; |
230 | } |
231 | |
232 | void 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 | */ |
249 | QQuickLabsPlatformMenu *QQuickLabsPlatformSystemTrayIcon::() const |
250 | { |
251 | return m_menu; |
252 | } |
253 | |
254 | void QQuickLabsPlatformSystemTrayIcon::(QQuickLabsPlatformMenu *) |
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 | */ |
277 | QRect 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 | */ |
297 | QQuickLabsPlatformIcon QQuickLabsPlatformSystemTrayIcon::icon() const |
298 | { |
299 | if (!m_iconLoader) |
300 | return QQuickLabsPlatformIcon(); |
301 | |
302 | return m_iconLoader->icon(); |
303 | } |
304 | |
305 | void 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 | */ |
319 | void 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 | */ |
329 | void 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 | */ |
346 | void 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 | |
352 | void 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 | |
365 | void QQuickLabsPlatformSystemTrayIcon::cleanup() |
366 | { |
367 | if (m_handle) |
368 | m_handle->cleanup(); |
369 | if (m_iconLoader) |
370 | m_iconLoader->setEnabled(false); |
371 | } |
372 | |
373 | void QQuickLabsPlatformSystemTrayIcon::classBegin() |
374 | { |
375 | } |
376 | |
377 | void QQuickLabsPlatformSystemTrayIcon::componentComplete() |
378 | { |
379 | m_complete = true; |
380 | if (m_visible) |
381 | init(); |
382 | } |
383 | |
384 | QQuickLabsPlatformIconLoader *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 | |
395 | void 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 | |
408 | QT_END_NAMESPACE |
409 | |
410 | #include "moc_qquicklabsplatformsystemtrayicon_p.cpp" |
411 | |