9#include <QtCore/qdatetime.h>
10#include <QtCore/qobject.h>
11#include <QtGui/private/qhighdpiscaling_p.h>
12#include <QtGui/private/qohosimageconversions_p.h>
13#include <QtGui/qguiapplication.h>
14#include <QtGui/qicon.h>
15#include <QtGui/qpa/qplatformmenu.h>
16#include <QtGui/qscreen.h>
19#include <qohosplugincore.h>
35 return !hoverTips.empty() ? hoverTips :
" ";
41 return QNapi::Array::New(jsState.env());
49 qOhosReportFatalErrorAndAbort(
"%s: Default QAbilityPeer is not a QUiAbilityPeer", Q_FUNC_INFO);
51 return qUiAbilityPeer->qAbility().eval<QNapi::Object>(
"context");
57 return registerQOhosOnOffMethodsBasedEventHandler(
58 jsState.eval<QNapi::Object>(
"@kit.StatusBarExtensionKit.statusBarManager"),
60 [leftClickListener = std::move(leftClickListener)](
const QtOhos::
CallbackInfo &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 QtOhos::runInJsThreadAndWait(&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);
120 "@kit.StatusBarExtensionKit.statusBarManager.updateStatusBarMenu(*)",
121 {getContextForStatusBarManager(jsState), statusBarGroupMenus});
123 qOhosPrintfDebug(
"%s: Successfully updated status bar menu", Q_FUNC_INFO);
127 QtOhos::
JsState &jsState, QNapi::Object statusBarIcon,
const std::string &title,
128 QNapi::Array statusBarGroupMenus,
std::optional<
std::string> hoverTips)
130 auto *env = jsState.env();
132 auto quickOperation = QNapi::makeObject(
136 {
"height", quickOperationHeight},
140 auto statusBarItem = QNapi::makeObject(
143 {
"icons", statusBarIcon},
144 {
"quickOperation", quickOperation},
145 {
"statusBarGroupMenu", statusBarGroupMenus},
148 if (hoverTips.has_value())
149 statusBarItem.set(
"hoverTips", applyWorkaroundForEmptyHoverTips(hoverTips.value()));
151 return statusBarItem;
155 const QIcon &icon,
const QSize &imageSize,
const QColor &fallbackContentColor)
157 auto iconImage = icon.pixmap(imageSize).toImage();
158 if (!iconImage.isNull())
161 auto fallbackImage = QImage(imageSize, QImage::Format_RGBA8888);
162 fallbackImage.fill(fallbackContentColor);
163 return fallbackImage;
168 const QSize iconSize(48, 48);
169 return makeDisplayDensityScaledJsPixelMapFromQImage(
170 jsState, convertIconToScaledImage(icon, iconSize, Qt::transparent));
175 auto *env = jsState.env();
177 auto trayIcon = makeJsPixelMapFromIcon(jsState, icon);
179 auto imageSize = trayIcon.eval<QNapi::Object>(
"getImageInfoSync().size");
181 int imageWidth = imageSize.get<QNapi::Number>(
"width");
182 int imageHeight = imageSize.get<QNapi::Number>(
"height");
183 qOhosPrintfDebug(
"%s: ceated PixelMap size: %dx%d", Q_FUNC_INFO, imageWidth, imageHeight);
185 return QNapi::makeObject(
198 return QNapi::makeObject(
201 {
"notificationContentType", jsState.mapOhosEnumToJs(ContentType::NOTIFICATION_CONTENT_BASIC_TEXT)},
216 const QIcon &icon,
std::optional<
int> optAutoDeletedDelayMs)
218 auto iconPixelMap = makeDisplayDensityScaledJsPixelMapFromQImage(
219 jsState, convertIconToScaledImage(icon, notificationIconSize, Qt::transparent));
220 auto notificationRequest = QNapi::makeObject(
223 {
"content", makeJsNotificationContent(jsState, title, content)},
224 {
"smallIcon", iconPixelMap},
226 if (optAutoDeletedDelayMs.has_value()) {
227 notificationRequest.set(
229 QDateTime::currentMSecsSinceEpoch() + optAutoDeletedDelayMs.value());
232 return notificationRequest;
235class QOhosSystemTrayIcon
final :
public QPlatformSystemTrayIcon
247 const QString &title,
const QString &msg,
const QIcon &icon,
248 MessageIcon iconType,
int msecs)
override;
257 std::optional<QString> m_optToolTip;
258 QPlatformMenu *m_menu =
nullptr;
262 std::shared_ptr<
void> m_statusBarItemHandle;
263 std::shared_ptr<
void> m_iconLeftClickListenerHandle;
266 std::shared_ptr<JsScopeData> m_jsScopeData;
271void QOhosSystemTrayIcon::
init()
276 auto jsStatusBarGroupMenusFactory =
278 ?
static_cast<QOhosStatusBarMenu *>(m_menu)->makeJsStatusBarGroupMenusFactory()
279 : makeEmptyJsArrayFactory();
281 auto selfRef = QtOhos::makeQThreadSafeRef(
this);
282 m_jsScopeData = QtOhos::evalInJsThread(
283 [&](QtOhos::JsState &jsState) {
284 auto jsStatusBarIcon = makeJsStatusBarIcon(jsState, m_icon);
285 auto jsStatusBarGroupMenus = jsStatusBarGroupMenusFactory(jsState);
286 auto optHoverTipsString = qTransform(
288 [](
const auto &toolTip) {
289 return toolTip.toStdString();
291 auto jsStatusBarItem = makeJsStatusBarItem(
292 jsState, jsStatusBarIcon, ohosSystemTrayItemTitle, jsStatusBarGroupMenus, optHoverTipsString);
293 return QtOhos::makeProxyWithJsThreadDeleter(
294 QtOhos::moveToSharedPtr(
296 .m_statusBarItemHandle = addItemToOhosStatusBar(jsState, jsStatusBarItem),
297 .m_iconLeftClickListenerHandle = registerOhosIconLeftClickListener(
300 selfRef.visitInQtThreadIfAlive(
302 Q_EMIT self.activated(QPlatformSystemTrayIcon::Trigger);
309 qOhosPrintfDebug(
"%s: System tray icon initialized", Q_FUNC_INFO);
314 m_jsScopeData.reset();
326 updateOhosStatusBarIcon(jsState, makeJsStatusBarIcon(jsState, icon));
333 m_optToolTip = tooltip;
337 [&](
QtOhos::
JsState &jsState, QOhosTaskPromise<> taskPromise) {
338 jsState.evalToPromiseOrRejectOnThrow(
339 "@kit.StatusBarExtensionKit.statusBarManager.updateStatusBarHoverTips(*)",
340 {getContextForStatusBarManager(jsState), applyWorkaroundForEmptyHoverTips(tooltip.toStdString())})
341 .onCatch(QtOhos::makeErrorLoggingJsCallback(
"updateStatusBarHoverTips()"))
342 .onFinally(
std::move(taskPromise).makeChained(Q_FUNC_INFO));
350 return trayIconGeometry;
354 const QString &title,
const QString &msg,
const QIcon &icon, MessageIcon iconType,
int msecs)
358 [&](
QtOhos::
JsState &jsState, QOhosTaskPromise<> taskPromise) {
359 auto notificationRequest = makeJsNotificationRequest(
360 jsState, title.toStdString(), msg.toStdString(), icon,
361 msecs > 0 ? std::optional(msecs) : std::nullopt);
362 jsState.evalToPromiseOrRejectOnThrow(
"@ohos.notificationManager.publish(*)", {notificationRequest})
363 .onCatch(QtOhos::makeErrorLoggingJsCallback(
"publish()"))
364 .onFinally(
std::move(taskPromise).makeChained(Q_FUNC_INFO));
381 if (m_menu ==
nullptr)
382 return makeQOhosStatusBarMenu().release();
388 qOhosPrintfDebug(
"%s: Updating status bar menu", Q_FUNC_INFO);
392 if (!m_jsScopeData) {
393 qOhosPrintfDebug(
"%s: System tray not initialized yet", Q_FUNC_INFO);
397 auto jsStatusBarGroupMenusFactory =
399 ?
static_cast<QOhosStatusBarMenu *>(m_menu)->makeJsStatusBarGroupMenusFactory()
400 : makeEmptyJsArrayFactory();
404 updateOhosStatusBarMenu(jsState, jsStatusBarGroupMenusFactory(jsState));
413 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.
virtual std::shared_ptr< QAbilityPeer > defaultQAbilityPeer()=0
static std::shared_ptr< QUiAbilityPeer > tryCastFromQAbilityPeerOrNull(std::shared_ptr< QAbilityPeer > qAbilityPeer)
const auto notificationIconSize
QNapi::Object makeJsStatusBarIcon(QtOhos::JsState &jsState, const QIcon &icon)
QImage convertIconToScaledImage(const QIcon &icon, const QSize &imageSize, const QColor &fallbackContentColor)
QNapi::Object makeJsNotificationRequest(QtOhos::JsState &jsState, const std::string &title, const std::string &content, const QIcon &icon, std::optional< int > optAutoDeletedDelayMs)
std::shared_ptr< void > addItemToOhosStatusBar(QtOhos::JsState &jsState, QNapi::Object statusBarItem)
QNapi::Object getContextForStatusBarManager(QtOhos::JsState &jsState)
QNapi::Object makeJsNotificationContent(QtOhos::JsState &jsState, const std::string &title, const std::string &text)
QNapi::Object makeJsPixelMapFromIcon(QtOhos::JsState &jsState, const QIcon &icon)
std::string applyWorkaroundForEmptyHoverTips(const std::string &hoverTips)
QNapi::Object makeJsStatusBarItem(QtOhos::JsState &jsState, QNapi::Object statusBarIcon, const std::string &title, QNapi::Array statusBarGroupMenus, std::optional< std::string > hoverTips)
std::function< QNapi::Array(QtOhos::JsState &)> makeEmptyJsArrayFactory()
void removeIconFromOhosStatusBar(QtOhos::JsState &jsState)
void updateOhosStatusBarIcon(QtOhos::JsState &jsState, QNapi::Object iconData)
const auto trayIconGeometry
constexpr int quickOperationHeight
std::shared_ptr< void > registerOhosIconLeftClickListener(QtOhos::JsState &jsState, std::function< void()> leftClickListener)
const std::string ohosSystemTrayItemTitle
void updateOhosStatusBarMenu(QtOhos::JsState &jsState, QNapi::Array statusBarGroupMenus)
void runInJsThreadAndWait(const std::function< void(JsState &)> &task, std::string callerContextName={})
void invokeInJsThreadAndWaitForContinue(std::function< void(JsState &, QOhosTaskPromise<>)> &&task, std::string callerContextName={})
QT_BEGIN_NAMESPACE std::unique_ptr< QPlatformSystemTrayIcon > makeQOhosSystemTrayIcon()