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 · API · all subjects

native integration

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

GTK3 requirement for Electron on Linux

Electron uses GTK3 internally because Chromium uses GTK3. Using GTK4 would cause runtime conflicts since both GTK3 and GTK4 would be loaded in the same process. When Chromium upgrades to GTK4, native code can likely be upgraded to GTK4 as well.

Linux native code requirements for GTK3 development

To develop native C++ addons for Electron on Linux using GTK3, you need: a Linux distribution with GTK3 development files installed, the pkg-config tool, and the G++ compiler and build tools. On Ubuntu/Debian: sudo apt-get install build-essential pkg-config libgtk-3-dev. On Fedora/RHEL/CentOS: sudo dnf install gcc-c++ pkgconfig gtk3-devel.

binding.gyp configuration for Linux GTK3 addon

For a Linux-specific GTK3 addon, the binding.gyp file must use conditional compilation with OS=="linux" check. It should leverage pkg-config to locate GTK3 libraries and headers using commands like `<!@(pkg-config --cflags-only-I gtk+-3.0)` and `<!@(pkg-config --libs gtk+-3.0)`. Must link the uuid library with -luuid. Must enable exceptions with -fexceptions and -pthread flags. The NODE_ADDON_API_CPP_EXCEPTIONS define must be set. The `<!@` syntax executes commands and uses their output as values.

TodoItem struct for GTK3 native code

A TodoItem struct stores todo data with: uuid_t id for unique identification, std::string text for content, int64_t date for timestamp in milliseconds. It includes a toJson() method that returns a JSON string with fields "id", "text", and "date". It includes a static formatDate(int64_t timestamp) method that formats timestamps as YYYY-MM-DD strings.

GTK thread management in native Electron addons

GTK must run in its own separate thread to prevent blocking Node.js's event loop. This requires managing GMainContext, GMainLoop, and a std::thread. The hello_gui() function initializes GTK with gtk_init_check(), creates a new GMainContext and GMainLoop, and launches a detached std::thread to run the GTK application. The cleanup_gui() function properly shuts down by quitting the main loop and unreferencing the context and loop.

Thread-safe callback notification in GTK

To safely invoke JavaScript callbacks from the GTK thread, use g_main_context_invoke() with a lambda that casts callback data and executes the callback. This function schedules execution in the GTK main context, ensuring thread safety since GTK is not thread-safe and all UI operations must happen on the main thread.

GTK UI definition using XML in C++

GTK UI layouts can be defined inline using XML markup and loaded with gtk_builder_add_from_string(). The XML includes object definitions with class, id, and property elements. Objects are then retrieved using gtk_builder_get_object() by their id. This pattern is commonly used in GTK applications for defining UI structure.

Event handler pattern for GTK list items

GTK ListBox items can show context menus using the row-activated signal. The handler creates a GMenu, appends actions with g_menu_append(), creates a popover from the menu model with gtk_popover_new_from_model(), and displays it with gtk_popover_popup(). Actions are registered on the application using g_action_map_add_action_entries().

napi_create_threadsafe_function for cross-thread JavaScript calls

napi_create_threadsafe_function() creates a thread-safe function that allows calling JavaScript from any thread. It takes parameters: the environment, a JavaScript callback, a name, queue size (0 for unlimited), max concurrent calls (1 for serialization), context data, a callback to execute on the JS thread, and an output handle. The callback receives the unpacked data, can call JavaScript functions, and must delete allocated data. This is essential for GUI frameworks that run on separate threads.

Node.js addon callback data structure pattern

For thread-safe callbacks, create a struct to hold event data (event type, payload, addon pointer). Allocate this on the heap in the native code, pass it to napi_call_threadsafe_function(), unpack it in the callback on the JS thread, call the JavaScript function, and delete the allocated data.

Napi::CallbackInfo in node-addon-api

Napi::CallbackInfo is a class provided by node-addon-api that encapsulates all information about a JavaScript function call. It provides info.Env() for the execution environment, info.Length() for argument count, info[0] for accessing arguments by index, and info[0].As<Type>() for type conversion. Every native method callable from JavaScript receives this object.

UUID generation and formatting in C++

