new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Electron · all subjects

native integration

74 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

Validating arguments in native addon methods

In native addon methods, validate argument count with info.Length() and type with methods like IsString() or IsFunction(). Throw TypeErrors for invalid arguments using Napi::TypeError::New(env, message).ThrowAsJavaScriptException(). Convert JavaScript values to C++ types using As<Napi::String>() or As<Napi::Function>().

Example native addon package.json scripts

A native addon package.json for Electron should include: "build": "node-gyp configure && node-gyp build" for local building, and "build-electron": "electron-rebuild" for building against Electron. Dependencies should include "node-addon-api" and "bindings" packages.

Native addon binding.gyp basic structure

A binding.gyp file contains a "targets" array with target configurations. Each target has: "target_name" specifying the addon name, "conditions" array for platform-specific settings, "sources" array listing C++ files, "include_dirs" array for header paths, "libraries" array for linking, "cflags" and "cflags_cc" for compiler flags, "ldflags" for linker flags, "defines" for preprocessor defines, and "dependencies" for dependencies like node-addon-api.gyp.

Using pkg-config in binding.gyp for library integration

Use '<!@(pkg-config --cflags-only-I gtk+-3.0 | sed s/-I//g)' to get include directories for a library. Use '<!@(pkg-config --libs gtk+-3.0)' to get linker flags. Use '<!@(pkg-config --cflags gtk+-3.0)' to get compiler flags. The sed command removes the -I prefix to make paths compatible with GYP format.

Node.js addon API initialization pattern

A minimal Node.js addon requires: #include <napi.h>, a Napi::Object Init function that creates the module interface, and NODE_API_MODULE macro to register the initializer. The Init function takes Napi::Env and Napi::Object exports parameters and returns the modified exports object.

Persistent references in native addons

Use Napi::ObjectReference for values that need to persist across JavaScript function calls. Create with Napi::Persistent(value) and access with Value(). Call Reset() to release the reference and allow garbage collection. This is essential for storing callback maps or event emitters.

GTK3 UI layout using XML in native addons

GTK3 UIs can be defined using XML markup and loaded with gtk_builder_add_from_string(). The XML defines objects like GtkWindow, GtkBox, GtkEntry, GtkButton, GtkListBox, etc. with properties and IDs. Use gtk_builder_get_object() to retrieve UI elements by ID after loading the XML definition.

GTK3 requirement for Linux native addons

Electron on Linux specifically uses GTK3 internally because that's what Chromium uses. Using GTK4 in a native addon would cause runtime conflicts since both GTK3 and GTK4 would be loaded in the same process. Native Linux addons for Electron must use GTK3, not GTK4.

Platform-specific pattern for loading native addons

The binding.gyp configuration should use conditional compilation with 'OS=="linux"' to ensure native code is only compiled on Linux systems. The configuration uses pkg-config to automatically locate and include GTK3 libraries and header paths on the user's system. Use the '<!@' syntax in binding.gyp to execute commands and use their output as values. For example: '<!@(pkg-config --cflags gtk+-3.0)' gets the compiler flags for GTK3, and sed is used to strip prefixes to make paths GYP-compatible.

Linux native addon build tools required

To build Linux native addons with GTK3, install: build-essential, pkg-config, libgtk-3-dev on Ubuntu/Debian. On Fedora/RHEL/CentOS install: gcc-c++, pkgconfig, gtk3-devel. The build requires the pkg-config tool and G++ compiler.

Thread-safe function pattern for native addons calling JavaScript

To safely call JavaScript from native addon threads, use napi_create_threadsafe_function from the N-API. This is essential when working with GUI frameworks like GTK3 that run on their own thread. The thread-safe function automatically queues function calls to the JavaScript thread and handles proper reference counting. Use napi_call_threadsafe_function to invoke the callback from the native thread. Always release the thread-safe function with napi_release_threadsafe_function in the addon destructor.

GTK must run in separate thread from Electron main process

GTK requires running in its own event loop and cannot be run on the main Node.js thread. Create a separate thread for the GTK application using std::thread to avoid blocking the Electron JavaScript event loop. Use g_main_context and g_main_loop to manage the GTK event loop on the separate thread. This separation ensures the native UI remains responsive while allowing bidirectional communication with Electron through thread-safe functions.

