16 QNapi::Object eventSourceObject,
const std::string &eventTypeName,
21 std::function<QNapi::Value(
const CallbackInfo &)> eventHandler;
22 std::function<
bool(QNapi::Object)> eventSourceAliveCheckFunc;
23 QNapi::Reference<QNapi::Value> optExtraOnArg;
24 QNapi::Reference<QNapi::Value> optExtraOffArg;
27 auto env = eventSourceObject.Env();
29 auto sharedContext = moveToSharedPtr(
31 .eventHandler = std::move(eventHandler.callbackFunc()),
32 .eventSourceAliveCheckFunc = options.optEventSourceAliveCheckFunc
33 ? std::move(options.optEventSourceAliveCheckFunc)
37 .optExtraOnArg = options.extraOnArg.hasValue()
38 ? QNapi::Reference<>::makePersistentFrom(
39 options.extraOnArg.value().mapToValue(env))
40 : QNapi::Reference<>::makeEmpty(),
41 .optExtraOffArg = options.extraOffArg.hasValue()
42 ? QNapi::Reference<>::makePersistentFrom(
43 options.extraOffArg.value().mapToValue(env))
44 : QNapi::Reference<>::makeEmpty(),
47 auto jsEventHandlerRef = moveToSharedPtr(
48 QNapi::Reference<>::makePersistentFrom(
50 eventSourceObject.Env(),
51 [eventTypeName, weakContext = makeWeakPtr(sharedContext)](
const CallbackInfo &cbInfo) {
52 auto sharedContext = weakContext.lock();
54 return sharedContext->eventHandler(cbInfo);
57 "%s: got unexpected '%s' event callback call for detached handler",
58 Q_FUNC_INFO, eventTypeName.c_str());
59 return cbInfo.Env().Undefined();
63 std::vector<QNapi::ValueWrapper> onCallArgs;
64 onCallArgs.push_back(eventTypeName);
65 if (!sharedContext->optExtraOnArg.IsEmpty())
66 onCallArgs.push_back(sharedContext->optExtraOnArg.Value());
67 onCallArgs.push_back(jsEventHandlerRef->Value());
68 eventSourceObject.call(
"on", onCallArgs);
70 auto eventSourceWeakRef = moveToSharedPtr(Napi::Weak(eventSourceObject));
72 return makeProxyWithJsThreadDeleter(
73 QtOhos::makeDestroyNotifier(
74 [eventSourceWeakRef, eventTypeName, sharedContext, jsEventHandlerRef]() {
75 auto eventSourceValue = eventSourceWeakRef->Value();
76 if (eventSourceValue.IsObject()) {
77 auto eventSourceObject = QNapi::checkedCast<QNapi::Object>(eventSourceValue);
78 if (sharedContext->eventSourceAliveCheckFunc(eventSourceObject)) {
80 std::vector<QNapi::ValueWrapper> offCallArgs;
81 offCallArgs.push_back(eventTypeName);
82 if (!sharedContext->optExtraOffArg.IsEmpty())
83 offCallArgs.push_back(sharedContext->optExtraOffArg.Value());
84 offCallArgs.push_back(jsEventHandlerRef->Value());
85 eventSourceObject.call(
"off", offCallArgs);
86 }
catch (
const Napi::Error &e) {
88 "%s: got exception from off(%s, ...) call (ignoring): %s",
89 Q_FUNC_INFO, eventTypeName.c_str(), e.what());
93 "%s: not calling off(%s, ...), event source 'considered' not alive",
94 Q_FUNC_INFO, eventTypeName.c_str());
98 "%s: not calling off(%s, ...), event source not alive",
99 Q_FUNC_INFO, eventTypeName.c_str());
104std::shared_ptr<
void> startDelayedJsThreadTask(
106 std::chrono::milliseconds delay)
114 auto context =
std::make_shared<Context>();
115 context->task =
std::move(task);
117 int timerId = jsState.eval<QNapi::Number>(
118 "Global.setTimeout(*)",
120 [context](
const CallbackInfo &cbInfo) {
122 auto task = std::exchange(context->task,
nullptr);
123 context->timerId.reset();
124 task(cbInfo.jsState());
127 std::max(delay, std::chrono::milliseconds(0)).count(),
129 context->timerId = timerId;
131 return QtOhos::makeDestroyNotifier(
133 if (context->timerId.hasValue()) {
134 runInJsThreadAndWait(
135 [&](JsState &jsState) {
136 jsState.eval(
"Global.clearTimeout(*)", {context->timerId.value()});
138 context->task =
nullptr;
139 context->timerId.reset();