Skip to content

Editor windows

  • 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.