Use uuid_t from uuid/uuid.h. Generate with uuid_generate(uuid_t). Convert to string with uuid_unparse(uuid_t, char[37]) which produces a 36-character string plus null terminator. The libuuid library must be linked.

GTK date handling using GDateTime

Create GDateTime with g_date_time_new_local(year, month, day, hour, minute, second). Note that GTK calendar months are 0-indexed while GDateTime months are 1-indexed, so add 1 when creating GDateTime from calendar. Convert to Unix timestamp milliseconds with g_date_time_to_unix(datetime) * 1000. Always unref GDateTime with g_date_time_unref().

Node.js addon package.json configuration

package.json for native addons should include: main pointing to the JavaScript entry point (e.g., js/index.js), scripts with build target using node-gyp, and dependencies on node-addon-api and bindings packages. Example build scripts: "build-electron": "electron-rebuild", "build": "node-gyp configure && node-gyp build".

GTK popup menu and GMenu usage

Create menus with g_menu_new(). Append items with g_menu_append(menu, label, action_id). Create popover from menu with gtk_popover_new_from_model(widget, G_MENU_MODEL(menu)). Set position with gtk_popover_set_position(popover, GTK_POS_RIGHT or other). Show with gtk_popover_popup(popover). Unref menu with g_object_unref(menu).

napi_call_threadsafe_function for invoking callbacks

Use napi_call_threadsafe_function(tsfn, data, mode) to queue a callback from a native thread. Pass the thread-safe function handle, data pointer to pass to the callback, and mode (napi_tsfn_blocking for blocking queue). The data is passed to the registered callback function which executes on the JavaScript thread.

NODE_API_MODULE macro for addon entry point

Use NODE_API_MODULE(addon_name, init_function) to register a Node.js native addon. The addon_name must match the target_name in binding.gyp. The init_function returns a Napi::Object with the exported API. This macro is required for Node.js to load and initialize the addon.

Native C++ addon platform check - Linux only

Before loading a native C++ addon, check that the process is running on Linux using `if (process.platform !== 'linux')` and throw an error or return an empty object on other platforms. This prevents module loading failures on non-Linux systems.

Loading native addon with node-bindings

Load a native C++ addon using `const native = require('bindings')('addon_name')`, then instantiate the native class with `new native.ClassName()`. The addon must be built with node-gyp or similar tool.

EventEmitter pattern for C++ native addon

Wrap a native C++ addon in a JavaScript class that extends EventEmitter. Forward events from the C++ addon to JavaScript using the addon's .on() method to listen and then emit the JavaScript events.

Destroy native addon resources on app quit

Call a destroy() method on the native addon before the app quits, specifically 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.

Native addon event forwarding example

Use this pattern to forward events from C++ to JavaScript: this.addon.on('eventName', (payload) => { this.emit('eventName', this.parse(payload)) }). This allows JavaScript to listen for native events through the wrapper's EventEmitter interface.

Complete C++ addon usage example with GTK3

import cppLinux from 'cpp-linux'; console.log(cppLinux.helloWorld('Hi!')); cppLinux.on('todoAdded', (todo) => { console.log('New todo added:', todo); }); cppLinux.on('todoUpdated', (todo) => { console.log('Todo updated:', todo); }); cppLinux.on('todoDeleted', (todo) => { console.log('Todo deleted:', todo); }); cppLinux.helloGui();

JSON payload parsing in native addon wrapper

When receiving JSON payloads from the C++ addon, parse them with JSON.parse() and convert date strings to JavaScript Date objects using new Date(). This ensures proper data type conversion for JavaScript consumers.

GTK3 native GUI with Electron addon

A native C++ addon can create a GTK3 GUI that runs in its own thread. The GUI can include text entry fields, calendar widgets, buttons, scrollable lists, and right-click context menus. All interactions trigger JavaScript events through the EventEmitter pattern.

Linux-specific native addon advantages

Using native C++ addons with Electron allows bidirectional communication between JavaScript and C++, access to system features, integration with Linux-specific libraries, and creation of performant native UIs while maintaining Electron's development flexibility.

Native addon Windows C++ setup: binding.gyp configuration

