#include <window_host.hpp>
Classes | |
| struct | ContentSize |
| struct | MonitorInfo |
| Monitor information. More... | |
Public Types | |
| enum class | HitTestRegion { none , client , caption , resize_n , resize_s , resize_e , resize_w , resize_ne , resize_nw , resize_se , resize_sw , close , minimize , maximize } |
| Hit-test region types for client-decorated windows. More... | |
| using | ResizeCallback = std::function<void(uint32_t width, uint32_t height)> |
| using | Factory |
Public Member Functions | |
| virtual | ~WindowHost () |
| Out-of-line, and NOT trivial: it clears the back-pointer of every NativeViewHost still attached to this host. | |
| virtual void | show ()=0 |
| virtual void | hide ()=0 |
| virtual bool | is_visible () const =0 |
| virtual void | repaint ()=0 |
| void | mark_dirty () |
| void | mark_dirty (const Rect &root_rect) |
| void | request_frame () |
| bool | pending_repaint_is_full () const |
| bool | has_pending_dirty_bounds () const |
| Rect | pending_dirty_bounds () const |
| void | clear_pending_dirty () |
| PendingDamage::Snapshot | take_pending_dirty () |
| void | restore_pending_dirty (const PendingDamage::Snapshot &snapshot) |
| void | paint_root (canvas::Canvas &canvas, View &root, bool surface_preserves_outside_clip=false) |
| void | attach_render_loop (render::RenderLoop *loop) |
| render::RenderLoop * | render_loop () const |
| virtual void | position_beside (WindowHost *other) |
| Position this window alongside another window. | |
| virtual void * | native_window_handle () const |
| virtual void * | native_content_view_handle () const |
| virtual void * | dawn_device_handle () const |
| virtual void * | dawn_queue_handle () const |
| virtual void * | dawn_instance_handle () const |
| virtual render::GpuSurface * | gpu_surface () const |
| virtual double | gpu_render_time_ms () const |
| Most recent whole-recording GPU render time in milliseconds for the last presented frame, or 0 when GPU timing is unavailable (CPU host, adapter without timestamp-query, or no sample landed yet). | |
| virtual bool | gpu_render_timing_available () const |
| Whether whole-recording GPU render timing is available this run — the host owns a SkiaSurface whose SkiaSurface::gpu_render_timing_available() is true. | |
| virtual ContentSize | get_content_size () const |
| virtual bool | attach_native_child_view (void *child_view, float x, float y, float width, float height) |
| virtual bool | set_native_child_view_bounds (void *child_view, float x, float y, float width, float height) |
| virtual void | detach_native_child_view (void *child_view) |
| virtual bool | set_native_child_view_clip (void *child_view, bool has_clip, float x, float y, float width, float height) |
| virtual std::vector< uint8_t > | capture_png () |
| virtual std::vector< uint8_t > | capture_back_buffer_png () |
| virtual void | invalidate_input_state () |
| virtual void | request_close () |
| virtual void | set_idle_callback (std::function< void()> cb) |
| virtual void | set_resize_callback (ResizeCallback cb) |
| virtual void | set_app_key_monitor (std::function< bool(const KeyEvent &)> handler) |
| virtual void | set_open_files_handler (std::function< void(const std::vector< std::string > &)> handler) |
| virtual void | set_close_callback (std::function< void()> cb)=0 |
| virtual void | run_event_loop ()=0 |
| virtual void | set_client_decoration (bool enabled) |
| Remove native title bar and let the app draw its own. | |
| virtual void | set_fixed_aspect_ratio (float ratio) |
| Constrain window resize to maintain aspect ratio. | |
| virtual void | set_always_on_top (bool on_top) |
| Keep window above all others. | |
| virtual void | request_content_size (float w, float h) |
| Request the native window resize so its CONTENT area becomes (w × h), keeping the window's TOP-LEFT corner fixed (so a pinned toolbar / toggle row doesn't jump). | |
| virtual void | set_design_viewport (float design_w, float design_h) |
| Set a fixed "design viewport". | |
| virtual bool | design_viewport_transform (float &sx, float &sy, float &tx, float &ty) const |
| virtual float | dpi_scale () const |
| Get the DPI scale factor for this window. | |
| virtual Size | max_dimensions () const |
| Get the maximum available dimensions for this window's screen. | |
| float | convert_to_logical (float px) const |
| Convert physical pixels to logical coordinates. | |
| float | convert_to_native (float logical) const |
| Convert logical coordinates to physical pixels. | |
| virtual std::vector< MonitorInfo > | get_monitors () const |
| Get list of connected monitors. Default returns one virtual monitor. | |
| virtual void | set_mouse_relative_mode (bool enabled) |
| Hide cursor and report relative deltas (infinite drag for knobs). | |
| virtual bool | is_gpu_backed () const |
| virtual bool | supports_deferred_close () const |
| True only when request_close_deferred() schedules close handling for a later native event-loop turn. | |
| virtual void | request_close_deferred () |
| Schedule request_close() for a later native event-loop turn. | |
| virtual bool | supports_compositor_capture () const |
| True when capture_png() returns pixels from the visible compositor rather than a deterministic host-managed back buffer. | |
| virtual bool | event_loop_blocks_until_close () const |
| Browser hosts override this query because their page-owned loop returns immediately. | |
| virtual bool | event_loop_supports_exit_drain () const |
| True only when run_event_loop_until() continues dispatching accepted main-thread work after the native loop receives its stop signal. | |
| virtual void | run_event_loop_until (std::function< bool()> ready_to_return) |
| Run the event loop, then keep dispatching main-thread work until ready_to_return reports that stack-borrowed state may be destroyed. | |
| virtual bool | supports_back_buffer_capture () const |
| True when capture_back_buffer_png() is implemented by this host. | |
| virtual bool | supports_gpu_submission_evidence () const |
| True when this host can report whether the last rendered frame's GPU work was submitted toward its intended output. | |
| virtual bool | last_frame_gpu_submission_observed () const |
| True when the most recent frame rendered by this host was submitted toward its intended output (a presentable drawable, or the offscreen target when that IS the output). | |
| virtual std::vector< double > | frame_time_samples_ms () const |
| Main-thread milliseconds spent on each host frame dispatched so far (idle pump + layout + paint + submit + present), oldest first and bounded, so a finite run (a headless screenshot) can report how its frames performed. | |
| virtual void | log_gpu_diagnostics_summary () |
| Log this host's GPU-diagnostics summary line(s) — whether the Skia log bridge is wired and what reached it — at info level. | |
| bool | feature_marked_unsupported (const char *method) const |
| True once note_unsupported_feature(method) has fired for method on this host — i.e. | |
Static Public Member Functions | |
| static std::unique_ptr< WindowHost > | create (View &root, const WindowOptions &options) |
| static void | set_factory (Factory factory) |
| static void | clear_factory () |
| static bool | has_factory () |
| static bool | compute_design_viewport_transform (float window_w, float window_h, float design_w, float design_h, float &sx, float &sy, float &tx, float &ty, bool top_align=false) |
| Pure math behind set_design_viewport — used both by the platform host's paint_scene and by tests. | |
| static Point | design_viewport_window_to_root (Point pt, float window_w, float window_h, float design_w, float design_h, bool top_align=false) |
| Inverse of compute_design_viewport_transform: map a HOST/window-space point back into ROOT (design) space. | |
Protected Member Functions | |
| void | note_unsupported_feature (const char *method) |
| Log ONCE (per method, per host instance) that a window feature is a base-class no-op on this host, so a silently-degraded CPU / headless host is self-diagnosing instead of a multi-hour debug (see the CLAUDE.md GPU-host gotcha). | |
Friends | |
| class | NativeViewHost |
| using pulp::view::WindowHost::ResizeCallback = std::function<void(uint32_t width, uint32_t height)> |
|
strong |
|
virtual |
Out-of-line, and NOT trivial: it clears the back-pointer of every NativeViewHost still attached to this host.
See the registry at the bottom of this class.
|
inlinevirtual |
|
inline |
|
inlinevirtual |
|
inlinevirtual |
|
static |
|
inline |
|
inlinestatic |
Pure math behind set_design_viewport — used both by the platform host's paint_scene and by tests.
Returns false (and leaves outputs untouched) when the inputs don't define a valid transform.
top_align: when true, anchor the scaled design to the TOP of the window (vertical slack falls below it) instead of centering it vertically. Horizontal centering is unchanged. Used by the AU v3 editor so a fixed-aspect design embedded in a taller host pane (e.g. REAPER's FX-chain pane — AU can't negotiate the pane aspect the way CLAP's gui_adjust_size / VST3's checkSizeConstraint do) reads like CLAP/VST3 (content at the top) instead of floating centered between two bands. Default false = centered (every other caller). Must be passed identically at the paint AND input-mapping call sites, or clicks misalign.
|
inline |
Convert physical pixels to logical coordinates.
|
inline |
Convert logical coordinates to physical pixels.
|
static |
|
inlinevirtual |
|
inlinevirtual |
|
inlinevirtual |
|
inlinevirtual |
|
inlinestatic |
Inverse of compute_design_viewport_transform: map a HOST/window-space point back into ROOT (design) space.
Every plug-in editor host needs this to hit-test a click against the widget the user visually pointed at, and every one of them had its own byte-identical copy — the macOS GPU and CPU plug-in hosts, the iOS host, and the Windows host (WAH-10). Four copies of an inverse letterbox transform is four chances for one of them to drift from the paint-side transform, and the symptom of that drift is clicks landing on the wrong control, which is not obviously a coordinate bug when you hit it.
Returns pt unchanged when no design viewport is active, which is the identity every caller wants for the un-pinned case.
top_align MUST match the value used at paint, or input misaligns vertically — the same coupling documented on the forward transform.
|
inlinevirtual |
|
inlinevirtual |
Get the DPI scale factor for this window.
|
inlinevirtual |
Browser hosts override this query because their page-owned loop returns immediately.
Stack-owned runtime state may use it to fail closed.
|
inlinevirtual |
True only when run_event_loop_until() continues dispatching accepted main-thread work after the native loop receives its stop signal.
|
inline |
True once note_unsupported_feature(method) has fired for method on this host — i.e.
a window feature was requested that this host silently no-ops (the base-class default ran because the host did not override it). Diagnostic surface for the "CPU host silently degrades" gotcha; also the test seam for the one-time logging.
|
inlinevirtual |
Main-thread milliseconds spent on each host frame dispatched so far (idle pump + layout + paint + submit + present), oldest first and bounded, so a finite run (a headless screenshot) can report how its frames performed.
Hosts that do not measure return an empty vector. Appended at the public vtable tail for downstream WindowHost ABI safety.
|
virtual |
|
inlinevirtual |
Get list of connected monitors. Default returns one virtual monitor.
|
inlinevirtual |
Most recent whole-recording GPU render time in milliseconds for the last presented frame, or 0 when GPU timing is unavailable (CPU host, adapter without timestamp-query, or no sample landed yet).
This is render-recording time (Skia Graphite's whole-recording GpuStats elapsed time as exposed by SkiaSurface::gpu_render_time_ms()), NOT total frame time and NOT a per-pass number. GPU-backed platform hosts forward this from their SkiaSurface; the base and CPU/non-GPU hosts return 0.
|
inlinevirtual |
Whether whole-recording GPU render timing is available this run — the host owns a SkiaSurface whose SkiaSurface::gpu_render_timing_available() is true.
When false the inspector should show the honest "GPU timing unavailable" rather than 0.
|
inlinevirtual |
|
static |
|
inline |
|
pure virtual |
|
inlinevirtual |
|
inlinevirtual |
|
pure virtual |
|
inlinevirtual |
True when the most recent frame rendered by this host was submitted toward its intended output (a presentable drawable, or the offscreen target when that IS the output).
Hosts that cannot observe submission keep the false default, so an absent producer is never read as evidence.
Submitted is not displayed, and the name is the honest bound: it means the recording was accepted and the queue submit was issued, NOT that the GPU executed the command buffer or that a viewer saw the pixels. A backend can still reject the buffer at its queue after a successful insert. Display evidence needs a presented-drawable producer, which no Pulp backend has.
|
inlinevirtual |
Log this host's GPU-diagnostics summary line(s) — whether the Skia log bridge is wired and what reached it — at info level.
For the end of a bounded run, never per frame. No-op for hosts without a GPU stack. Appended at the public vtable tail for downstream WindowHost ABI safety.
| void pulp::view::WindowHost::mark_dirty | ( | ) |
| void pulp::view::WindowHost::mark_dirty | ( | const Rect & | root_rect | ) |
|
inlinevirtual |
Get the maximum available dimensions for this window's screen.
|
inlinevirtual |
|
inlinevirtual |
|
protected |
Log ONCE (per method, per host instance) that a window feature is a base-class no-op on this host, so a silently-degraded CPU / headless host is self-diagnosing instead of a multi-hour debug (see the CLAUDE.md GPU-host gotcha).
A host that really implements the feature overrides the method and never calls this.
| void pulp::view::WindowHost::paint_root | ( | canvas::Canvas & | canvas, |
| View & | root, | ||
| bool | surface_preserves_outside_clip = false ) |
|
inline |
|
inline |
|
inlinevirtual |
Position this window alongside another window.
Places to the right if there's screen space, otherwise to the left.
|
inline |
|
pure virtual |
|
inlinevirtual |
|
inlinevirtual |
Schedule request_close() for a later native event-loop turn.
The base implementation deliberately does not close synchronously.
|
inlinevirtual |
Request the native window resize so its CONTENT area becomes (w × h), keeping the window's TOP-LEFT corner fixed (so a pinned toolbar / toggle row doesn't jump).
For content whose intrinsic size changes at runtime — e.g. the Musical Typing Keyboard's piano⇄typing toggle (piano is shorter): the window shrinks/grows in height, top-aligned, while the top-left controls stay put. No-op on hosts that don't override (the content just letterboxes within the current window). Callers that also use a design viewport should update set_design_viewport()/set_fixed_aspect_ratio() to the same (w, h) so paint scale and the OS aspect lock track the resize.
|
inline |
|
inline |
|
pure virtual |
|
inlinevirtual |
Run the event loop, then keep dispatching main-thread work until ready_to_return reports that stack-borrowed state may be destroyed.
Hosts advertising exit-drain support must override this fallback.
|
inlinevirtual |
Keep window above all others.
|
inlinevirtual |
|
inlinevirtual |
Remove native title bar and let the app draw its own.
|
pure virtual |
|
inlinevirtual |
Set a fixed "design viewport".
When set, the root view's bounds are pinned to (design_w x design_h) and paint applies an aspect-correct scale + letterbox translate to fit the current window size. Input coordinates receive the inverse transform before hit-testing. Pass (0, 0) to disable.
Use this for content authored at a known fixed size (e.g. an editor imported from Figma / Stitch / v0 / Pencil) that must resize proportionally without re-layout. Combine with set_fixed_aspect_ratio(design_w / design_h) so the OS enforces the aspect on user drag and letterbox bars only appear as a backstop during in-flight drag.
Why this exists (pulp #59 / #63 / #64 / #65 — 2026-05-14): the "obvious" alternatives all failed for native-react renderers like Spectr:
|
static |
|
inlinevirtual |
Constrain window resize to maintain aspect ratio.
|
inlinevirtual |
|
inlinevirtual |
Hide cursor and report relative deltas (infinite drag for knobs).
|
inlinevirtual |
|
inlinevirtual |
|
inlinevirtual |
|
virtual |
|
pure virtual |
|
inlinevirtual |
True when capture_back_buffer_png() is implemented by this host.
Kept independent from compositor capture: an SSH-safe back-buffer path must not be inferred from the ability to capture a visible window. Appended at the public vtable tail for downstream WindowHost ABI safety.
|
inlinevirtual |
True when capture_png() returns pixels from the visible compositor rather than a deterministic host-managed back buffer.
|
inlinevirtual |
True only when request_close_deferred() schedules close handling for a later native event-loop turn.
External standalone hosts must override both methods when inspector startup can occur from an idle callback.
|
inlinevirtual |
True when this host can report whether the last rendered frame's GPU work was submitted toward its intended output.
Appended at the public vtable tail for downstream WindowHost ABI safety.
|
inline |
|
friend |