Node-addon-api classes for native module wrapping

To wrap C++ code for Node.js use Napi::ObjectWrap<ClassName>. Define an Init static method that calls DefineClass to define JavaScript interface methods. Use Napi::InstanceMethod to map JavaScript method names to C++ member functions. Expose the class to JavaScript via exports.Set(). Each method receives Napi::CallbackInfo containing arguments and environment.

MulDiv scales UI values based on DPI

Use MulDiv(value, dpi, 96) to scale UI element dimensions based on the current DPI. The denominator 96 is the default DPI baseline. This ensures controls are properly sized on high-DPI displays.

Convert SYSTEMTIME to milliseconds since epoch for JavaScript

To convert Windows SYSTEMTIME to JavaScript-compatible time, convert to FILETIME, extract to ULARGE_INTEGER, then calculate: (uli.QuadPart - 116444736000000000ULL) / 10000. This gives milliseconds since Unix epoch.

InitCommonControlsEx registers Windows common controls

Call InitCommonControlsEx with appropriate dwICC flags to register Windows common controls before creating them. For standard controls and Win95-style controls, use ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES.

Windows message loop uses GetMessage, TranslateMessage, DispatchMessage

A Windows GUI message loop runs GetMessage to retrieve messages, TranslateMessage to translate virtual key messages, and DispatchMessage to dispatch the message to the window procedure. Continue looping until GetMessage returns false (on WM_QUIT).

Segoe UI font with ClearType quality for modern Windows appearance

For modern Windows applications, create fonts with face name L"Segoe UI", quality CLEARTYPE_QUALITY, pitch DEFAULT_PITCH | FF_DONTCARE, and DPI-scaled height. This provides a modern native appearance.

SendMessageW sets control properties and sends messages

Use SendMessageW(hwnd, message, wParam, lParam) to send messages to windows and controls. For example, WM_SETFONT sets the font, LB_ADDSTRING adds items to list boxes, DateTime_GetSystemtime and DateTime_SetSystemtime work with date pickers.

WM_COMMAND message indicates user control interaction

Handle WM_COMMAND messages in the window procedure to respond to user interactions with controls. Use LOWORD(wParam) to get the control ID and distinguish between different controls.

binding.gyp conditions restrict compilation to Windows

In binding.gyp, use conditions: [['OS=="win"', { ... }]] to restrict target configuration to Windows only. This prevents compilation on other platforms and allows Windows-specific libraries and settings.

CoCreateGuid generates unique GUIDs for data items

Use CoCreateGuid(GUID*) to generate universally unique identifiers for data items. The function fills the provided GUID structure with a unique value. Use StringFromCLSID to convert GUID to string representation.

GetDlgItem retrieves control handles by ID

Use GetDlgItem(hwnd, id) to retrieve a window handle to a control that was created with that numeric ID. This is useful for manipulating controls after creation.

WC_EDITW, WC_BUTTONW, WC_LISTBOXW are standard Windows control class names

Windows common control class names include WC_EDITW for edit boxes, WC_BUTTONW for buttons, WC_LISTBOXW for list boxes, and DATETIMEPICK_CLASSW for date picker controls. Use with CreateWindowExW to create controls.

GUI code must run on separate thread to avoid blocking Node.js event loop

When implementing a Windows message loop for native GUI code, run it on a separate thread to avoid blocking the Node.js event loop. The Windows message loop runs in an infinite loop processing GUI events. Running it on the main thread would prevent Node.js from processing other events. This separation also helps prevent deadlocks that could occur if GUI operations need to wait for JavaScript callbacks. Use std::thread to create the GUI thread and detach it.

comctl32.lib provides Windows Common Controls

comctl32.lib is a Windows library that contains common controls and user interface components. It provides various UI elements like buttons, scrollbars, toolbars, status bars, progress bars, and tree views. It is low-level and basic for GUI development on Windows.

shcore.lib provides DPI awareness and Shell features

