diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 84846c29..f92ba922 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -1,6 +1,55 @@ name: main on: [push, pull_request] jobs: + build-windows: + name: windows - nodejs ${{ matrix.node }} + runs-on: windows-latest + strategy: + matrix: + node: + - 16 + - 12 + defaults: + run: + shell: msys2 {0} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + - uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + path-type: inherit + update: true + install: | + git + mingw-w64-x86_64-gobject-introspection + mingw-w64-x86_64-gtk3 + mingw-w64-x86_64-cairo + mingw-w64-x86_64-gstreamer + mingw-w64-x86_64-gst-plugins-good + mingw-w64-x86_64-gst-plugins-bad + mingw-w64-x86_64-libsoup + + - name: Install VS 2017 + shell: cmd + run: choco upgrade -y visualstudio2017-workload-vctools + + - name: Install & Build + run: | + ./windows/mingw_include_extra.sh + export MINGW_WINDOWS_PATH=$(./windows/mingw_windows_path.sh) + npm config set msvs_version 2017 + npm install --build-from-source + + - name: Run tests + run: | + npx mocha \ + --skip=callback \ + --skip=signal__non-introspected \ + tests/__run__.js + build: name: ${{ matrix.os }} - nodejs ${{ matrix.node }} runs-on: ${{ matrix.os }} diff --git a/README.md b/README.md index 3a3a3adf..bc2ecdf1 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,13 @@ cd ~/oss git clone https://github.com/romgrk/node-gtk cd node-gtk +# don't include /mingw64/include directly since it conflicts with +# Windows SDK headers. we copy needed headers to __extra__ directory: +./windows/mingw_include_extra.sh + +# if MSYS2 is NOT installed in C:/msys64 run: +export MINGW_WINDOWS_PATH=$(./windows/mingw_windows_path.sh) + # first run might take a while GYP_MSVS_VERSION=2015 npm install ``` diff --git a/binding.gyp b/binding.gyp index 6c47270a..fed88c24 100644 --- a/binding.gyp +++ b/binding.gyp @@ -39,21 +39,20 @@ "include_dirs" : [ " &info) { boxed = g_boxed_copy (gtype, boxed); } else if ((size = Boxed::GetSize(gi_info)) != 0) { - void *boxedCopy = malloc(size); + void *boxedCopy = g_malloc(size); memcpy(boxedCopy, boxed, size); boxed = boxedCopy; } @@ -223,7 +223,7 @@ static void BoxedConstructor(const Nan::FunctionCallbackInfo &info) { boxed = return_value.v_pointer; } else if ((size = Boxed::GetSize(gi_info)) != 0) { - boxed = calloc(1, size); + boxed = g_malloc0(size); } else { Nan::ThrowError("Boxed allocation failed: no constructor found"); @@ -267,7 +267,7 @@ static void BoxedDestroyed(const Nan::WeakCallbackInfo &info) { } else if (box->size != 0) { // Allocated in ./function.cc @ AllocateArgument - free(box->data); + g_free(box->data); } else if (box->data != NULL) { /* diff --git a/src/callback.cc b/src/callback.cc index 7dd55b1d..273bd421 100644 --- a/src/callback.cc +++ b/src/callback.cc @@ -22,7 +22,7 @@ using Nan::TryCatch; namespace GNodeJS { -static uint callbackLevel = 0; +static guint callbackLevel = 0; static GSList* notifiedCallbacks = NULL; static Local GetSelfInstance(GIArgument **args) { @@ -91,10 +91,10 @@ void Callback::Execute (GIArgument *result, GIArgument **args, Callback *callbac /* Skip the object instance in first place */ int args_offset = isVFunc ? 1 : 0; - uint n_native_args = (uint) g_callable_info_get_n_args(callback->info); - uint n_return_values = 1; + guint n_native_args = (guint) g_callable_info_get_n_args(callback->info); + guint n_return_values = 1; - uint primitive_out_arguments_mask = 0; + guint primitive_out_arguments_mask = 0; #ifndef __linux__ Local* js_args = new Local[n_native_args]; @@ -102,7 +102,7 @@ void Callback::Execute (GIArgument *result, GIArgument **args, Callback *callbac Local js_args[n_native_args]; #endif - for (uint i = 0; i < n_native_args; i++) { + for (guint i = 0; i < n_native_args; i++) { GIArgInfo arg_info; GITypeInfo arg_type; g_callable_info_load_arg (callback->info, i, &arg_info); @@ -144,12 +144,11 @@ void Callback::Execute (GIArgument *result, GIArgument **args, Callback *callbac auto jsReturnValue = maybeReturnValue.ToLocalChecked(); auto jsRealReturnValue = jsReturnValue; Local jsReturnArray; - uint returnIndex = 0; + guint returnIndex = 0; bool success; bool isOutPrimitive; - uint n_js_return_values = n_return_values - (hasVoidReturn ? 1 : 0); + guint n_js_return_values = n_return_values - (hasVoidReturn ? 1 : 0); - uint i; GIArgInfo arg_info; GITypeInfo arg_type; @@ -172,7 +171,7 @@ void Callback::Execute (GIArgument *result, GIArgument **args, Callback *callbac else jsRealReturnValue = Nan::Get(jsReturnArray, returnIndex++).ToLocalChecked(); - for (i = 0; i < n_native_args; i++) { + for (guint i = 0; i < n_native_args; i++) { isOutPrimitive = (primitive_out_arguments_mask & (1 << i)) != 0; if (!isOutPrimitive) continue; diff --git a/src/closure.cc b/src/closure.cc index 2d1ee36c..4b5bc736 100644 --- a/src/closure.cc +++ b/src/closure.cc @@ -35,7 +35,7 @@ GClosure *Closure::New (Local function, GICallableInfo* info, guint si void Closure::Execute(GICallableInfo *info, guint signal_id, const Nan::Persistent &persFn, - GValue *g_return_value, uint n_param_values, + GValue *g_return_value, guint n_param_values, const GValue *param_values) { Nan::HandleScope scope; auto func = Nan::New(persFn); @@ -45,7 +45,7 @@ void Closure::Execute(GICallableInfo *info, guint signal_id, g_signal_query(signal_id, &signal_query); // We don't pass the implicit instance as first argument - uint n_js_args = n_param_values - 1; + auto n_js_args = n_param_values - 1; #ifndef __linux__ Local* js_args = new Local[n_js_args]; @@ -58,7 +58,7 @@ void Closure::Execute(GICallableInfo *info, guint signal_id, GIArgument argument; GIArgInfo arg_info; GITypeInfo type_info; - for (uint i = 1; i < n_param_values; i++) { + for (guint i = 1; i < n_param_values; i++) { memcpy(&argument, ¶m_values[i].data[0], sizeof(GIArgument)); g_callable_info_load_arg(info, i - 1, &arg_info); g_arg_info_load_type(&arg_info, &type_info); @@ -76,7 +76,7 @@ void Closure::Execute(GICallableInfo *info, guint signal_id, } } else { /* CallableInfo is not available: use GValueToV8 */ - for (uint i = 1; i < n_param_values; i++) { + for (guint i = 1; i < n_param_values; i++) { bool mustCopy = true; if (signal_query.signal_id) { @@ -123,7 +123,7 @@ void Closure::Execute(GICallableInfo *info, guint signal_id, void Closure::Marshal(GClosure *base, GValue *g_return_value, - uint n_param_values, + guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data) { diff --git a/src/closure.h b/src/closure.h index 19e621bb..792f8c9d 100644 --- a/src/closure.h +++ b/src/closure.h @@ -30,12 +30,12 @@ struct Closure { static void Execute(GICallableInfo *info, guint signal_id, const Nan::Persistent &persFn, - GValue *g_return_value, uint n_param_values, + GValue *g_return_value, guint n_param_values, const GValue *param_values); static void Marshal(GClosure *closure, GValue *g_return_value, - uint argc, const GValue *g_argv, + guint argc, const GValue *g_argv, gpointer invocation_hint, gpointer marshal_data); diff --git a/src/debug.cc b/src/debug.cc index 65384088..091b9f69 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -158,7 +158,7 @@ void print_callable_info (GICallableInfo *info) { g_callable_info_load_return_type(info, &return_info); auto typeName = GetTypeName(&return_info); printf("%s %s (", typeName, g_base_info_get_name(info)); - free(typeName); + g_free(typeName); int n_args = g_callable_info_get_n_args(info); for (int i = 0; i < n_args; i++) { @@ -168,7 +168,7 @@ void print_callable_info (GICallableInfo *info) { g_arg_info_load_type(&arg_info, &type_info); auto typeName = GetTypeName(&type_info); printf("%s %s", typeName, g_base_info_get_name(&arg_info)); - free(typeName); + g_free(typeName); if (i < n_args - 1) printf(", "); } diff --git a/src/function.cc b/src/function.cc index 00affdda..b00b9a0f 100644 --- a/src/function.cc +++ b/src/function.cc @@ -1,4 +1,3 @@ - #include #include @@ -56,7 +55,7 @@ static void* AllocateArgument (GIBaseInfo *arg_info) { GIBaseInfo* base_info = g_type_info_get_interface (&arg_type); size_t size = Boxed::GetSize (base_info); - void* pointer = calloc(1, size); + void* pointer = g_malloc0(size); g_base_info_unref(base_info); return pointer; @@ -165,14 +164,14 @@ bool FunctionInfo::Init() { call_parameters[i].direction = direction; - if (call_parameters[i].type == ParameterType::SKIP) + if (call_parameters[i].type == ParameterType::kSKIP) continue; // If there is an array length, this is an array int length_i = g_type_info_get_array_length (&type_info); if (tag == GI_TYPE_TAG_ARRAY && length_i >= 0) { - call_parameters[i].type = ParameterType::ARRAY; - call_parameters[length_i].type = ParameterType::SKIP; + call_parameters[i].type = ParameterType::kARRAY; + call_parameters[length_i].type = ParameterType::kSKIP; // If array length came before, we need to remove it from args count @@ -190,9 +189,9 @@ bool FunctionInfo::Init() { if (interface_type == GI_INFO_TYPE_CALLBACK) { if (IsDestroyNotify(interface_info)) { /* Skip GDestroyNotify if they appear before the respective callback */ - call_parameters[i].type = ParameterType::SKIP; + call_parameters[i].type = ParameterType::kSKIP; } else { - call_parameters[i].type = ParameterType::CALLBACK; + call_parameters[i].type = ParameterType::kCALLBACK; int destroy_i = g_arg_info_get_destroy(&arg_info); int closure_i = g_arg_info_get_closure(&arg_info); @@ -204,10 +203,10 @@ bool FunctionInfo::Init() { } if (destroy_i >= 0 && destroy_i < n_callable_args) - call_parameters[destroy_i].type = ParameterType::SKIP; + call_parameters[destroy_i].type = ParameterType::kSKIP; if (closure_i >= 0 && closure_i < n_callable_args) - call_parameters[closure_i].type = ParameterType::SKIP; + call_parameters[closure_i].type = ParameterType::kSKIP; if (destroy_i < i) { if (IsDirectionIn(call_parameters[destroy_i].direction)) @@ -271,7 +270,7 @@ bool FunctionInfo::TypeCheck (const Nan::FunctionCallbackInfo &arguments) for (int in_arg = 0, i = 0; i < n_callable_args; i++) { Parameter ¶m = call_parameters[i]; - if (param.type == ParameterType::SKIP) + if (param.type == ParameterType::kSKIP) continue; GIArgInfo arg_info; @@ -325,7 +324,12 @@ Local FunctionCall ( * and for error, if it can throw */ - GIArgument total_arg_values[func->n_total_args]; + #ifndef __linux__ + GIArgument *total_arg_values = new GIArgument[func->n_total_args](); + #else + GIArgument total_arg_values[func->n_total_args]; + #endif + GIArgument *callable_arg_values; GError *error_stack = nullptr; @@ -340,7 +344,6 @@ Local FunctionCall ( if (func->can_throw) callable_arg_values[func->n_callable_args].v_pointer = error != NULL ? error : &error_stack; - /* * Second, allocate OUT-arguments and fill IN-arguments */ @@ -348,7 +351,7 @@ Local FunctionCall ( for (int in_arg = 0, i = 0; i < func->n_callable_args; i++) { Parameter& param = func->call_parameters[i]; - if (param.type == ParameterType::SKIP) + if (param.type == ParameterType::kSKIP) continue; GIArgInfo arg_info; @@ -357,7 +360,7 @@ Local FunctionCall ( g_arg_info_load_type (&arg_info, &type_info); GIDirection direction = g_arg_info_get_direction (&arg_info); - if (param.type == ParameterType::ARRAY) { + if (param.type == ParameterType::kARRAY) { GIArgInfo array_length_arg; GITypeInfo array_length_type; @@ -383,7 +386,7 @@ Local FunctionCall ( callable_arg_values[length_i].v_pointer = &len_param.data; } } - else if (param.type == ParameterType::CALLBACK) { + else if (param.type == ParameterType::kCALLBACK) { Callback *callback; ffi_closure *closure; @@ -402,12 +405,12 @@ Local FunctionCall ( int closure_i = g_arg_info_get_closure(&arg_info); if (destroy_i >= 0) { - g_assert (func->call_parameters[destroy_i].type == ParameterType::SKIP); + g_assert (func->call_parameters[destroy_i].type == ParameterType::kSKIP); callable_arg_values[destroy_i].v_pointer = callback ? (void*) Callback::DestroyNotify : NULL; } if (closure_i >= 0) { - g_assert (func->call_parameters[closure_i].type == ParameterType::SKIP); + g_assert (func->call_parameters[closure_i].type == ParameterType::kSKIP); callable_arg_values[closure_i].v_pointer = callback; } @@ -426,7 +429,7 @@ Local FunctionCall ( else /* (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) */ { // Callback GIArgument is filled above, for the rest... - if (param.type != ParameterType::CALLBACK) { + if (param.type != ParameterType::kCALLBACK) { // FIXME(handle failure here) FillArgument(&arg_info, &callable_arg_values[i], info[in_arg]); @@ -448,16 +451,24 @@ Local FunctionCall ( * Third, make the actual ffi_call */ - void *ffi_args[func->n_total_args]; - for (int i = 0; i < func->n_total_args; i++) - ffi_args[i] = &total_arg_values[i]; + #ifndef __linux__ + void **ffi_args = new void*[func->n_total_args](); + #else + void *ffi_args[func->n_total_args]; + #endif + for (int i = 0; i < func->n_total_args; i++) + ffi_args[i] = (void *)&total_arg_values[i]; - GIArgument return_value_stack; + GIArgument return_value_stack = {0}; ffi_call (&func->invoker.cif, FFI_FN (func->invoker.native_address), use_return_value ? return_value : &return_value_stack, ffi_args); + #ifndef __linux__ + delete[] ffi_args; + #endif + /* * Fourth, convert the return value & OUT-arguments back to JS @@ -507,13 +518,13 @@ Local FunctionCall ( GIDirection direction = g_arg_info_get_direction (&arg_info); GITransfer transfer = g_arg_info_get_ownership_transfer (&arg_info); - if (param.type == ParameterType::ARRAY) { + if (param.type == ParameterType::kARRAY) { if (direction == GI_DIRECTION_INOUT || direction == GI_DIRECTION_OUT) FreeGIArgumentArray (&arg_type, (GIArgument*)arg_value.v_pointer, transfer, direction, param.length); else FreeGIArgumentArray (&arg_type, &arg_value, transfer, direction, param.length); } - else if (param.type == ParameterType::CALLBACK) { + else if (param.type == ParameterType::kCALLBACK) { Callback *callback = static_cast(func->call_parameters[i].data.v_pointer); g_assert(direction == GI_DIRECTION_IN); @@ -530,6 +541,10 @@ Local FunctionCall ( } } + #ifndef __linux__ + delete[] total_arg_values; + #endif + return jsReturnValue; } @@ -595,7 +610,7 @@ Local FunctionInfo::GetReturnValue ( if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { - if (param.type == ParameterType::ARRAY) { + if (param.type == ParameterType::kARRAY) { int length_i = g_type_info_get_array_length(&arg_type); GIArgInfo length_arg; @@ -614,7 +629,7 @@ Local FunctionInfo::GetReturnValue ( ADD_RETURN (result) - } else if (param.type == ParameterType::NORMAL) { + } else if (param.type == ParameterType::kNORMAL) { if (IsPointerType(&arg_type) && g_arg_info_is_caller_allocates(&arg_info)) { void *pointer = &arg_value.v_pointer; diff --git a/src/function.h b/src/function.h index 37dd3133..e6579d16 100644 --- a/src/function.h +++ b/src/function.h @@ -16,7 +16,7 @@ using v8::String; namespace GNodeJS { enum ParameterType { - NORMAL, ARRAY, SKIP, CALLBACK + kNORMAL, kARRAY, kSKIP, kCALLBACK }; struct Parameter { diff --git a/src/gi.cc b/src/gi.cc index f955e79c..b897840a 100644 --- a/src/gi.cc +++ b/src/gi.cc @@ -345,22 +345,22 @@ NAN_METHOD(RegisterVFunc) { void InitModule(Local exports, Local module, void *priv) { GNodeJS::AsyncCallEnvironment::Initialize(); - NAN_EXPORT(exports, Bootstrap); - NAN_EXPORT(exports, GetModuleCache); - NAN_EXPORT(exports, GetBaseClass); - NAN_EXPORT(exports, GetTypeSize); - NAN_EXPORT(exports, GetConstantValue); - NAN_EXPORT(exports, MakeBoxedClass); - NAN_EXPORT(exports, MakeObjectClass); - NAN_EXPORT(exports, MakeFunction); - NAN_EXPORT(exports, StructFieldGetter); - NAN_EXPORT(exports, StructFieldSetter); - NAN_EXPORT(exports, ObjectPropertyGetter); - NAN_EXPORT(exports, ObjectPropertySetter); - NAN_EXPORT(exports, StartLoop); - NAN_EXPORT(exports, GetLoopStack); - NAN_EXPORT(exports, RegisterClass); - NAN_EXPORT(exports, RegisterVFunc); + Nan::Export(exports, "Bootstrap", Bootstrap); + Nan::Export(exports, "GetModuleCache", GetModuleCache); + Nan::Export(exports, "GetBaseClass", GetBaseClass); + Nan::Export(exports, "GetTypeSize", GetTypeSize); + Nan::Export(exports, "GetConstantValue", GetConstantValue); + Nan::Export(exports, "MakeBoxedClass", MakeBoxedClass); + Nan::Export(exports, "MakeObjectClass", MakeObjectClass); + Nan::Export(exports, "MakeFunction", MakeFunction); + Nan::Export(exports, "StructFieldGetter", StructFieldGetter); + Nan::Export(exports, "StructFieldSetter", StructFieldSetter); + Nan::Export(exports, "ObjectPropertyGetter", ObjectPropertyGetter); + Nan::Export(exports, "ObjectPropertySetter", ObjectPropertySetter); + Nan::Export(exports, "StartLoop", StartLoop); + Nan::Export(exports, "GetLoopStack", GetLoopStack); + Nan::Export(exports, "RegisterClass", RegisterClass); + Nan::Export(exports, "RegisterVFunc", RegisterVFunc); Nan::Set(exports, UTF8("System"), GNodeJS::System::GetModule()); Nan::Set(exports, UTF8("Cairo"), GNodeJS::Cairo::GetModule()); diff --git a/src/gobject.cc b/src/gobject.cc index caa23411..1476df98 100644 --- a/src/gobject.cc +++ b/src/gobject.cc @@ -350,7 +350,7 @@ NAN_METHOD(SignalConnect) { guint signalId; GQuark detail; GClosure *gclosure; - ulong handler_id; + gulong handler_id; const char *signalName = *Nan::Utf8String (TO_STRING (info[0])); if (!g_signal_parse_name(signalName, gtype, &signalId, &detail, FALSE)) { @@ -390,7 +390,7 @@ NAN_METHOD(SignalDisconnect) { } gpointer instance = static_cast(gobject); - ulong handler_id = TO_LONG (info[0]); + gulong handler_id = TO_LONG (info[0]); g_signal_handler_disconnect (instance, handler_id); info.GetReturnValue().Set((double)handler_id); @@ -447,7 +447,7 @@ NAN_METHOD(SignalEmit) { g_value_set_object(&args[0], gobject); failed = false; - for (uint i = 0; i < signal_query.n_params; i++) { + for (guint i = 0; i < signal_query.n_params; i++) { GValue *gvalue = &args[i + 1]; g_value_init(gvalue, signal_query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE); @@ -470,7 +470,7 @@ NAN_METHOD(SignalEmit) { } } - for (uint i = 0; i < argc; i++) { + for (guint i = 0; i < argc; i++) { g_value_unset(&args[i]); } } @@ -490,7 +490,7 @@ NAN_METHOD(GObjectToString) { char *className = *Nan::Utf8String(self->GetConstructorName()); void *address = self->GetAlignedPointerFromInternalField(0); - char *str = g_strdup_printf("[%s:%s %#zx]", typeName, className, (unsigned long)address); + char *str = g_strdup_printf("[%s:%s %#zx]", typeName, className, (size_t)address); info.GetReturnValue().Set(UTF8(str)); g_free(str); diff --git a/src/loop.cc b/src/loop.cc index 85bc0ba9..63d757e3 100644 --- a/src/loop.cc +++ b/src/loop.cc @@ -92,9 +92,14 @@ static GSourceFuncs uv_loop_source_funcs = { static GSource *loop_source_new (uv_loop_t *loop) { struct uv_loop_source *source = (struct uv_loop_source *) g_source_new (&uv_loop_source_funcs, sizeof (*source)); source->loop = loop; +#if OS_WINDOWS + // FIXME + // https://github.com/nodejs/node/issues/36015 +#else g_source_add_unix_fd (&source->source, uv_backend_fd (loop), (GIOCondition) (G_IO_IN | G_IO_OUT | G_IO_ERR)); +#endif return &source->source; } diff --git a/src/modules/cairo/context.cc b/src/modules/cairo/context.cc index e0e97619..553678e8 100644 --- a/src/modules/cairo/context.cc +++ b/src/modules/cairo/context.cc @@ -1336,119 +1336,115 @@ NAN_METHOD(tagEnd) { } #endif -#define SET_METHOD(tpl, name) Nan::SetPrototypeMethod(tpl, #name, name) - static void AttachMethods(Local tpl) { - SET_METHOD(tpl, status); - SET_METHOD(tpl, save); - SET_METHOD(tpl, restore); - SET_METHOD(tpl, getTarget); - SET_METHOD(tpl, pushGroup); - SET_METHOD(tpl, pushGroupWithContent); - SET_METHOD(tpl, popGroup); - SET_METHOD(tpl, popGroupToSource); - SET_METHOD(tpl, getGroupTarget); - SET_METHOD(tpl, setSourceRgb); - SET_METHOD(tpl, setSourceRgba); - SET_METHOD(tpl, setSource); - SET_METHOD(tpl, setSourceSurface); - SET_METHOD(tpl, getSource); - SET_METHOD(tpl, setAntialias); - SET_METHOD(tpl, getAntialias); - SET_METHOD(tpl, getDashCount); - SET_METHOD(tpl, getDash); - SET_METHOD(tpl, setFillRule); - SET_METHOD(tpl, getFillRule); - SET_METHOD(tpl, setLineCap); - SET_METHOD(tpl, getLineCap); - SET_METHOD(tpl, setLineJoin); - SET_METHOD(tpl, getLineJoin); - SET_METHOD(tpl, setLineWidth); - SET_METHOD(tpl, getLineWidth); - SET_METHOD(tpl, setMiterLimit); - SET_METHOD(tpl, getMiterLimit); - SET_METHOD(tpl, setOperator); - SET_METHOD(tpl, getOperator); - SET_METHOD(tpl, setTolerance); - SET_METHOD(tpl, getTolerance); - SET_METHOD(tpl, clip); - SET_METHOD(tpl, clipPreserve); - SET_METHOD(tpl, clipExtents); - SET_METHOD(tpl, inClip); - SET_METHOD(tpl, resetClip); - SET_METHOD(tpl, copyClipRectangleList); - SET_METHOD(tpl, fill); - SET_METHOD(tpl, fillPreserve); - SET_METHOD(tpl, fillExtents); - SET_METHOD(tpl, inFill); - SET_METHOD(tpl, mask); - SET_METHOD(tpl, maskSurface); - SET_METHOD(tpl, paint); - SET_METHOD(tpl, paintWithAlpha); - SET_METHOD(tpl, stroke); - SET_METHOD(tpl, strokePreserve); - SET_METHOD(tpl, strokeExtents); - SET_METHOD(tpl, inStroke); - SET_METHOD(tpl, copyPage); - SET_METHOD(tpl, showPage); - SET_METHOD(tpl, getReferenceCount); - SET_METHOD(tpl, copyPath); - SET_METHOD(tpl, copyPathFlat); - SET_METHOD(tpl, appendPath); - SET_METHOD(tpl, hasCurrentPoint); - SET_METHOD(tpl, getCurrentPoint); - SET_METHOD(tpl, newPath); - SET_METHOD(tpl, newSubPath); - SET_METHOD(tpl, closePath); - SET_METHOD(tpl, arc); - SET_METHOD(tpl, arcNegative); - SET_METHOD(tpl, curveTo); - SET_METHOD(tpl, lineTo); - SET_METHOD(tpl, moveTo); - SET_METHOD(tpl, rectangle); - SET_METHOD(tpl, glyphPath); - SET_METHOD(tpl, textPath); - SET_METHOD(tpl, relCurveTo); - SET_METHOD(tpl, relLineTo); - SET_METHOD(tpl, relMoveTo); - SET_METHOD(tpl, pathExtents); - SET_METHOD(tpl, showText); - SET_METHOD(tpl, showGlyphs); - SET_METHOD(tpl, showTextGlyphs); - SET_METHOD(tpl, fontExtents); - SET_METHOD(tpl, textExtents); - SET_METHOD(tpl, glyphExtents); - SET_METHOD(tpl, selectFontFace); - SET_METHOD(tpl, setFontSize); - SET_METHOD(tpl, setFontMatrix); - SET_METHOD(tpl, getFontMatrix); - SET_METHOD(tpl, setFontOptions); - SET_METHOD(tpl, getFontOptions); - SET_METHOD(tpl, setFontFace); - SET_METHOD(tpl, getFontFace); - SET_METHOD(tpl, setScaledFont); - SET_METHOD(tpl, getScaledFont); - SET_METHOD(tpl, translate); - SET_METHOD(tpl, scale); - SET_METHOD(tpl, rotate); - SET_METHOD(tpl, transform); - SET_METHOD(tpl, setMatrix); - SET_METHOD(tpl, getMatrix); - SET_METHOD(tpl, identityMatrix); - SET_METHOD(tpl, userToDevice); - SET_METHOD(tpl, userToDeviceDistance); - SET_METHOD(tpl, deviceToUser); - SET_METHOD(tpl, deviceToUserDistance); + SET_PROTOTYPE_METHOD(tpl, status); + SET_PROTOTYPE_METHOD(tpl, save); + SET_PROTOTYPE_METHOD(tpl, restore); + SET_PROTOTYPE_METHOD(tpl, getTarget); + SET_PROTOTYPE_METHOD(tpl, pushGroup); + SET_PROTOTYPE_METHOD(tpl, pushGroupWithContent); + SET_PROTOTYPE_METHOD(tpl, popGroup); + SET_PROTOTYPE_METHOD(tpl, popGroupToSource); + SET_PROTOTYPE_METHOD(tpl, getGroupTarget); + SET_PROTOTYPE_METHOD(tpl, setSourceRgb); + SET_PROTOTYPE_METHOD(tpl, setSourceRgba); + SET_PROTOTYPE_METHOD(tpl, setSource); + SET_PROTOTYPE_METHOD(tpl, setSourceSurface); + SET_PROTOTYPE_METHOD(tpl, getSource); + SET_PROTOTYPE_METHOD(tpl, setAntialias); + SET_PROTOTYPE_METHOD(tpl, getAntialias); + SET_PROTOTYPE_METHOD(tpl, getDashCount); + SET_PROTOTYPE_METHOD(tpl, getDash); + SET_PROTOTYPE_METHOD(tpl, setFillRule); + SET_PROTOTYPE_METHOD(tpl, getFillRule); + SET_PROTOTYPE_METHOD(tpl, setLineCap); + SET_PROTOTYPE_METHOD(tpl, getLineCap); + SET_PROTOTYPE_METHOD(tpl, setLineJoin); + SET_PROTOTYPE_METHOD(tpl, getLineJoin); + SET_PROTOTYPE_METHOD(tpl, setLineWidth); + SET_PROTOTYPE_METHOD(tpl, getLineWidth); + SET_PROTOTYPE_METHOD(tpl, setMiterLimit); + SET_PROTOTYPE_METHOD(tpl, getMiterLimit); + SET_PROTOTYPE_METHOD(tpl, setOperator); + SET_PROTOTYPE_METHOD(tpl, getOperator); + SET_PROTOTYPE_METHOD(tpl, setTolerance); + SET_PROTOTYPE_METHOD(tpl, getTolerance); + SET_PROTOTYPE_METHOD(tpl, clip); + SET_PROTOTYPE_METHOD(tpl, clipPreserve); + SET_PROTOTYPE_METHOD(tpl, clipExtents); + SET_PROTOTYPE_METHOD(tpl, inClip); + SET_PROTOTYPE_METHOD(tpl, resetClip); + SET_PROTOTYPE_METHOD(tpl, copyClipRectangleList); + SET_PROTOTYPE_METHOD(tpl, fill); + SET_PROTOTYPE_METHOD(tpl, fillPreserve); + SET_PROTOTYPE_METHOD(tpl, fillExtents); + SET_PROTOTYPE_METHOD(tpl, inFill); + SET_PROTOTYPE_METHOD(tpl, mask); + SET_PROTOTYPE_METHOD(tpl, maskSurface); + SET_PROTOTYPE_METHOD(tpl, paint); + SET_PROTOTYPE_METHOD(tpl, paintWithAlpha); + SET_PROTOTYPE_METHOD(tpl, stroke); + SET_PROTOTYPE_METHOD(tpl, strokePreserve); + SET_PROTOTYPE_METHOD(tpl, strokeExtents); + SET_PROTOTYPE_METHOD(tpl, inStroke); + SET_PROTOTYPE_METHOD(tpl, copyPage); + SET_PROTOTYPE_METHOD(tpl, showPage); + SET_PROTOTYPE_METHOD(tpl, getReferenceCount); + SET_PROTOTYPE_METHOD(tpl, copyPath); + SET_PROTOTYPE_METHOD(tpl, copyPathFlat); + SET_PROTOTYPE_METHOD(tpl, appendPath); + SET_PROTOTYPE_METHOD(tpl, hasCurrentPoint); + SET_PROTOTYPE_METHOD(tpl, getCurrentPoint); + SET_PROTOTYPE_METHOD(tpl, newPath); + SET_PROTOTYPE_METHOD(tpl, newSubPath); + SET_PROTOTYPE_METHOD(tpl, closePath); + SET_PROTOTYPE_METHOD(tpl, arc); + SET_PROTOTYPE_METHOD(tpl, arcNegative); + SET_PROTOTYPE_METHOD(tpl, curveTo); + SET_PROTOTYPE_METHOD(tpl, lineTo); + SET_PROTOTYPE_METHOD(tpl, moveTo); + SET_PROTOTYPE_METHOD(tpl, rectangle); + SET_PROTOTYPE_METHOD(tpl, glyphPath); + SET_PROTOTYPE_METHOD(tpl, textPath); + SET_PROTOTYPE_METHOD(tpl, relCurveTo); + SET_PROTOTYPE_METHOD(tpl, relLineTo); + SET_PROTOTYPE_METHOD(tpl, relMoveTo); + SET_PROTOTYPE_METHOD(tpl, pathExtents); + SET_PROTOTYPE_METHOD(tpl, showText); + SET_PROTOTYPE_METHOD(tpl, showGlyphs); + SET_PROTOTYPE_METHOD(tpl, showTextGlyphs); + SET_PROTOTYPE_METHOD(tpl, fontExtents); + SET_PROTOTYPE_METHOD(tpl, textExtents); + SET_PROTOTYPE_METHOD(tpl, glyphExtents); + SET_PROTOTYPE_METHOD(tpl, selectFontFace); + SET_PROTOTYPE_METHOD(tpl, setFontSize); + SET_PROTOTYPE_METHOD(tpl, setFontMatrix); + SET_PROTOTYPE_METHOD(tpl, getFontMatrix); + SET_PROTOTYPE_METHOD(tpl, setFontOptions); + SET_PROTOTYPE_METHOD(tpl, getFontOptions); + SET_PROTOTYPE_METHOD(tpl, setFontFace); + SET_PROTOTYPE_METHOD(tpl, getFontFace); + SET_PROTOTYPE_METHOD(tpl, setScaledFont); + SET_PROTOTYPE_METHOD(tpl, getScaledFont); + SET_PROTOTYPE_METHOD(tpl, translate); + SET_PROTOTYPE_METHOD(tpl, scale); + SET_PROTOTYPE_METHOD(tpl, rotate); + SET_PROTOTYPE_METHOD(tpl, transform); + SET_PROTOTYPE_METHOD(tpl, setMatrix); + SET_PROTOTYPE_METHOD(tpl, getMatrix); + SET_PROTOTYPE_METHOD(tpl, identityMatrix); + SET_PROTOTYPE_METHOD(tpl, userToDevice); + SET_PROTOTYPE_METHOD(tpl, userToDeviceDistance); + SET_PROTOTYPE_METHOD(tpl, deviceToUser); + SET_PROTOTYPE_METHOD(tpl, deviceToUserDistance); #if CAIRO_VERSION_MAJOR >= 1 && CAIRO_VERSION_MINOR >= 16 - SET_METHOD(tpl, tagBegin); + SET_PROTOTYPE_METHOD(tpl, tagBegin); #endif #if CAIRO_VERSION_MAJOR >= 1 && CAIRO_VERSION_MINOR >= 16 - SET_METHOD(tpl, tagEnd); + SET_PROTOTYPE_METHOD(tpl, tagEnd); #endif } -#undef SET_METHOD - /* &info); diff --git a/src/modules/cairo/generator.js b/src/modules/cairo/generator.js index 7ba4610f..a7bd58b4 100644 --- a/src/modules/cairo/generator.js +++ b/src/modules/cairo/generator.js @@ -521,8 +521,6 @@ function getReturn(fn, outArguments) { function getAttachMethods(name, functions) { return unindent(` - #define SET_METHOD(tpl, name) Nan::SetPrototypeMethod(tpl, #name, name) - static void AttachMethods(Local tpl) { ${functions.map(fn => (fn.attributes.version ? (() => { @@ -533,12 +531,10 @@ function getAttachMethods(name, functions) { (micro ? 'CAIRO_VERSION_MICRO >= ' + micro : undefined), ].filter(Boolean).join(' && ') + '\n ' })() : '') - + `SET_METHOD(tpl, ${getJSName(fn.name)});` + + `SET_PROTOTYPE_METHOD(tpl, ${getJSName(fn.name)});` + (fn.attributes.version ? '\n #endif' : '') ).join('\n ')} } - - #undef SET_METHOD `) } diff --git a/src/type.cc b/src/type.cc index 1b1ab035..081e038e 100644 --- a/src/type.cc +++ b/src/type.cc @@ -256,13 +256,13 @@ GITypeTag GetStorageType (GITypeInfo *type_info) { GITypeTag type_tag = g_type_info_get_tag (type_info); if (type_tag == GI_TYPE_TAG_INTERFACE) { - GIBaseInfo *interface = g_type_info_get_interface (type_info); - GIInfoType interface_type = g_base_info_get_type (interface); + GIBaseInfo *iface = g_type_info_get_interface (type_info); + GIInfoType iface_type = g_base_info_get_type (iface); - if (interface_type == GI_INFO_TYPE_ENUM || interface_type == GI_INFO_TYPE_FLAGS) - type_tag = g_enum_info_get_storage_type ((GIEnumInfo *)interface); + if (iface_type == GI_INFO_TYPE_ENUM || iface_type == GI_INFO_TYPE_FLAGS) + type_tag = g_enum_info_get_storage_type ((GIEnumInfo *)iface); - g_base_info_unref (interface); + g_base_info_unref (iface); } return type_tag; diff --git a/src/value.cc b/src/value.cc index 041751b1..03a9dd47 100644 --- a/src/value.cc +++ b/src/value.cc @@ -68,8 +68,8 @@ Local GIArgumentToV8(GITypeInfo *type_info, GIArgument *arg, long length, case GI_TYPE_TAG_UINT64: return New (arg->v_uint64); - case GI_TYPE_TAG_GTYPE: /* c++: gulong */ - return v8::BigInt::NewFromUnsigned(Isolate::GetCurrent(), arg->v_ulong); + case GI_TYPE_TAG_GTYPE: /* c++: gsize */ + return v8::BigInt::NewFromUnsigned(Isolate::GetCurrent(), arg->v_size); case GI_TYPE_TAG_UNICHAR: { @@ -349,7 +349,7 @@ Local ArrayToV8 (GITypeInfo *type_info, void* data, long length) { if (length != -1 && i >= length) break; - void** pointer = (void**)((ulong)data + i * item_size); + void** pointer = (void**)((size_t)data + i * item_size); memcpy(&value, pointer, item_size); if (length == -1 && isZero(value, item_type_info)) @@ -458,7 +458,7 @@ static void *V8ArrayToCArray(GITypeInfo *type_info, Local value) { GITypeInfo* element_info = g_type_info_get_param_type (type_info, 0); gsize element_size = GetTypeSize(element_info); - void *result = malloc(element_size * (length + (isZeroTerminated ? 1 : 0))); + void *result = g_malloc0(element_size * (length + (isZeroTerminated ? 1 : 0))); for (int i = 0; i < length; i++) { auto value = Nan::Get(array, i).ToLocalChecked(); @@ -466,7 +466,7 @@ static void *V8ArrayToCArray(GITypeInfo *type_info, Local value) { GIArgument arg; if (V8ToGIArgument(element_info, &arg, value, true)) { - void* pointer = (void*)((ulong)result + i * element_size); + void* pointer = (void*)((size_t)result + i * element_size); memcpy(pointer, &arg, element_size); } else { WARN("couldnt convert value: %s", *Nan::Utf8String(TO_STRING (value))); @@ -474,7 +474,10 @@ static void *V8ArrayToCArray(GITypeInfo *type_info, Local value) { } if (isZeroTerminated) { - void* pointer = (void*)((ulong)result + length * element_size); + // TODO: + // Since g_malloc0 above already zeros the memory + // it's better to assert the last element is zero + void* pointer = (void*)((size_t)result + length * element_size); memset(pointer, 0, element_size); } @@ -490,12 +493,15 @@ static void *V8TypedArrayToCArray(GITypeInfo *type_info, Local value) { GITypeInfo* element_info = g_type_info_get_param_type (type_info, 0); gsize element_size = GetTypeSize(element_info); - void *result = malloc(element_size * (length + (isZeroTerminated ? 1 : 0))); + void *result = g_malloc0(element_size * (length + (isZeroTerminated ? 1 : 0))); array->CopyContents(result, length); if (isZeroTerminated) { - void* pointer = (void*)((ulong)result + length * element_size); + // TODO: + // Since g_malloc0 above already zeros the memory + // it's better to assert the last element is zero + void* pointer = (void*)((size_t)result + length * element_size); memset(pointer, 0, element_size); } @@ -648,14 +654,14 @@ gpointer V8ToGHash (GITypeInfo *type_info, Local value) { if (!V8ToGIArgument(key_type_info, &key_arg, key, false)) { char* message = g_strdup_printf("Couldn't convert key '%s'", *Nan::Utf8String(key)); Nan::ThrowError(message); - free(message); + g_free(message); goto item_error; } if (!V8ToGIArgument(value_type_info, &value_arg, value, false)) { char* message = g_strdup_printf("Couldn't convert value for key '%s'", *Nan::Utf8String(key)); Nan::ThrowError(message); - free(message); + g_free(message); goto item_error; } @@ -679,6 +685,8 @@ gpointer V8ToGHash (GITypeInfo *type_info, Local value) { bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local value) { GIInfoType type = g_base_info_get_type (gi_info); + memset(arg, 0, sizeof(GIArgument)); + switch (type) { case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: @@ -716,6 +724,8 @@ bool V8ToGIArgument(GIBaseInfo *gi_info, GIArgument *arg, Local value) { bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local value, bool may_be_null) { GITypeTag type_tag = g_type_info_get_tag (type_info); + memset(arg, 0, sizeof(GIArgument)); + if (value->IsUndefined () || value->IsNull ()) { arg->v_pointer = NULL; @@ -776,9 +786,9 @@ bool V8ToGIArgument(GITypeInfo *type_info, GIArgument *arg, Local value, break; case GI_TYPE_TAG_GTYPE: if (value->IsBigInt()) - arg->v_ulong = value.As()->Uint64Value(); + arg->v_size = value.As()->Uint64Value(); else - arg->v_ulong = Nan::To (value).ToChecked(); + arg->v_size = Nan::To (value).ToChecked(); break; case GI_TYPE_TAG_UTF8: @@ -867,6 +877,8 @@ bool V8ToOutGIArgument(GITypeInfo *type_info, GIArgument *arg, Local valu */ GITypeTag type_tag = g_type_info_get_tag (type_info); + memset(arg, 0, sizeof(GIArgument)); + if (value->IsUndefined () || value->IsNull ()) { arg->v_pointer = NULL; @@ -920,9 +932,9 @@ bool V8ToOutGIArgument(GITypeInfo *type_info, GIArgument *arg, Local valu break; case GI_TYPE_TAG_GTYPE: if (value->IsBigInt()) - *(gulong*)arg->v_pointer = value.As()->Uint64Value(); + *(gsize*)arg->v_pointer = value.As()->Uint64Value(); else - *(gulong*)arg->v_pointer = Nan::To (value).ToChecked(); + *(gsize*)arg->v_pointer = Nan::To (value).ToChecked(); break; case GI_TYPE_TAG_UTF8: @@ -1314,7 +1326,7 @@ void FreeGIArgumentArray(GITypeInfo *type_info, GIArgument *arg, GITransfer tran for (int i = 0; i < length; i++) { GIArgument item; - memcpy (&item, (void*)((ulong)data + element_size * i), sizeof (GIArgument)); + memcpy (&item, (void*)((size_t)data + element_size * i), sizeof (GIArgument)); FreeGIArgument (element_info, &item, item_transfer, direction); } @@ -1333,7 +1345,7 @@ void FreeGIArgumentArray(GITypeInfo *type_info, GIArgument *arg, GITransfer tran switch (array_type) { case GI_ARRAY_TYPE_C: { - free(data); + g_free (data); break; } case GI_ARRAY_TYPE_ARRAY: diff --git a/src/value.h b/src/value.h index a23ea6f2..759b8716 100644 --- a/src/value.h +++ b/src/value.h @@ -26,7 +26,7 @@ void FreeGIArgument (GITypeInfo *type_info, GIArgument *argument, GITran void FreeGIArgumentArray (GITypeInfo *type_info, GIArgument *arg, GITransfer transfer = GI_TRANSFER_EVERYTHING, GIDirection direction = GI_DIRECTION_OUT, long length = -1); bool CanConvertV8ToGIArgument (GITypeInfo *type_info, Local value, bool may_be_null); -bool V8ToGValue(GValue *gvalue, Local value, bool mustCopy = false) __attribute__((warn_unused_result)); +bool V8ToGValue(GValue *gvalue, Local value, bool mustCopy = false); Local GValueToV8(const GValue *gvalue, bool mustCopy = false); bool CanConvertV8ToGValue(GValue *gvalue, Local value); diff --git a/tests/__run__.js b/tests/__run__.js index 98f9c97c..9173a81b 100644 --- a/tests/__run__.js +++ b/tests/__run__.js @@ -21,13 +21,15 @@ const watchdog = setTimeout(() => { }, 10 * 60 * 1000) watchdog.unref() -const skipPattern = process.argv +// usage: npx mocha [--skip=pat1[,pat2...]] [--skip=...] tests/__run__.js +const skipPatterns = process.argv .filter(a => a.startsWith('--skip=')) - .map(a => new RegExp(a.replace('--skip=', '')))[0] + .flatMap(a => a.replace('--skip=', '').split(',')) + .map(a => new RegExp(a)) files.forEach(file => { - if (skipPattern && skipPattern.test(file)) + if (skipPatterns.reduce((acc, pat) => acc || pat.test(file), false)) return it(file, function(done) { diff --git a/tests/conversion__array.js b/tests/conversion__array.js index c7acb4fc..5e3c4a01 100644 --- a/tests/conversion__array.js +++ b/tests/conversion__array.js @@ -51,7 +51,14 @@ describe('OUT-array (zero-terminated, of strings)', () => { expect(alternates, [ 'special' ]) }) -describe('OUT-array (zero-terminated, of guint8)', () => { + +// The below test fails on Windows with: +// Error: Failed to dup() in child process (Bad file descriptor) +// ... +// at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12) +// at node:internal/main/run_main_module:17:47 + +process.platform !== 'win32' && describe('OUT-array (zero-terminated, of guint8)', () => { const cmd = 'echo foo' const result = glib.spawnCommandLineSync(cmd) diff --git a/tests/require.js b/tests/require.js index 965978f0..fb5ab3e6 100644 --- a/tests/require.js +++ b/tests/require.js @@ -59,7 +59,7 @@ describe('gi.require() works for all modules', async () => { function testRequire(module, i, modules) { return new Promise((resolve, reject) => { - const modulePath = path.join(__dirname, '..') + const modulePath = path.posix.join(__dirname, '..') const cmd = `node -e "const gi = require('${modulePath}'); gi.require('${module.name}', '${module.version}')"` const options = { maxBuffer: 10 * 1024 * 1024, diff --git a/tests/union__fields.js b/tests/union__fields.js index 886270b4..d8300a49 100644 --- a/tests/union__fields.js +++ b/tests/union__fields.js @@ -15,8 +15,8 @@ const tk = new GLib.TokenValue() * get/set works */ { - tk.vInt = Number.MAX_SAFE_INTEGER - const result = tk.vInt + tk.vInt64 = Number.MAX_SAFE_INTEGER + const result = tk.vInt64 console.log('Result:', result) common.assert(result === Number.MAX_SAFE_INTEGER) } diff --git a/windows/mingw_include_extra.sh b/windows/mingw_include_extra.sh new file mode 100644 index 00000000..3063967d --- /dev/null +++ b/windows/mingw_include_extra.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +SRC_DIR=/mingw64/include +DST_DIR=$SRC_DIR/__extra__ + +mkdir -p $DST_DIR + +cp $SRC_DIR/ffi.h $DST_DIR +cp $SRC_DIR/ffitarget.h $DST_DIR + +FC_DIR=$DST_DIR/fontconfig +mkdir -p $FC_DIR +cp $SRC_DIR/fontconfig/fcfreetype.h $FC_DIR +cp $SRC_DIR/fontconfig/fcprivate.h $FC_DIR +cp $SRC_DIR/fontconfig/fontconfig.h $FC_DIR + +echo $DST_DIR diff --git a/windows/mingw_windows_path.sh b/windows/mingw_windows_path.sh new file mode 100644 index 00000000..ef937be0 --- /dev/null +++ b/windows/mingw_windows_path.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +# Return where/ is mounted to. + +mount | awk '$3 == "/" { print $1 }'