Skip to content
- Linux (
editor_linux.rs): the plug-in must support kPlatformTypeX11EmbedWindowID.
Each editor opens its own X11 connection and a top-level window (sized from getSize, fixed
size unless canResize), then calls attached. IPlugFrame::resizeView resizes the window
and calls onSize. Closing the window sets a flag; the next idle() closes the view.
- IRunLoop: plug-ins register file descriptors and timers through the frame. They are run by
an
EventLoop installed once with set_event_loop; the app installs glib_loop::GlibLoop,
which adds them to GTK’s main loop (unix_fd_add_local, timeout_add_local). Source ids are
kept in a thread-local map, so editors must be created and destroyed on the main thread. The
X connection’s own fd is registered the same way.
- GDK_BACKEND: GLX-based editors fail when GTK runs natively on Wayland in the same
process, so
main.rs sets GDK_BACKEND=x11 unless the user set it.
- macOS (
editor_macos.rs): the plug-in must support kPlatformTypeNSView. Each editor is
an NSWindow (sized from getSize in points, resizable only if canResize) whose content view
the plug-in attaches to. The windows float (NSFloatingWindowLevel, FullScreenAuxiliary)
and hide while another app is active (hidesOnDeactivate), like Logic’s; several cascade. An
NSWindowDelegate reports the close button (windowWillClose:, read by pump) and applies
checkSizeConstraint during live resizes, then onSize. The window is a small NSWindow
subclass (MarbblePlugInWindow) whose keyDown:/keyUp: get only the keys the plug-in’s
view didn’t use; they go to the hook set with keys::set_key_forwarder (keys.rs maps macOS
key codes to KeyboardEvent key/code). The app emits them to the main window as
plugin-key, and src/pluginKeys.ts re-dispatches each as a synthetic KeyboardEvent, so key
commands, the user’s keymap and Musical Typing all apply. Menu ⌘-shortcuts are taken by the
menu first, so nothing runs twice. Linux doesn’t forward keys: the plug-in’s child window
takes KeyPress itself. IPlugFrame::resizeView resizes the
content keeping the top-left corner. There is no IRunLoop: plug-ins use the main run loop.
open fails off the main thread; close and raise called from another thread (an async
command, a controller dropped elsewhere) are queued on the main queue, and close keeps the
plug-in’s Shared alive until the view is removed. set_hide_on_deactivate(false) is for the
editor example, which macOS may never make the active app when it’s started from a terminal.
- Windows:
editor_other.rs returns an error (“not implemented on this platform yet”).
Plug-ins load and process normally.
crates/vst3-host/examples/editor.rs opens one editor for debugging: on Linux with a small
poll() loop, without GTK; on macOS with an NSApplication event loop.