Source code

Revision control

Copy as Markdown

// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOHOSPLUGINCORE_H
#define QOHOSPLUGINCORE_H
#include <QtCore/private/qcore_ohos_p.h>
#include <QtCore/private/qnapi_p.h>
#include <QtCore/private/qohoscommon_p.h>
#include <atomic>
#include <chrono>
#include <cstdlib>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <qohosqpaenums.h>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <vector>
QT_BEGIN_NAMESPACE
namespace QtOhos {
class JsWindowsTracker
{
public:
static void tagWindowAsClosing(QNapi::Object jsWindow, const char *logContext);
static bool isWindowClosing(QNapi::Object jsWindow);
JsWindowsTracker() = delete;
};
class QAbilityPeer
{
public:
virtual ~QAbilityPeer();
virtual std::string instanceId() = 0;
virtual QNapi::Object uiContext() = 0;
virtual QNapi::Object qAbility() = 0;
virtual QNapi::Object launchWant() = 0;
virtual QObjectThreadSafeRef qWindowRef() = 0;
virtual std::optional<QNapi::Promise> qWindowDestroyPromise() = 0;
virtual void forceResolveQWindowDestroyPromiseIfPresent(Napi::Env env) = 0;
virtual std::shared_ptr<std::atomic_bool> destroyAllowedFlag() = 0;
virtual void setQWindow(Napi::Env env, QObjectThreadSafeRef qwindow) = 0;
virtual void *tryCastWithTypeIdObject(const void *matchTypeIdObject) = 0;
protected:
QAbilityPeer();
};
class JsState;
class AppFunctions
{
public:
virtual ~AppFunctions();
virtual void startQAbilityInstance(
QNapi::Object baseQAbility, QObjectThreadSafeRef qwindow,
QNapi::Object optStartOptions,
std::function<void(JsState &, std::shared_ptr<QAbilityPeer>)> startupNotifyFunc) = 0;
virtual void startAppProcess(
QNapi::Object baseQAbility, const std::string &processId, QNapi::Object want,
QNapi::Object optStartOptions, std::function<void(JsState &)> continueFunc) = 0;
virtual void startNoUiChildProcess(JsState &jsState, const std::string &libraryName, const std::vector<std::string> &args) = 0;
};
enum class QtRunMode
{
Normal,
NoUiChildProcess,
};
class JsState : public QOhosJsState
{
public:
static JsState &castFrom(QOhosJsState &jsState);
JsState(const JsState &) = delete;
JsState &operator=(const JsState &) = delete;
~JsState() override;
virtual std::shared_ptr<QAbilityPeer> defaultQAbilityPeer() = 0;
virtual std::shared_ptr<QAbilityPeer> tryGetQAbilityPeerByInstanceId(const std::string &instanceId) = 0;
virtual std::shared_ptr<QAbilityPeer> tryGetQAbilityPeerByInstance(QNapi::Object qAbility) = 0;
virtual void visitEachQAbilityPeer(const std::function<void(std::shared_ptr<QAbilityPeer>)> &visitor) = 0;
virtual void startNewQAbilityInstance(
QNapi::Object baseQAbility, QObjectThreadSafeRef qwindow,
QNapi::Object optStartOptions,
std::function<void(JsState &, std::shared_ptr<QAbilityPeer>)> startupNotifyFunc) = 0;
virtual QtRunMode qtRunMode() = 0;
template<typename T>
QNapi::Symbol getJsSymbolForType();
protected:
JsState();
private:
virtual QNapi::Symbol getJsSymbolForType(const std::type_info &typeInfo) = 0;
};
using QOhosAbilityOnContinueResult = QtOhosQpa::enums::ohos::app::ability::AbilityConstant::OnContinueResult;
class QUiAbilityPeer : public virtual QAbilityPeer, public std::enable_shared_from_this<QUiAbilityPeer>
{
public:
static std::shared_ptr<QUiAbilityPeer> tryCastFromQAbilityPeerOrNull(std::shared_ptr<QAbilityPeer> qAbilityPeer);
~QUiAbilityPeer() override;
virtual QNapi::Object launchParam() = 0;
virtual QNapi::Object windowStage() = 0;
virtual QNapi::Object window() = 0;
virtual void setOnContinueRequestsHandler(
std::function<void(JsState &, QNapi::Object, QOhosConsumer<JsState &, QOhosAbilityOnContinueResult>)> requestsHandler) = 0;
protected:
QUiAbilityPeer();
private:
static const nullptr_t typeIdObject;
void *tryCastWithTypeIdObject(const void *matchTypeIdObject) final;
};
class CallbackInfo : public ::QOhosCallbackInfo
{
public:
using ::QOhosCallbackInfo::QOhosCallbackInfo;
JsState &jsState() const;
};
// this function should be called once from JS thread at some point during startup
void initJsThreadState(
napi_env env, std::map<std::string, QNapi::Reference<QNapi::Function>> &&jsModulesFactories,
std::shared_ptr<AppFunctions> appFunctions, QtRunMode qtRunMode);
// returns true iff the calling thread is the JS thread
bool isJsThread();
// this function should be called from JS thread for each UIAbility when it's ready
void addJsQAbilityPeer(std::shared_ptr<QAbilityPeer> qAbilityPeer);
// this function should be called from JS thread when WindowStage of UIAbility is destroyed
void removeMatchingJsQAbilityPeer(QNapi::Object qAbility);
// this function should be called from JS thread when new Want object is received
void dispatchNewWant(QNapi::Object qAbility, QNapi::Object want, QNapi::Object launchParam);
// Invokes the task inside the Qt thread and blocks the caller's thread until either:
// - the "continue" function (std::function<void()>, passed as second argument to
// the task) is called on the Qt side and returns,
// - timeout occurs (we don't receive response from the finished task within the
// specified time limit),
// - deadlock is detected (both Qt and JS thread use synchronous calls at the same
// time).
// It can be called from the JS thread. Calling it from the Qt thread is illegal.
//
// Returns true iff the caller receives confirmation about finishing the task within
// the time limit.
//
// Note:
// If the function returns false then:
// - either the task wasn't started at all (timeout or deadlock)
// - or the task was still running (and may be still running!) in the Qt thread
// after reaching the timeout.
Q_REQUIRED_RESULT bool tryInvokeInQtThreadAndTryWaitForContinue(
std::function<void(std::function<void()>)> &&task,
std::chrono::nanoseconds timeout);
template<typename T>
QNapi::Symbol JsState::getJsSymbolForType()
{
return getJsSymbolForType(typeid(T));
}
}
QT_END_NAMESPACE
#endif