For Windows-specific native addons, the binding.gyp file must include three key configurations: 1) Ensure compilation only on Windows using conditions with OS=="win", 2) Include Windows-specific libraries like comctl32.lib and shcore.lib, 3) Configure compiler settings and C++ macros. The msvs_settings section controls Visual Studio compiler behavior. VCCLCompilerTool settings should include ExceptionHandling: 1 (enables C++ exception handling with /EHsc flag), DebugInformationFormat: "OldStyle" (uses PDB format), and AdditionalOptions: ["/FS"] (enables file serialization for parallel builds). VCLinkerTool should have GenerateDebugInformation: "true" to include debug symbols. Preprocessor defines should include NODE_ADDON_API_CPP_EXCEPTIONS (enables C++ exceptions in Node-API), WINVER=0x0A00 (Windows 10 minimum), and _WIN32_WINNT=0x0A00 (Windows NT kernel version).

Win32 GUI implementation requires separate thread for message loop

To prevent blocking the Node.js event loop, Win32 GUI code must run in a separate thread using std::thread. The Windows message loop (GetMessage, TranslateMessage, DispatchMessage) runs in an infinite loop and would block Node.js if executed on the main thread. By running the GUI in a detached thread via guiThread.detach(), both the native Windows interface and Node.js remain responsive and potential deadlocks from GUI operations waiting on JavaScript callbacks are prevented.

DPI awareness configuration for Win32 GUI

For proper high-DPI display scaling, call SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) at the start of the GUI thread. Retrieve the DPI using GetDpiForSystem(). To scale UI elements based on DPI, use the MulDiv function: MulDiv(value, dpi, 96) where 96 is the default DPI. All window sizes, control positions, and font sizes should be scaled using this calculation to ensure proper rendering on high-DPI displays.

Win32 common controls initialization

Initialize common controls before creating any controls by calling InitCommonControlsEx with an INITCOMMONCONTROLSEX structure. Set dwSize to sizeof(INITCOMMONCONTROLSEX) and dwICC to ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES to enable standard Windows controls like buttons, edit boxes, list boxes, and date pickers.

Native addon destructor cleanup requirement for Electron apps

Must call destroy() on the native addon before the app quits (in will-quit or before-quit event handler). Without this, persistent references to callbacks and the threadsafe function will prevent the native addon's destructor from running, causing Electron to hang on quit. The destructor must call napi_release_threadsafe_function with napi_tsfn_release and reset all Napi::ObjectReference members.

Win32 GUI thread must call delete callback data

In the threadsafe function callback, when a CallbackData object is created and passed between threads, it must be deleted after processing. The finalization callback receives a CallbackData* and is responsible for calling delete callbackData after invoking the associated JavaScript callback to prevent memory leaks.

Segoe UI font for modern Windows GUI appearance

Use "Segoe UI" as the font face name when creating fonts for modern Windows GUI appearance in C++ native addons. Font should be created with CLEARTYPE_QUALITY for anti-aliasing, FW_NORMAL weight, and DEFAULT_CHARSET. Height should be negative and scaled based on DPI (e.g., -Scale(14, dpi) for 14pt).

Windows manifest dependency for common controls

Include the Windows common controls manifest dependency using pragma comment: #pragma comment(linker, "/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"). This ensures the application uses the correct version of Windows common controls.

SYSTEMTIME to JavaScript Date conversion

Convert Windows SYSTEMTIME timestamps to milliseconds since epoch for JavaScript using SystemTimeToFileTime to get FILETIME, then use the formula: (FILETIME_value - 116444736000000000ULL) / 10000. JavaScript Date objects use milliseconds since epoch, so converting properly ensures timestamps display correctly when passed from C++ to JavaScript.

Node-API exception handling configuration

Enable NODE_ADDON_API_CPP_EXCEPTIONS preprocessor macro to use C++ exception handling in Node-API. This allows C++ code to throw and catch C++ exceptions rather than using return-value error handling, making code more idiomatic. With this enabled, set ExceptionHandling: 1 in VCCLCompilerTool settings to enable /EHsc compiler flag.

Napi::ObjectWrap for exposing C++ classes to JavaScript

