Wrap some native objects during event dispatch

This commit is contained in:
Simon Edwards 2021-11-06 20:41:04 +01:00
parent 2dc8319b50
commit 7ae4a5cb7e
7 changed files with 60 additions and 11 deletions

View File

@ -4,7 +4,9 @@
#ifndef COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE
#define COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE(ComponentWrapName) \
\
InstanceValue("type", Napi::String::New(env, "native")),
InstanceValue("type", Napi::String::New(env, "native")), \
InstanceValue("wrapperType", \
Napi::String::New(env, #ComponentWrapName)),
#endif
#ifndef COMPONENT_WRAPPED_METHODS_DECLARATION

View File

@ -47,12 +47,10 @@ class DLL_EXPORT WrapperCache : public QObject {
Napi::Object get(Napi::Env env, T* object) {
if (this->cache.contains(object)) {
napi_value result = nullptr;
napi_get_reference_value(this->cache[object].env, this->cache[object].ref,
&result);
napi_get_reference_value(env, this->cache[object].ref, &result);
return Napi::Object(env, result);
}
Napi::HandleScope scope(env);
Napi::Object wrapper =
W::constructor.New({Napi::External<T>::New(env, object)});
@ -67,7 +65,6 @@ class DLL_EXPORT WrapperCache : public QObject {
}
static Napi::Object init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
exports.Set("WrapperCache_injectCallback",
Napi::Function::New<injectDestroyCallback>(env));
return exports;
@ -75,7 +72,6 @@ class DLL_EXPORT WrapperCache : public QObject {
static Napi::Value injectDestroyCallback(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
destroyedCallback = Napi::Persistent(info[0].As<Napi::Function>());
return env.Null();
@ -95,6 +91,7 @@ class DLL_EXPORT WrapperCache : public QObject {
Napi::Env env = destroyedCallback.Env();
Napi::HandleScope scope(env);
destroyedCallback.Call(
env.Global(),
{Napi::Value::From(env, extrautils::hashPointerTo53bit(object))});
}

View File

@ -168,7 +168,13 @@ export { FlexLayout, FlexLayoutSignals } from './lib/core/FlexLayout';
// Others:
export { StyleSheet } from './lib/core/Style/StyleSheet';
export { NativeElement, Component } from './lib/core/Component';
export { checkIfNativeElement, checkIfNapiExternal } from './lib/utils/helpers';
export {
checkIfNativeElement,
checkIfNapiExternal,
JsWrapFunction,
registerNativeWrapFunction as registerNativeWrapper,
wrapNative,
} from './lib/utils/helpers';
export { Margins } from './lib/utils/Margins';
// Test:

View File

@ -1,9 +1,10 @@
import { NativeElement } from '../core/Component';
import { checkIfNativeElement } from '../utils/helpers';
import { checkIfNativeElement, registerNativeWrapFunction } from '../utils/helpers';
import { NodeObject, QObjectSignals } from '../QtCore/QObject';
import { QRect } from '../QtCore/QRect';
import { QSizeF } from '../QtCore/QSizeF';
import { QSize } from '../QtCore/QSize';
import { wrapperCache } from '../core/WrapperCache';
export class QScreen extends NodeObject<QScreenSignals> {
native: NativeElement;
@ -104,3 +105,7 @@ export interface QScreenSignals extends QObjectSignals {
refreshRateChanged: (refreshRate: number) => void;
virtualGeometryChanged: (rect: QRect) => void;
}
registerNativeWrapFunction('QScreenWrap', (native: any) => {
return wrapperCache.get<QScreen>(QScreen, native);
});

View File

@ -1,5 +1,5 @@
import { NativeElement } from '../core/Component';
import { checkIfNativeElement } from '../utils/helpers';
import { checkIfNativeElement, registerNativeWrapFunction } from '../utils/helpers';
import { NodeObject, QObjectSignals } from '../QtCore/QObject';
import { QScreen } from './QScreen';
import { wrapperCache } from '../core/WrapperCache';
@ -24,3 +24,7 @@ export class QWindow extends NodeObject<QWindowSignals> {
export interface QWindowSignals extends QObjectSignals {
screenChanged: (screen: QScreen) => void;
}
registerNativeWrapFunction('QWindowWrap', (native: any) => {
return wrapperCache.get<QWindow>(QWindow, native);
});

View File

@ -1,6 +1,6 @@
import { EventEmitter } from 'events';
import { NativeElement, Component, NativeRawPointer } from './Component';
import { wrapWithActivateUvLoop } from '../utils/helpers';
import { wrapNative, wrapWithActivateUvLoop } from '../utils/helpers';
function addDefaultErrorHandler(native: NativeElement, emitter: EventEmitter): void {
native.subscribeToQtEvent('error');
@ -54,10 +54,11 @@ export abstract class EventWidget<Signals extends unknown> extends Component {
// Preserve the value of `_isQObjectEventProcessed` as we dispatch this event
// to JS land, and restore it afterwards. This lets us support recursive event
// dispatches on the same object.
const wrappedArgs = args.map(wrapNative);
const previousEventProcessed = this._isEventProcessed;
this._isEventProcessed = false;
try {
this.emitter.emit(event, ...args);
this.emitter.emit(event, ...wrappedArgs);
} catch (e) {
console.log(`An exception was thrown while dispatching an event of type '${event.toString()}':`);
console.log(e);

View File

@ -25,3 +25,37 @@ export function wrapWithActivateUvLoop<T extends Function>(func: T): T {
};
return fn as any;
}
export type JsWrapFunction = (element: any) => any;
const nativeWrapperRegistry = new Map<string, JsWrapFunction>();
/**
* Register a function to wrap a specific Node API wrapper objects with a JS object.
*
* @param wrapperTypeName the C++ wrapper type name the wrap function applies to.
* @param jsWrapFunction function to wrap a native wrapper to a JS wrapper object.
*/
export function registerNativeWrapFunction(wrapperTypeName: string, jsWrapFunction: JsWrapFunction): void {
nativeWrapperRegistry.set(wrapperTypeName, jsWrapFunction);
}
/**
* Try to wrap a native Node object with its JS wrapper.
*
* @param native the native object to wrap
* @return the JS object wrapping the native object or the native object if
* it couldn't be wrapped or doesn't need to be wrapped.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function wrapNative(native: any): any {
if (!checkIfNativeElement(native)) {
return native;
}
const func: JsWrapFunction | undefined = nativeWrapperRegistry.get(native.wrapperType);
if (func == null) {
return native;
}
return func(native);
}