Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohosjsutils.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qohosjsutils.h"
5#include <QtCore/private/qohoscommon_p.h>
6#include <qohosutils.h>
7#include <utility>
8
9using namespace std::chrono_literals;
10
11QT_BEGIN_NAMESPACE
12
13namespace QtOhos {
14
16 QNapi::Object eventSourceObject, const std::string &eventTypeName,
17 QNapi::CallbackFuncWrapper eventHandler, OnOffMethodsBasedEventHandlerOptions options)
18{
19 struct Context
20 {
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;
25 };
26
27 auto env = eventSourceObject.Env();
28
29 auto sharedContext = moveToSharedPtr(
30 Context{
31 .eventHandler = std::move(eventHandler.callbackFunc()),
32 .eventSourceAliveCheckFunc = options.optEventSourceAliveCheckFunc
33 ? std::move(options.optEventSourceAliveCheckFunc)
34 : [](QNapi::Object) {
35 return true;
36 },
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(),
45 });
46
47 auto jsEventHandlerRef = moveToSharedPtr(
48 QNapi::Reference<>::makePersistentFrom(
49 QNapi::Function::New(
50 eventSourceObject.Env(),
51 [eventTypeName, weakContext = makeWeakPtr(sharedContext)](const CallbackInfo &cbInfo) {
52 auto sharedContext = weakContext.lock();
53 if (sharedContext) {
54 return sharedContext->eventHandler(cbInfo);
55 } else {
56 qOhosPrintfWarning(
57 "%s: got unexpected '%s' event callback call for detached handler",
58 Q_FUNC_INFO, eventTypeName.c_str());
59 return cbInfo.Env().Undefined();
60 }
61 })));
62
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);
69
70 auto eventSourceWeakRef = moveToSharedPtr(Napi::Weak(eventSourceObject));
71
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)) {
79 try {
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) {
87 qOhosPrintfError(
88 "%s: got exception from off(%s, ...) call (ignoring): %s",
89 Q_FUNC_INFO, eventTypeName.c_str(), e.what());
90 }
91 } else {
92 qOhosPrintfDebug(
93 "%s: not calling off(%s, ...), event source 'considered' not alive",
94 Q_FUNC_INFO, eventTypeName.c_str());
95 }
96 } else {
97 qOhosPrintfDebug(
98 "%s: not calling off(%s, ...), event source not alive",
99 Q_FUNC_INFO, eventTypeName.c_str());
100 }
101 }));
102}
103
104std::shared_ptr<void> startDelayedJsThreadTask(
105 JsState &jsState, std::function<void(JsState &)> task,
106 std::chrono::milliseconds delay)
107{
108 struct Context
109 {
110 std::function<void(JsState &)> task;
111 QOhosOptional<int> timerId;
112 };
113
114 auto context = std::make_shared<Context>();
115 context->task = std::move(task);
116
117 int timerId = jsState.eval<QNapi::Number>(
118 "Global.setTimeout(*)",
119 {
120 [context](const CallbackInfo &cbInfo) {
121 if (context->task) {
122 auto task = std::exchange(context->task, nullptr);
123 context->timerId.reset();
124 task(cbInfo.jsState());
125 }
126 },
127 std::max(delay, std::chrono::milliseconds(0)).count(),
128 });
129 context->timerId = timerId;
130
131 return QtOhos::makeDestroyNotifier(
132 [context]() {
133 if (context->timerId.hasValue()) {
134 runInJsThreadAndWait(
135 [&](JsState &jsState) {
136 jsState.eval("Global.clearTimeout(*)", {context->timerId.value()});
137 });
138 context->task = nullptr;
139 context->timerId.reset();
140 }
141 });
142}
143
145 JsState &jsState, std::function<void(const CallbackInfo &)> timeoutFunc,
146 std::chrono::milliseconds delay)
147{
148 int timerId = jsState.eval<QNapi::Number>(
149 "Global.setTimeout(*)", {std::move(timeoutFunc), delay.count()});
150 return timerId;
151}
152
153void clearJsTimeout(JsState &jsState, int timerId)
154{
155 jsState.eval("Global.clearTimeout(*)", {timerId});
156}
157
158QNapi::Promise makeResolvedPromise(QNapi::Value valueForResolve)
159{
160 auto promiseDeferred = QNapi::Promise::Deferred::New(valueForResolve.Env());
161 promiseDeferred.Resolve(valueForResolve);
162 return promiseDeferred.Promise();
163}
164
166{
167 if (!error.Value().IsObject())
168 return {};
169
170 auto errorObject = QNapi::checkedCast<QNapi::Object>(error.Value());
171 auto optErrorCode = QNapi::getOptionalPropOrEmpty<QNapi::Number>(errorObject, "code");
172
173 return !optErrorCode.IsEmpty()
174 ? makeQOhosOptional(optErrorCode.Uint32Value())
176}
177
178}
179
180QT_END_NAMESPACE
std::enable_if_t< qohosplugincore_h_detail::isQOhosOptional< QOhosInvokeResult< Func, T > >, QOhosInvokeResult< Func, T > > andThen(Func &&func) const
std::shared_ptr< void > registerOnOffMethodsBasedEventHandler(QNapi::Object eventSourceObject, const std::string &eventTypeName, QNapi::CallbackFuncWrapper handler, OnOffMethodsBasedEventHandlerOptions options={})
void clearJsTimeout(JsState &jsState, int timerId)
int setJsTimeout(JsState &jsState, std::function< void(const CallbackInfo &)> timeoutFunc, std::chrono::milliseconds delay)
QNapi::Promise makeResolvedPromise(QNapi::Value valueForResolve)
QOhosOptional< std::uint32_t > tryGetCodeFromJsBusinessError(const Napi::Error &error)
QOhosOptional< void > makeEmptyQOhosOptional()