shcore.lib is a Windows library that provides high-DPI awareness functionality and other Shell-related features around managing displays and UI elements.

SetProcessDpiAwarenessContext for per-monitor DPI scaling

Use SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) to enable per-monitor DPI awareness for proper display scaling in native Windows GUI applications.

ExceptionHandling: 1 enables C++ exception handling in Visual Studio builds

In binding.gyp msvs_settings, set ExceptionHandling: 1 to enable C++ exception handling with the /EHsc compiler flag. This is important because it enables the compiler to catch C++ exceptions, ensures proper stack unwinding when exceptions occur, and is required for Node-API to properly handle exceptions between JavaScript and C++.

DebugInformationFormat: OldStyle for PDB debugging

In binding.gyp msvs_settings VCCLCompilerTool, set DebugInformationFormat to OldStyle to use the older, more compatible PDB (Program Database) format. This supports compatibility with various debugging tools and works better with incremental builds.

AdditionalOptions: ["/FS"] prevents parallel build PDB conflicts

In binding.gyp msvs_settings VCCLCompilerTool, add AdditionalOptions: ["/FS"] to force serialized access to PDB files during compilation. This prevents build errors in parallel builds where multiple compiler processes try to access the same PDB file.

GenerateDebugInformation in VCLinkerTool for readable stack traces

In binding.gyp msvs_settings VCLinkerTool, set GenerateDebugInformation to true. This tells the linker to include debug information, which allows source-level debugging and enables human-readable stack traces if the addon crashes.

NODE_ADDON_API_CPP_EXCEPTIONS enables idiomatic C++ exception handling

In binding.gyp defines, add NODE_ADDON_API_CPP_EXCEPTIONS to enable C++ exception handling in the Node Addon API. By default, Node-API uses a return-value error handling pattern, but this define allows the C++ wrapper to throw and catch C++ exceptions, making the code more idiomatic C++ and easier to work with.

WINVER and _WIN32_WINNT define minimum Windows version

In binding.gyp defines, set WINVER and _WIN32_WINNT to the minimum Windows version the code targets. The value 0x0A00 corresponds to Windows 10. These macros tell the compiler that the code can use features available in that Windows version and won't attempt to maintain backward compatibility with earlier versions. Set both to the lowest version of Windows you intend to support.

Native addon N-API class structure for Electron

Native addons for Electron using N-API should define a class inheriting from Napi::ObjectWrap<ClassName>. The class should have a static Init method that registers instance methods, a constructor to set up callbacks and threadsafe functions, and a destructor to clean up resources. Use Napi::ObjectReference for persistent JavaScript references and store them as class members.

Native addons on macOS use Objective-C++ (.mm files)

macOS native addons for Electron use the .mm file extension to indicate Objective-C++ files, which can mix Objective-C and C++. This is the standard approach for integrating native macOS code with Node.js addons.

macOS addon build requires Foundation and AppKit frameworks

When building native addons for macOS, the binding.gyp configuration must include the Foundation and AppKit frameworks using libraries: ["-framework Foundation", "-framework AppKit"]. Foundation provides data management and file system interaction, while AppKit provides UI components like windows, buttons, and text fields.

Automatic Reference Counting (ARC) for macOS addons

The xcode_settings in binding.gyp should include "CLANG_ENABLE_OBJC_ARC": "YES" to enable Automatic Reference Counting for easier memory management in Objective-C code.

binding.gyp xcode_settings for macOS Objective-C++

The xcode_settings in binding.gyp for macOS native addons should include: "GCC_ENABLE_CPP_EXCEPTIONS": "YES", "CLANG_CXX_LIBRARY": "libc++", "MACOSX_DEPLOYMENT_TARGET": "11.0", "CLANG_ENABLE_OBJC_ARC": "YES", "OTHER_CFLAGS": ["-ObjC++", "-std=c++17"], and "NODE_ADDON_API_CPP_EXCEPTIONS" in defines.

All UI operations on macOS must run on the main thread