Use Napi::ObjectWrap<ClassName> base class to wrap C++ objects for JavaScript. Define an Init static method that calls DefineClass to register instance methods. Methods should be wrapped as Napi::Value methods that receive Napi::CallbackInfo. Use Napi::FunctionReference to store the constructor reference. This pattern allows JavaScript to create instances of C++ classes and call their methods.

EventEmitter pattern in JavaScript wrapper for native addon

Create a JavaScript EventEmitter-based wrapper around the native addon to provide a familiar Node.js API. The wrapper should check process.platform to ensure platform compatibility. Listen to events from the native addon using addon.on() and re-emit them via this.emit(), optionally transforming data (e.g., converting timestamp strings to Date objects). Export an instance or throw an error if the platform is not supported.

Win32 window class registration and creation flow

To create a Win32 window: 1) Define WNDCLASSEXW structure with cbSize, lpfnWndProc (window procedure), hInstance, and lpszClassName. 2) Call RegisterClassExW to register the class. 3) Call CreateWindowExW with the class name, title, style flags (WS_OVERLAPPEDWINDOW for standard window), position (CW_USEDEFAULT), size (scaled by DPI), parent window (nullptr for top-level), and module handle. Check if the returned HWND is nullptr to detect creation failure.

Win32 GUID to JSON string conversion

To serialize a Windows GUID to JSON: Call StringFromCLSID(guid, &guidString) to get an OLECHAR* wide string representation. Convert to std::wstring, then to std::string. Call CoTaskMemFree(guidString) to free the allocated memory. The resulting string includes curly braces (e.g., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}").

Native addon build command for Electron

Run 'npm run build-electron' to rebuild native addon for the current Electron version using electron-rebuild, or 'npm run build' to use node-gyp configure and node-gyp build commands directly.

N-API Napi::ObjectWrap for native class binding

Create native addon class inheriting from Napi::ObjectWrap<ClassName>. Implement static Init method that calls DefineClass with class name and array of InstanceMethod entries. Each method takes a string name and method pointer like InstanceMethod("methodName", &ClassName::CppMethodName). Store constructor reference in env.SetInstanceData and export with exports.Set("ClassName", func).

Objective-C native addon build configuration for macOS

To build an Objective-C native addon for Electron on macOS, use binding.gyp with OS=='mac' condition. Include Foundation and AppKit frameworks via libraries: ["-framework Foundation", "-framework AppKit"]. Set xcode_settings with CLANG_ENABLE_OBJC_ARC: "YES" for automatic reference counting, OTHER_CFLAGS: ["-ObjC++", "-std=c++17"], MACOSX_DEPLOYMENT_TARGET: "11.0", GCC_ENABLE_CPP_EXCEPTIONS: "YES", and CLANG_CXX_LIBRARY: "libc++". Use .mm extension for Objective-C++ source files.

AppKit framework components for native macOS GUI

AppKit is the primary UI framework for macOS applications. It provides components like NSWindow (windows), NSButton (buttons), NSTextField (text fields), NSDatePicker (date selection), NSTableView (tabular data display), NSTableColumn (table columns), NSScrollView (scrollable containers), and NSWindowController (window management). All UI operations must execute on the main thread.

UI operations must run on main thread in macOS

In macOS/iOS, 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 calling native UI code from a Node.js worker thread, use Grand Central Dispatch (GCD) to safely redirect to the main thread: dispatch_async(dispatch_get_main_queue(), ^{ /* UI code */ });. This ensures proper UI behavior and thread safety.

Objective-C date to JavaScript timestamp conversion

To convert an NSDate to JavaScript format, convert to milliseconds since epoch: @((NSTimeInterval)[date timeIntervalSince1970] * 1000). The resulting number can be serialized to JSON and converted to a JavaScript Date object when received in JavaScript.

NSTableView data source protocol implementation

Implement NSTableViewDataSource methods: numberOfRowsInTableView:(NSTableView *)tableView returns NSInteger count of rows, and tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row returns id object for that cell. Set both delegate and data source with [tableView setDataSource:self] and [tableView setDelegate:self].

NSDateFormatter for displaying dates in table views

