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>
18#include <qohosplugincore.h>
34 return !hoverTips.empty() ? hoverTips :
" ";
40 return QNapi::Array::New(jsState.env());
48 qOhosReportFatalErrorAndAbort(
"%s: Default QAbilityPeer is not a QUiAbilityPeer", Q_FUNC_INFO);
50 return qUiAbilityPeer->qAbility().eval<QNapi::Object>(
"context");
56 return registerQOhosOnOffMethodsBasedEventHandler(
57 jsState.eval<QNapi::Object>(
"@kit.StatusBarExtensionKit.statusBarManager"),
59 [leftClickListener = std::move(leftClickListener)](
const QtOhos::
CallbackInfo &cbInfo) {
60 auto eventData = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
61 auto optIconClickType = QNapi::getOptionalPropOrEmpty<QNapi::String>(
62 QNapi::getOptionalPropOrEmpty<QNapi::Object>(eventData,
"data"),
65 if (optIconClickType.IsEmpty()) {
67 "%s: no 'iconClickType' in the event (%s), ignoring it",
68 Q_FUNC_INFO, QNapi::toJsonString(eventData).c_str());
72 if (optIconClickType.Utf8Value() ==
"leftClick")
80 "@kit.StatusBarExtensionKit.statusBarManager.removeFromStatusBar(*)",
81 {getContextForStatusBarManager(jsState)});
83 qOhosPrintfDebug(
"%s: Successfully removed icon from status bar", Q_FUNC_INFO);
89 "@kit.StatusBarExtensionKit.statusBarManager.addToStatusBar(*)",
90 {getContextForStatusBarManager(jsState), statusBarItem});
92 qOhosPrintfDebug(
"%s: Successfully added icon to status bar [Statusbar] ", Q_FUNC_INFO);
94 return QtOhos::makeDestroyNotifier(
96 QtOhos::runInJsThreadAndWait(&removeIconFromOhosStatusBar, Q_FUNC_INFO);
102 qOhosPrintfDebug(
"%s", Q_FUNC_INFO);
104 if (iconData.IsEmpty()) {
105 qOhosPrintfError(
"%s: Icon data is empty", Q_FUNC_INFO);
110 "@kit.StatusBarExtensionKit.statusBarManager.updateStatusBarIcon(*)",
111 {getContextForStatusBarManager(jsState), iconData});
113 qOhosPrintfDebug(
"%s: Successfully updated status bar icon", Q_FUNC_INFO);
119 "@kit.StatusBarExtensionKit.statusBarManager.updateStatusBarMenu(*)",
120 {getContextForStatusBarManager(jsState), statusBarGroupMenus});
122 qOhosPrintfDebug(
"%s: Successfully updated status bar menu", Q_FUNC_INFO);
126 QtOhos::
JsState &jsState, QNapi::Object statusBarIcon,
const std::string &title,
127 QNapi::Array statusBarGroupMenus, QOhosOptional<std::string> hoverTips)
129 auto *env = jsState.env();
131 auto quickOperation = QNapi::makeObject(
135 {
"height", quickOperationHeight},
139 auto statusBarItem = QNapi::makeObject(
142 {
"icons", statusBarIcon},
143 {
"quickOperation", quickOperation},
144 {
"statusBarGroupMenu", statusBarGroupMenus},
147 if (hoverTips.has_value())
148 statusBarItem.set(
"hoverTips", applyWorkaroundForEmptyHoverTips(hoverTips.value()));
150 return statusBarItem;
154 const QIcon &icon,
const QSize &imageSize,
const QColor &fallbackContentColor)
156 auto iconImage = icon.pixmap(imageSize).toImage();
157 if (!iconImage.isNull())
160 auto fallbackImage = QImage(imageSize, QImage::Format_RGBA8888);
161 fallbackImage.fill(fallbackContentColor);
162 return fallbackImage;
167 const QSize iconSize(48, 48);
168 QImage iconImage = icon.pixmap(iconSize).toImage();
170 createDisplayDensityScaledJsMonochromePixelMapFromIconImage(jsState, iconImage, isWhiteIcon);
174 QImage defaultImage(iconSize, QImage::Format_RGBA8888);
175 defaultImage.fill(isWhiteIcon ? Qt::white : Qt::black);
176 return makeDisplayDensityScaledJsPixelMapFromQImage(jsState, defaultImage);
181 auto *env = jsState.env();
183 auto whitePixelMap = makeJsPixelMapFromIcon(jsState, icon,
true);
184 auto blackPixelMap = makeJsPixelMapFromIcon(jsState, icon,
false);
186 auto imageSize = whitePixelMap.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(
195 {
"white", whitePixelMap},
196 {
"black", blackPixelMap},
205 return QNapi::makeObject(
208 {
"notificationContentType", jsState.mapOhosEnumToJs(ContentType::NOTIFICATION_CONTENT_BASIC_TEXT)},
223 const QIcon &icon, QOhosOptional<
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 QOhosOptional<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 = QtOhos::evalInJsThread(
290 [&](QtOhos::JsState &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();
333 updateOhosStatusBarIcon(jsState, makeJsStatusBarIcon(jsState, icon));
340 m_optToolTip = tooltip;
344 [&](
QtOhos::
JsState &jsState, QOhosTaskPromise<> taskPromise) {
345 jsState.evalToPromiseOrRejectOnThrow(
346 "@kit.StatusBarExtensionKit.statusBarManager.updateStatusBarHoverTips(*)",
347 {getContextForStatusBarManager(jsState), applyWorkaroundForEmptyHoverTips(tooltip.toStdString())})
348 .onCatch(QtOhos::makeErrorLoggingJsCallback(
"updateStatusBarHoverTips()"))
349 .onFinally(
std::move(taskPromise).makeChained(Q_FUNC_INFO));
357 return trayIconGeometry;
361 const QString &title,
const QString &msg,
const QIcon &icon, MessageIcon iconType,
int msecs)
365 [&](
QtOhos::
JsState &jsState, QOhosTaskPromise<> taskPromise) {
366 auto notificationRequest = makeJsNotificationRequest(
367 jsState, title.toStdString(), msg.toStdString(), icon,
368 msecs > 0 ? makeQOhosOptional(msecs) : makeEmptyQOhosOptional());
369 jsState.evalToPromiseOrRejectOnThrow(
"@ohos.notificationManager.publish(*)", {notificationRequest})
370 .onCatch(QtOhos::makeErrorLoggingJsCallback(
"publish()"))
371 .onFinally(
std::move(taskPromise).makeChained(Q_FUNC_INFO));
388 if (m_menu ==
nullptr)
389 return makeQOhosStatusBarMenu().release();
395 qOhosPrintfDebug(
"%s: Updating status bar menu", Q_FUNC_INFO);
399 if (!m_jsScopeData) {
400 qOhosPrintfDebug(
"%s: System tray not initialized yet", Q_FUNC_INFO);
404 auto jsStatusBarGroupMenusFactory =
406 ?
static_cast<QOhosStatusBarMenu *>(m_menu)->makeJsStatusBarGroupMenusFactory()
407 : makeEmptyJsArrayFactory();
411 updateOhosStatusBarMenu(jsState, jsStatusBarGroupMenusFactory(jsState));
420 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 makeJsStatusBarItem(QtOhos::JsState &jsState, QNapi::Object statusBarIcon, const std::string &title, QNapi::Array statusBarGroupMenus, QOhosOptional< std::string > hoverTips)
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)
std::string applyWorkaroundForEmptyHoverTips(const std::string &hoverTips)
std::function< QNapi::Array(QtOhos::JsState &)> makeEmptyJsArrayFactory()
void removeIconFromOhosStatusBar(QtOhos::JsState &jsState)
QNapi::Object makeJsNotificationRequest(QtOhos::JsState &jsState, const std::string &title, const std::string &content, const QIcon &icon, QOhosOptional< int > optAutoDeletedDelayMs)
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
QNapi::Object makeJsPixelMapFromIcon(QtOhos::JsState &jsState, const QIcon &icon, bool isWhiteIcon)
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()