In macOS/iOS development, all UI updates must happen on the main thread, which is the primary execution path where the application runs its event loop and processes user interface events. When JavaScript calls native code that might be running on a Node.js worker thread, use Grand Central Dispatch (GCD) with dispatch_async(dispatch_get_main_queue(), ^{ ... }) to safely redirect UI operations to the main thread.

N-API threadsafe functions for native callbacks across threads

Use napi_create_threadsafe_function to create a threadsafe function in N-API when native code running on different threads needs to call JavaScript callbacks. This bridges thread boundaries safely. Call napi_call_threadsafe_function to invoke the threadsafe callback from any thread, and use napi_release_threadsafe_function with napi_tsfn_release in destructors or napi_tsfn_abort for cleanup.

Destroy native addon resources before app quit

You must call destroy() or cleanup methods on native addons before the app quits (such as in the will-quit or before-quit event handler). Without this, persistent references to callbacks and threadsafe functions will prevent the native addon's destructor from running, causing Electron to hang on quit.

Platform check for macOS-only native modules

When creating macOS-only native modules, check process.platform === 'darwin' in both the native addon bridge and JavaScript wrapper to ensure the module is only used on macOS. Throw an error if instantiated on other platforms.

JavaScript wrapper for native addon using EventEmitter

Create a JavaScript wrapper class extending EventEmitter to expose native addon functionality with a clean API. The wrapper should load the native addon using require('bindings'), instantiate it, set up event listeners that forward events from the native layer to JavaScript, and provide method wrappers that call the native addon methods.

Native addon example: complete Objective-C++ todo app addon

Example showing how to create a complete native macOS addon that exposes a todo app GUI. The addon includes: (1) objc_code.h header defining namespace functions like hello_world() and hello_gui(), and callback setters like setTodoAddedCallback(). (2) objc_code.mm implementing Objective-C UI using TodoWindowController with NSTextField, NSDatePicker, NSButton, and NSTableView, plus callbacks to JavaScript. (3) objc_addon.mm creating N-API class ObjcMacosAddon with threadsafe callbacks bridging Objective-C to JavaScript. (4) js/index.js wrapper class extending EventEmitter that loads the native addon and forwards events.

Objective-C callback pattern for native events in addons

To pass events from native code to JavaScript, define a std::function callback type (e.g., using TodoCallback = std::function<void(const std::string&)>), store it in a static variable (e.g., static TodoCallback g_todoAddedCallback), and provide a setter function (e.g., void setTodoAddedCallback(TodoCallback callback)). When native events occur, serialize data to JSON and call the callback with the JSON string. In the N-API addon, use napi_create_threadsafe_function to invoke the callback from any thread safely.

NSTableView implementation for native macOS addon

To display a table in a native macOS addon using NSTableView: (1) Create the table with NSTableView alloc/initWithFrame. (2) Create table columns using NSTableColumn with identifiers and set widths and titles. (3) Add columns to the table with addTableColumn. (4) Set the data source and delegate to self. (5) Wrap the table in an NSScrollView for scrolling. (6) Implement NSTableViewDataSource methods: numberOfRowsInTableView returns row count, tableView:objectValueForTableColumn:row returns cell values based on column identifier.

NSDatePicker date format conversion to JavaScript

When converting NSDate from a native macOS addon to JavaScript, convert the date to milliseconds since epoch using (NSTimeInterval)[date timeIntervalSince1970] * 1000, then in JavaScript parse it back to a Date object. NSDateFormatterShortStyle can be used to format dates for display in UI elements like NSTableView.

Native addon cannot be built directly from Node.js, requires Electron

Native addons that interact with macOS frameworks cannot be tested directly from Node.js because Node.js does not set up an app from the macOS perspective. Electron does set up a proper app, so native addons must be tested and run from within an Electron application.

binding.gyp configuration for Swift addon with actions