Create NSDateFormatter with [[NSDateFormatter alloc] init], set style with [formatter setDateStyle:NSDateFormatterShortStyle], then format dates with [formatter stringFromDate:date]. This produces localized, human-readable date strings suitable for display in UI.

NSWindow initialization and setup

Create NSWindow with alloc/initWithContentRect:styleMask:backing:defer: parameters. styleMask options include NSWindowStyleMaskTitled (title bar), NSWindowStyleMaskClosable (close button), NSWindowStyleMaskResizable (resize handles). Center with [window center]. Set title with [window setTitle:@"string"]. Access content view with [window contentView] to add subviews.

NSTextField and placeholder text setup

Create NSTextField with [[NSTextField alloc] initWithFrame:NSMakeRect(x, y, width, height)]. Set placeholder text with [textField setPlaceholderString:@"text"]. Get text value with [textField stringValue] and set with [textField setStringValue:@"text"].

NSDatePicker configuration for date selection

Create NSDatePicker with [[NSDatePicker alloc] initWithFrame:NSMakeRect(x, y, width, height)]. Set style with [datePicker setDatePickerStyle:NSDatePickerStyleTextField]. Configure elements to show with [datePicker setDatePickerElements:NSDatePickerElementFlagYearMonthDay]. Get selected date with [datePicker dateValue].

NSButton action binding in Objective-C

Create NSButton with [[NSButton alloc] initWithFrame:NSMakeRect(x, y, width, height)]. Set title with [button setTitle:@"text"]. Set bezel style with [button setBezelStyle:NSBezelStyleRounded]. Bind action with [button setTarget:self] and [button setAction:@selector(methodName:)]. The action method receives the button as parameter.

NSScrollView for containing NSTableView

Create NSScrollView with [[NSScrollView alloc] initWithFrame:NSMakeRect(x, y, width, height)]. Set border with [scrollView setBorderType:NSBezelBorder]. Enable scrolling with [scrollView setHasVerticalScroller:YES]. Add table view with [scrollView setDocumentView:tableView].

NSTableColumn for NSTableView columns

Create NSTableColumn with [[NSTableColumn alloc] initWithIdentifier:@"identifier"] where identifier is a unique string. Set width with [column setWidth:pixelWidth]. Set display title with [column setTitle:@"text"]. Add to table with [tableView addTableColumn:column].

NSMutableArray and NSUUID for todo storage

Create NSMutableArray with [NSMutableArray array]. Add objects with [array addObject:object]. Generate unique IDs with NSUUID *uuid = [NSUUID UUID] and convert to string with [uuid UUIDString]. Store todos as NSDictionary: @{@"id": idString, @"text": text, @"date": date}.

NSJSONSerialization for converting objects to JSON

Convert Objective-C objects to JSON with NSJSONSerialization dataWithJSONObject:options:error:. Creates NSData which can be converted to NSString with [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]. Convert to C++ string with [nsString UTF8String]. Pass NSError* to capture serialization errors.

N-API method implementation pattern

Implement methods as private members returning Napi::Value or void, taking const Napi::CallbackInfo& info parameter. Access environment with info.Env(), parameter count with info.Length(), and specific parameters with info[index]. Throw exceptions with Napi::TypeError::New(env, "message").ThrowAsJavaScriptException(). Return values with Napi::String::New(env, value) or env.Null/Undefined().

NODE_API_MODULE macro for native addon export

End native addon .mm file with NODE_API_MODULE(module_name, Init) where module_name matches the binding.gyp target_name and Init is the module initialization function. This registers the addon for requiring.

Swift cannot be used directly with Node.js N-API

While you cannot use Swift directly with the Node.js N-API as used by Electron, you can create a bridge using Objective-C++ to connect Swift with JavaScript in your Electron application.

macOS Swift native addon build architecture

Building Swift native addons for macOS requires a two-step compilation process: compile Swift code separately into a static library (.a file), create an Objective-C bridge that exposes Swift functionality, link the compiled Swift library with the Node.js addon, and manage Swift runtime dependencies. Swift has its own compilation model and runtime requirements that don't directly integrate with node-gyp's C/C++ focused build system.

Give your agent this brain