ui::NativeHost¶
Header: winui/render/NativeHost.hpp.
The interface between a NativeControl, a leaf wrapping a real Win32 child window such as RichEdit, a shell control or WebView2, and whatever owns the real HWND.
Call it from a NativeControl. The library implements it, and a test installs TestNativeHost.
Every other control draws itself without a window of its own. NativeControl hosts what libwinui doesn't reimplement. The control never calls Win32 itself. It calls this interface from Element::sync_native(), keyed by its VisualId, and the host creates, moves, clips and hides the child window. The window installs its host with Window::set_native_host() (non-owning). The host must outlive every NativeControl synced against it, since a NativeControl's destructor calls back into it.
Example:
// An app never calls a NativeHost. It puts a NativeControl in the tree, and the window's host
// creates the child window, places it and keeps it in step with the element:
auto edit = std::make_unique<ui::NativeControl>(
ui::NativeControlDesc{.class_name = "EDIT", .initial_text = "hello"}, ui::Size{100, 20});
window.set_content(std::move(edit));
~NativeHost¶
ensure_created¶
Creates the native control for id if it doesn't exist yet, and does nothing if it does. A NativeControl calls this once per sync_native(), whether or not it already has a live handle.
set_bounds¶
Moves and resizes the native control to bounds, in DIPs like every other Element. The host converts to device pixels.
set_visible¶
Shows or hides the control without destroying its window, for example while it is inactive. Does nothing if id has no created control yet.
destroy¶
Destroys the native control. Does nothing if id has none.
set_clip¶
Cuts the native control down to visible (DIPs, the same space as set_bounds()), or shows all of it for nullopt. A child window ignores the clips the rest of the window is drawn with, so a control half scrolled out of a Scroll would otherwise paint over whatever sits outside the viewport. NativeControl::sync_native() sends the part its scrolling ancestors leave in view, through place() whenever the control also moved, so a host may keep the region relative to the window. The default does nothing, for a host with nothing to cut.
place¶
Moves the control and clips it in one step, so a host that repaints on a move paints the new position with the new clip, not the one left over from the old position. NativeControl::sync_native() calls this whenever the bounds changed; the default is set_bounds() then set_clip().
native_handle¶
The raw platform handle (an HWND on Windows), for control-specific messages a generic NativeControl can't express, such as WM_SETTEXT or WM_GETTEXT to a RichEdit. nullptr if id has no created control yet.
set_spell_checker¶
Publishes the window's spell checker, or null when the window has none. Window::sync_native() calls it, and NativeControl::sync_native() hands the checker to the control through Element::sync_spell_checker().
Other controls get the checker when they take focus. A NativeControl never becomes the window's focused element, because keyboard focus inside it belongs to the child window, so it gets the checker through this sync pass instead.
spell_checker¶
The checker set_spell_checker() last published, or null. Non-owning.
begin_sync¶
Window::sync_native() brackets its tree walk with these. Every NativeControl the walk reaches reports through present() whether it should show. end_sync() then hides every control the walk didn't reach, such as one on a Tabs page or NavigationShell entry that isn't selected, and present() shows it again the next time a pass reaches it. Only end_sync() hides anything, so a host whose controls are synced directly never hides one this way. This one starts a pass.
end_sync¶
Ends a pass: hides (set_visible(false)) every shown control present() wasn't called for since begin_sync().
present¶
Called by NativeControl::sync_native() on every sync: visible is whether any of the control shows. Calls set_visible() only on a change; a control starts out shown.
presented¶
Whether present()/end_sync() last left the control shown (true for one never presented).
forget¶
Drops the control's presence record; NativeControl's destructor calls it before destroy().
notify_host_lost¶
Tells control, a NativeControl registered through set_owner(), that this host is going away while it lives on (its window was closed; the app still owns the Window and its tree). The control forgets the host and its native window, and gets a new one from the next sync_native(). A host calls it from its destructor for every owner still registered.
set_owner¶
Records which NativeControl owns id, so a host that receives platform events addressed to the child window can route them back to its element. On Windows that is a child window's WM_CONTEXTMENU: a right-click inside a native control goes to the child window and never reaches Window::handle_context_menu(), so the host looks the owner up by its handle and calls Element::handle_context_menu() on it directly.
NativeControl::sync_native() calls it right after ensure_created(), so the owner is registered for exactly as long as the control exists. destroy() drops it again, and NativeControl is non-movable, so the pointer can't go stale. The default does nothing, for a host with no platform events to route. A host implements it, and only NativeControl calls it.