The binding.gyp file for a Swift addon must include a 'conditions' section for OS=="mac", sources array containing swift_addon.mm, SwiftBridge.m, and SwiftCode.swift, and two actions: (1) 'build_swift' action that compiles SwiftCode.swift using swiftc command with flags: -emit-objc-header-path for generating Objective-C header, -emit-library for static library output, -emit-module with module-name and module-link-name; (2) 'copy_swift_lib' action that copies the compiled library to the product directory and uses install_name_tool to set the correct install name. Key Xcode settings include: GCC_ENABLE_CPP_EXCEPTIONS=YES, CLANG_ENABLE_OBJC_ARC=YES, SWIFT_VERSION=5.0, MACOSX_DEPLOYMENT_TARGET=11.0, OTHER_CFLAGS with -ObjC++ and -fobjc-arc, OTHER_LDFLAGS with rpath settings.

NSHostingView bridges SwiftUI with AppKit in Electron

NSHostingView is a crucial component that allows SwiftUI views to be used in AppKit applications. It acts as a container that wraps SwiftUI views and handles the translation between SwiftUI's declarative UI system and AppKit's imperative UI system. This enables leveraging SwiftUI's modern UI framework while integrating with macOS traditional window management system.

Objective-C++ addon must call destroy() before app quit

You must call the destroy() method on a Swift/Objective-C++ addon before the application quits (for example in the 'will-quit' or 'before-quit' event handler). Without calling destroy(), persistent references to callbacks and the threadsafe function will prevent the native addon's destructor from running, causing Electron to hang on quit. The destroy() method should reset all persistent object references and release the threadsafe function.

Swift addon must check for macOS platform

When creating a JavaScript wrapper for a Swift addon in Electron, check if process.platform === 'darwin' before attempting to load the native module. If not on macOS, throw an error with a message indicating the module is only available on macOS, since Swift addons can only run on macOS.

Swift addon cannot be called from Node.js directly

Swift addon code cannot be tested by calling npm scripts that invoke Node.js directly, since Node.js doesn't set up an 'app' in the eyes of macOS. Electron does set up an app properly, so testing must be done from within an Electron application.

JSON encoding strategy for Swift Date objects in Electron

When encoding Swift Date objects to JSON for JavaScript, use a custom encoding strategy that converts dates to milliseconds since 1970 (Unix epoch), which matches JavaScript's Date timestamp format. This allows JavaScript to correctly reconstruct Date objects from the millisecond values using new Date(milliseconds).

@objc attribute required for Swift code to be accessible from Objective-C

Swift classes and methods that need to be called from Objective-C must be marked with the @objc attribute. This makes them visible to the Objective-C runtime. Classes should use @objc public class, and methods should use @objc public static func or similar.

Swift addon file structure for macOS with Node.js integration

A complete Swift addon for Electron on macOS consists of: binding.gyp (build configuration), include/SwiftBridge.h (Objective-C header defining the bridge interface), js/index.js (JavaScript wrapper extending EventEmitter), package.json (package configuration with node-addon-api and node-gyp dependencies), and src/ directory containing SwiftCode.swift (Swift implementation), SwiftBridge.m (Objective-C bridge implementation), and swift_addon.mm (Node.js addon in Objective-C++ using N-API).

Objective-C++ N-API wrapper class structure for Swift addon

The Objective-C++ wrapper (swift_addon.mm) should inherit from Napi::ObjectWrap<SwiftAddon> and define methods: Init(static) to register the class with Node.js via DefineClass, constructor to set up persistent object references and threadsafe function, HelloWorld/HelloGui/On/Destroy methods as InstanceMethods. Member variables should include: Napi::Env env_, Napi::ObjectReference emitter, Napi::ObjectReference callbacks, napi_threadsafe_function tsfn_. The Init method must set up exports using env.SetInstanceData and exports.Set().

Swift native addon architecture for Electron

Swift cannot be used directly with Node.js N-API in Electron. Instead, create a bridge using Objective-C++ to connect Swift with JavaScript. The architecture consists of four layers: Swift code (native logic), Objective-C bridge (exposes Swift to C++), Objective-C++ native addon (Node.js integration), and JavaScript wrapper (friendly API).

Objective-C bridge must store callbacks as static variables

In the Objective-C bridge (SwiftBridge.m), callback blocks should be stored as static variables (e.g., static void (^todoAddedCallback)(NSString*)). These persist throughout the application's lifecycle, allowing JavaScript callbacks to be invoked at any time when todo items are added, updated, or deleted.

Give your agent this brain