9#include <QtCore/private/qcore_ohos_p.h>
10#include <QtCore/qdatetime.h>
11#include <QtCore/qobject.h>
12#include <QtGui/private/qhighdpiscaling_p.h>
13#include <QtGui/private/qohosimageconversions_p.h>
14#include <QtGui/qguiapplication.h>
15#include <QtGui/qicon.h>
16#include <QtGui/qpa/qplatformmenu.h>
17#include <QtGui/qscreen.h>
35 return !hoverTips.empty() ? hoverTips :
" ";
40 return [](QOhosJsState &jsState) {
41 return QNapi::Array::New(jsState.env());
47 auto optQAbility = jsState.defaultQAbility();
49 qOhosReportFatalErrorAndAbort(
"%s: no default Ability instance", Q_FUNC_INFO);
51 return optQAbility->eval<QNapi::Object>(
"context");
55 QOhosJsState &jsState,
std::function<
void()> leftClickListener)
57 return registerQOhosOnOffMethodsBasedEventHandler(
58 jsState.eval<QNapi::Object>(
"@kit.StatusBarExtensionKit.statusBarManager"),
60 [leftClickListener = std::move(leftClickListener)](
const QOhosCallbackInfo &cbInfo) {
61 auto eventData = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
62 auto optIconClickType = QNapi::getOptionalPropOrEmpty<QNapi::String>(
63 QNapi::getOptionalPropOrEmpty<QNapi::Object>(eventData,
"data"),
66 if (optIconClickType.IsEmpty()) {
68 "%s: no 'iconClickType' in the event (%s), ignoring it",
69 Q_FUNC_INFO, QNapi::toJsonString(eventData).c_str());
73 if (optIconClickType.Utf8Value() ==
"leftClick")
81 "@kit.StatusBarExtensionKit.statusBarManager.removeFromStatusBar(*)",
82 {getContextForStatusBarManager(jsState)});
84 qOhosPrintfDebug(
"%s: Successfully removed icon from status bar", Q_FUNC_INFO);
90 "@kit.StatusBarExtensionKit.statusBarManager.addToStatusBar(*)",
91 {getContextForStatusBarManager(jsState), statusBarItem});
93 qOhosPrintfDebug(
"%s: Successfully added icon to status bar [Statusbar] ", Q_FUNC_INFO);
95 return QtOhos::makeDestroyNotifier(
97 QOhosJsThreadGateway::runAndWait(&removeIconFromOhosStatusBar, Q_FUNC_INFO);
103 qOhosPrintfDebug(
"%s", Q_FUNC_INFO);
105 if (iconData.IsEmpty()) {
106 qOhosPrintfError(
"%s: Icon data is empty", Q_FUNC_INFO);
111 "@kit.StatusBarExtensionKit.statusBarManager.updateStatusBarIcon(*)",
112 {getContextForStatusBarManager(jsState), iconData});
114 qOhosPrintfDebug(
"%s: Successfully updated status bar icon", Q_FUNC_INFO);
119 return jsState.evalToPromiseOrRejectOnThrow(
120 "@kit.StatusBarExtensionKit.statusBarManager.updateStatusBarHoverTips(*)",
121 {getContextForStatusBarManager(jsState), applyWorkaroundForEmptyHoverTips(hoverTips)});
127 "@kit.StatusBarExtensionKit.statusBarManager.updateStatusBarMenu(*)",
128 {getContextForStatusBarManager(jsState), statusBarGroupMenus});
130 qOhosPrintfDebug(
"%s: Successfully updated status bar menu", Q_FUNC_INFO);
134 QOhosJsState &jsState, QNapi::Object statusBarIcon,
const std::string &title,
135 QNapi::Array statusBarGroupMenus,
std::optional<
std::string> hoverTips)
137 auto *env = jsState.env();
139 auto quickOperation = QNapi::makeObject(
143 {
"height", quickOperationHeight},
147 auto statusBarItem = QNapi::makeObject(
150 {
"icons", statusBarIcon},
151 {
"quickOperation", quickOperation},
152 {
"statusBarGroupMenu", statusBarGroupMenus},
155 if (hoverTips.has_value())
156 statusBarItem.set(
"hoverTips", applyWorkaroundForEmptyHoverTips(hoverTips.value()));
158 return statusBarItem;
162 const QIcon &icon,
const QSize &imageSize,
const QColor &fallbackContentColor)
164 auto iconImage = icon.pixmap(imageSize).toImage();
165 if (!iconImage.isNull())
168 auto fallbackImage = QImage(imageSize, QImage::Format_RGBA8888);
169 fallbackImage.fill(fallbackContentColor);
170 return fallbackImage;
175 const QSize iconSize(48, 48);
176 return makeDisplayDensityScaledJsPixelMapFromQImage(
177 jsState, convertIconToScaledImage(icon, iconSize, Qt::transparent));
182 auto *env = jsState.env();
184 auto trayIcon = makeJsPixelMapFromIcon(jsState, icon);
186 auto imageSize = trayIcon.eval<QNapi::Object>(
"getImageInfoSync().size");
188 int imageWidth = imageSize.get<QNapi::Number>(
"width");
189 int imageHeight = imageSize.get<QNapi::Number>(
"height");
190 qOhosPrintfDebug(
"%s: ceated PixelMap size: %dx%d", Q_FUNC_INFO, imageWidth, imageHeight);
192 return QNapi::makeObject(
201 QOhosJsState &jsState,
const std::string &title,
const std::string &text)
205 return QNapi::makeObject(
208 {
"notificationContentType", jsState.mapOhosEnumToJs(ContentType::NOTIFICATION_CONTENT_BASIC_TEXT)},
222 QOhosJsState &jsState,
const std::string &title,
const std::string &content,
223 const QIcon &icon,
std::optional<
int> optAutoDeletedDelayMs)
225 auto iconPixelMap = makeDisplayDensityScaledJsPixelMapFromQImage(
226 jsState, convertIconToScaledImage(icon, notificationIconSize, Qt::transparent));
227 auto notificationRequest = QNapi::makeObject(
230 {
"content", makeJsNotificationContent(jsState, title, content)},
231 {
"smallIcon", iconPixelMap},
233 if (optAutoDeletedDelayMs.has_value()) {
234 notificationRequest.set(
236 QDateTime::currentMSecsSinceEpoch() + optAutoDeletedDelayMs.value());
239 return notificationRequest;
242class QOhosSystemTrayIcon
final :
public QPlatformSystemTrayIcon
254 const QString &title,
const QString &msg,
const QIcon &icon,
255 MessageIcon iconType,
int msecs)
override;
264 std::optional<QString> m_optToolTip;
265 QPlatformMenu *m_menu =
nullptr;
269 std::shared_ptr<
void> m_statusBarItemHandle;
270 std::shared_ptr<
void> m_iconLeftClickListenerHandle;
273 std::shared_ptr<JsScopeData> m_jsScopeData;
278void QOhosSystemTrayIcon::
init()
283 auto jsStatusBarGroupMenusFactory =
285 ?
static_cast<QOhosStatusBarMenu *>(m_menu)->makeJsStatusBarGroupMenusFactory()
286 : makeEmptyJsArrayFactory();
288 auto selfRef = QtOhos::makeQThreadSafeRef(
this);
289 m_jsScopeData = QOhosJsThreadGateway::eval(
290 [&](QOhosJsState &jsState) {
291 auto jsStatusBarIcon = makeJsStatusBarIcon(jsState, m_icon);
292 auto jsStatusBarGroupMenus = jsStatusBarGroupMenusFactory(jsState);
293 auto optHoverTipsString = qTransform(
295 [](
const auto &toolTip) {
296 return toolTip.toStdString();
298 auto jsStatusBarItem = makeJsStatusBarItem(
299 jsState, jsStatusBarIcon, ohosSystemTrayItemTitle, jsStatusBarGroupMenus, optHoverTipsString);
300 return QtOhos::makeProxyWithJsThreadDeleter(
301 QtOhos::moveToSharedPtr(
303 .m_statusBarItemHandle = addItemToOhosStatusBar(jsState, jsStatusBarItem),
304 .m_iconLeftClickListenerHandle = registerOhosIconLeftClickListener(
307 selfRef.visitInQtThreadIfAlive(
309 Q_EMIT self.activated(QPlatformSystemTrayIcon::Trigger);
316 qOhosPrintfDebug(
"%s: System tray icon initialized", Q_FUNC_INFO);
321 m_jsScopeData.reset();
331 QOhosJsThreadGateway::runAndWait(
332 [&](QOhosJsState &jsState) {
333 updateOhosStatusBarIcon(jsState, makeJsStatusBarIcon(jsState, icon));
340 m_optToolTip = tooltip;
343 QOhosJsThreadGateway::invokeAndWaitForContinue(
344 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
345 updateOhosStatusBarHoverTips(jsState, tooltip.toStdString())
346 .onCatch(QtOhos::makeErrorLoggingJsCallback(
"updateStatusBarHoverTips()"))
347 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
355 return trayIconGeometry;
359 const QString &title,
const QString &msg,
const QIcon &icon, MessageIcon iconType,
int msecs)
362 QOhosJsThreadGateway::invokeAndWaitForContinue(
363 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
364 auto notificationRequest = makeJsNotificationRequest(
365 jsState, title.toStdString(), msg.toStdString(), icon,
366 msecs > 0 ? std::optional(msecs) : std::nullopt);
367 jsState.evalToPromiseOrRejectOnThrow(
"@ohos.notificationManager.publish(*)", {notificationRequest})
368 .onCatch(QtOhos::makeErrorLoggingJsCallback(
"publish()"))
369 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
386 if (m_menu ==
nullptr)
387 return makeQOhosStatusBarMenu().release();
393 qOhosPrintfDebug(
"%s: Updating status bar menu", Q_FUNC_INFO);
397 if (!m_jsScopeData) {
398 qOhosPrintfDebug(
"%s: System tray not initialized yet", Q_FUNC_INFO);
402 auto jsStatusBarGroupMenusFactory =
404 ?
static_cast<QOhosStatusBarMenu *>(m_menu)->makeJsStatusBarGroupMenusFactory()
405 : makeEmptyJsArrayFactory();
407 QOhosJsThreadGateway::runAndWait(
408 [&](QOhosJsState &jsState) {
409 updateOhosStatusBarMenu(jsState, jsStatusBarGroupMenusFactory(jsState));
418 return std::make_unique<QOhosSystemTrayIcon>();
void init() override
This method is called to initialize the platform dependent implementation.
void cleanup() override
This method is called to cleanup the platform dependent implementation.
void showMessage(const QString &title, const QString &msg, const QIcon &icon, MessageIcon iconType, int msecs) override
Shows a balloon message for the entry with the given title, message msg and icon for the time specifi...
void updateMenu(QPlatformMenu *menu) override
This method is called when the system tray menu did change.
QPlatformMenu * createMenu() const override
This method allows platforms to use a different QPlatformMenu for system tray menus than what would n...
QRect geometry() const override
This method returns the geometry of the platform dependent system tray icon on the screen.
bool supportsMessages() const override
Returns true if the system tray supports messages on the platform.
bool isSystemTrayAvailable() const override
Returns true if the system tray is available on the platform.
void updateToolTip(const QString &tooltip) override
This method is called when the tooltip text did change.
void updateIcon(const QIcon &icon) override
This method is called when the icon did change.
QNapi::Promise updateOhosStatusBarHoverTips(QOhosJsState &jsState, const std::string &hoverTips)
std::function< QNapi::Array(QOhosJsState &)> makeEmptyJsArrayFactory()
QNapi::Object makeJsStatusBarItem(QOhosJsState &jsState, QNapi::Object statusBarIcon, const std::string &title, QNapi::Array statusBarGroupMenus, std::optional< std::string > hoverTips)
const auto notificationIconSize
void updateOhosStatusBarMenu(QOhosJsState &jsState, QNapi::Array statusBarGroupMenus)
std::shared_ptr< void > registerOhosIconLeftClickListener(QOhosJsState &jsState, std::function< void()> leftClickListener)
QImage convertIconToScaledImage(const QIcon &icon, const QSize &imageSize, const QColor &fallbackContentColor)
QNapi::Object makeJsStatusBarIcon(QOhosJsState &jsState, const QIcon &icon)
QNapi::Object makeJsPixelMapFromIcon(QOhosJsState &jsState, const QIcon &icon)
void updateOhosStatusBarIcon(QOhosJsState &jsState, QNapi::Object iconData)
std::shared_ptr< void > addItemToOhosStatusBar(QOhosJsState &jsState, QNapi::Object statusBarItem)
std::string applyWorkaroundForEmptyHoverTips(const std::string &hoverTips)
QNapi::Object makeJsNotificationRequest(QOhosJsState &jsState, const std::string &title, const std::string &content, const QIcon &icon, std::optional< int > optAutoDeletedDelayMs)
QNapi::Object getContextForStatusBarManager(QOhosJsState &jsState)
const auto trayIconGeometry
constexpr int quickOperationHeight
void removeIconFromOhosStatusBar(QOhosJsState &jsState)
const std::string ohosSystemTrayItemTitle
QNapi::Object makeJsNotificationContent(QOhosJsState &jsState, const std::string &title, const std::string &text)
QT_BEGIN_NAMESPACE std::unique_ptr< QPlatformSystemTrayIcon > makeQOhosSystemTrayIcon()