pub trait Shell: Debug {
Show 33 methods
// Required methods
fn backend(&self) -> ShellBackend;
fn caps(&self) -> ShellCaps;
fn create_window(
&mut self,
desc: &WindowDesc<'_>,
) -> Result<WindowId, ShellError>;
fn destroy_window(&mut self, window: WindowId) -> Result<(), ShellError>;
fn window_state(&self, window: WindowId) -> Result<WindowState, ShellError>;
fn set_title(
&mut self,
window: WindowId,
title: &str,
) -> Result<(), ShellError>;
fn set_visible(
&mut self,
window: WindowId,
visible: bool,
) -> Result<(), ShellError>;
fn set_mode(
&mut self,
window: WindowId,
mode: DisplayMode,
) -> Result<(), ShellError>;
fn set_constraints(
&mut self,
window: WindowId,
constraints: SizeConstraints,
) -> Result<(), ShellError>;
fn monitors(&self) -> &[MonitorInfo];
fn pump(&mut self, sink: &mut dyn FnMut(ShellEvent));
fn keep_alive(&mut self);
fn surface_target(
&self,
window: WindowId,
) -> Result<SurfaceTarget, ShellError>;
fn set_pointer_mode(
&mut self,
window: WindowId,
mode: PointerMode,
) -> Result<(), ShellError>;
fn set_cursor(
&mut self,
window: WindowId,
cursor: Option<CursorIcon>,
) -> Result<(), ShellError>;
fn warp_pointer(
&mut self,
window: WindowId,
position: PhysicalPoint,
) -> Result<(), ShellError>;
fn reply_close_request(
&mut self,
window: WindowId,
reply: CloseReply,
) -> Result<(), ShellError>;
fn clipboard_offer(
&mut self,
window: WindowId,
offers: &[ClipboardOffer<'_>],
) -> Result<(), ShellError>;
fn clipboard_request(
&mut self,
window: WindowId,
mime: MimeType,
) -> Result<ClipboardRequestId, ShellError>;
fn request_frame(&mut self, window: WindowId) -> Result<(), ShellError>;
// Provided methods
fn reposition_popup(
&mut self,
popup: WindowId,
anchor: LogicalRect,
size: LogicalSize,
) -> Result<(), ShellError> { ... }
fn set_panel(
&mut self,
window: WindowId,
size: LogicalSize,
panel: &PanelDesc<'_>,
) -> Result<(), ShellError> { ... }
fn monitor(&self, id: MonitorId) -> Option<&MonitorInfo> { ... }
fn wait_events(&mut self, timeout: Option<Duration>) { ... }
fn waker(&mut self) -> Option<ShellWaker> { ... }
fn align_event_clock(&mut self, elapsed: Duration) { ... }
fn clipboard_readable(&self, window: WindowId) -> bool { ... }
fn activation_token(
&mut self,
window: WindowId,
) -> Result<Option<String>, ShellError> { ... }
fn set_text_input_area(
&mut self,
window: WindowId,
area: Option<PhysicalRect>,
) -> Result<(), ShellError> { ... }
fn set_input_region(
&mut self,
window: WindowId,
region: Option<&[PhysicalRect]>,
) -> Result<(), ShellError> { ... }
fn set_idle_inhibit(
&mut self,
window: WindowId,
inhibit: bool,
) -> Result<(), ShellError> { ... }
fn open_url(
&mut self,
window: WindowId,
url: &WebUrl,
) -> Result<(), ShellError> { ... }
fn set_text_input(
&mut self,
window: WindowId,
field: Option<TextPurpose>,
) -> Result<(), ShellError> { ... }
}Expand description
The window system, as the engine sees it.
Object-safe by requirement; see the crate docs for why, and
backend for how an implementation is selected at runtime.
§The loop is the caller’s
There is no run that takes the program over: the caller loops on
pump and wait_events itself, so
ending the program is leaving that loop and dropping the shell. Each
desktop backend’s Drop destroys the windows it still holds, so nothing has
to be torn down by hand first. Work that arrives
on another thread reaches a sleeping loop through a ShellWaker.
§Implementing this
Six obligations that are not visible in the signatures. The first three are P0.4’s; the last three are P0.5c’s, written down because a real compositor showed that leaving them unstated pushes the work onto every consumer.
- Stale handles fail cleanly. Every method taking a
WindowIdmust returnShellError::InvalidWindowfor a destroyed or foreign one, never act on whatever window took the slot. - Timestamps are rebased. Input events carry the window system’s
timestamp converted to the engine epoch — see
EventTime, which documents the conversion each platform needs. - Capabilities are latched.
capsmust return the same value for the shell’s lifetime, so a consumer that branched on it at startup is never contradicted mid-session. Seecapsfor the Wayland-binds-a-global-late edge this rules out. - Every accepted clipboard read is answered exactly once, and within a
bounded time.
clipboard_requestthat returnsOkpromises exactly oneShellEvent::ClipboardDatacarrying thatClipboardRequestId. A backend that cannot complete the read answersClipboardContent::Unavailablerather than dropping the request; a request with no answer is a UI stuck on “pasting…” forever, which no consumer can detect. - A read that cannot be answered yet is held, never answered “empty”.
If the backend does not yet know what is on the clipboard — Wayland’s
focus-gated, asynchronous
wl_data_device.selectionis the case this exists for — it holds the request until it does, and bounds that wait. ReportingEmptyfor “I have not looked yet” is indistinguishable from an empty clipboard, so it makes every consumer write a retry loop with a timeout it cannot choose correctly. Where the answer is always immediately available (X11 asks the server who owns the selection; a headless shell owns it), holding costs nothing and this obligation is discharged by answering. - A refusal for want of user interaction is named. Where the window
system requires a recent input event to claim the clipboard — Wayland
does, the browser does, X11 and Win32 do not —
clipboard_offerreturnsShellError::NeedsUserInteractionand not a generic backend error, so a caller can distinguish “ask the user to press the key again” from “this is broken”. A backend on a platform without the rule never returns it.
Required Methods§
Sourcefn backend(&self) -> ShellBackend
fn backend(&self) -> ShellBackend
Which implementation this is. Logs and bug reports only — behaviour
branches on caps.
Sourcefn create_window(
&mut self,
desc: &WindowDesc<'_>,
) -> Result<WindowId, ShellError>
fn create_window( &mut self, desc: &WindowDesc<'_>, ) -> Result<WindowId, ShellError>
Creates a window. The window has no size yet.
desc.size is a request. The authoritative size arrives later, as the
first ShellEvent::Resized, and until it does
WindowState::size is None. This is not a headless quirk: a Wayland
xdg_surface is unsized and may not be given a buffer until the
compositor answers with a configure, which is a round trip away.
A swapchain needs an extent, so this is a hard ordering constraint:
let window = shell.create_window(&WindowDesc::default())?;
let size: PhysicalSize = loop {
shell.pump(&mut |_event| { /* … */ });
if let Some(size) = shell.window_state(window)?.size() {
break size;
}
};
// Only now is there an extent to create a swapchain at.
assert_eq!(size, PhysicalSize::new(1280, 720));HeadlessShell deliberately defers the first configure by at least one
pump, so a consumer that skips the loop fails in CI rather than at
P0.5.
§Errors
ShellError::WindowCreation if the window system refused, or
ShellError::Unsupported if this would be a second window on a
backend without ShellCaps::MULTI_WINDOW.
Sourcefn destroy_window(&mut self, window: WindowId) -> Result<(), ShellError>
fn destroy_window(&mut self, window: WindowId) -> Result<(), ShellError>
Destroys a window. A ShellEvent::WindowDestroyed follows.
The SurfaceTarget previously returned for this window is dead
afterwards; the HAL surface built from it must be destroyed first.
§Errors
ShellError::InvalidWindow if the handle is stale.
Sourcefn window_state(&self, window: WindowId) -> Result<WindowState, ShellError>
fn window_state(&self, window: WindowId) -> Result<WindowState, ShellError>
A snapshot of the window’s current state.
For consumers that started late; not a substitute for handling events.
Note that WindowState::size is None until the window system has
configured the window, and that the requested mode and the effective
one are separate fields — see WindowState.
§Errors
ShellError::InvalidWindow if the handle is stale.
Sourcefn set_visible(
&mut self,
window: WindowId,
visible: bool,
) -> Result<(), ShellError>
fn set_visible( &mut self, window: WindowId, visible: bool, ) -> Result<(), ShellError>
Sourcefn set_mode(
&mut self,
window: WindowId,
mode: DisplayMode,
) -> Result<(), ShellError>
fn set_mode( &mut self, window: WindowId, mode: DisplayMode, ) -> Result<(), ShellError>
Asks for windowed or borderless.
A request, not a command. It updates
WindowState::requested_mode immediately and nothing else; the mode
that is actually in effect appears in
WindowConfiguration::mode when the window system answers, which it
may do with something other than what was asked (a compositor can refuse
fullscreen, and a tiling window manager makes the question moot). Use
WindowState::mode_request_honoured rather than reading the request
back as fact.
The answer usually arrives as a ShellEvent::Resized, preceded by a
ShellEvent::ScaleFactorChanged when the target monitor has a
different scale. Never assume the new size — read the event.
§Errors
ShellError::InvalidWindow if the handle is stale, or
ShellError::NoSuchMonitor if the named monitor is gone.
Sourcefn set_constraints(
&mut self,
window: WindowId,
constraints: SizeConstraints,
) -> Result<(), ShellError>
fn set_constraints( &mut self, window: WindowId, constraints: SizeConstraints, ) -> Result<(), ShellError>
Asks for resize limits and an aspect lock.
Hints, not guarantees, and a request rather than a command: it updates
WindowState::requested_constraints immediately, and the only
observable effect is whatever size the window system reports next. No
platform reports back “effective constraints”, so neither does this
seam. See SizeConstraints.
§Errors
ShellError::InvalidWindow if the handle is stale.
Sourcefn monitors(&self) -> &[MonitorInfo]
fn monitors(&self) -> &[MonitorInfo]
Every connected monitor.
Invalidated by ShellEvent::MonitorsChanged; call again rather than
caching across it.
Sourcefn pump(&mut self, sink: &mut dyn FnMut(ShellEvent))
fn pump(&mut self, sink: &mut dyn FnMut(ShellEvent))
Drains everything that has arrived from the window system into sink.
Non-blocking and finite: it delivers what is queued and returns. Call it
once at the top of every frame. See the crate docs for why there
is no run() and how a requestAnimationFrame-driven build uses this.
The sink is &mut dyn FnMut rather than a generic parameter because the
trait must stay object-safe. That is not purely a cost: a closure passed
here can borrow the caller’s state mutably, which an
Iterator-returning shape could not while the shell is also borrowed.
Sourcefn keep_alive(&mut self)
fn keep_alive(&mut self)
Lets the window system run, and delivers nothing.
Everything pump does except hand events to a sink: the
platform’s queue is drained, whatever it asks of the client is answered,
and what it produced is kept in this shell’s queue, in order, for the
next pump. Every backend implements pump as this followed by the
delivery, so the two cannot drift apart.
§What it is for: a long load on the thread that owns the window
Desktops mark a client that stops draining its queue as hung. Windows
ghosts a window whose thread has not asked for a message for about five
seconds — IsHungAppWindow, a greyed “Not Responding” title, clicks
held — a Wayland compositor pings through xdg_wm_base and offers to
kill a client that does not answer (GNOME’s “not responding” dialog),
and macOS puts the spinning cursor over an application whose main thread
has stopped taking events. A game that loads its assets between opening
its window and its first frame calls this every so often — a few times a
second is plenty — and stays responsive to all three.
Nothing is dropped, which is why this is not pump with an empty
sink: a key pressed, a resize or a close request made during the load is
delivered by the first frame’s pump, exactly as if the load had been
one long frame. So a close request stays unanswered until then — the
window stays open and the load finishes first — and a loader that must
stop for one has to pump and handle events itself.
Work that can leave the loop thread should, instead: a loop that keeps running frames keeps pumping on its own, and can show progress while it does. This is for the load that cannot — work on the device the loop owns, or on anything else tied to this thread.
Non-blocking and finite, like pump, and with the same exception: on
Win32 and AppKit it does not return while the user is dragging the
window’s border.
Sourcefn surface_target(&self, window: WindowId) -> Result<SurfaceTarget, ShellError>
fn surface_target(&self, window: WindowId) -> Result<SurfaceTarget, ShellError>
The native handles a HAL backend needs to create a surface for this window.
Opaque to everyone except a HAL backend. Re-query it after a
set_mode: some backends recreate the underlying
surface on a mode switch, and a cached target then names a dead object.
A resize is not such an event — see below.
§Available before the window is configured, and unchanged by a resize
The handle exists as soon as the window does — a wl_surface is
created up front and only its size is pending — so this succeeds
immediately and a HAL surface can be created from it right away. Only
the swapchain has to wait, because only the swapchain needs an
extent.
No variant carries a size, so the value this returns does not change
when the window is resized, and a HAL surface created before the first
configure stays correct forever. That is what makes “re-query after a
mode change” a complete rule. SurfaceTarget::Offscreen used to carry
width/height and was the one exception; P0.7 removed it, because an
exception in this rule means a surface silently describing a size the
window no longer has. The extent reaches a backend through
WindowState::size and the swapchain descriptor, and only there —
crcbl-hal’s swapchain module states that precedence as a backend
obligation.
§Errors
ShellError::InvalidWindow if the handle is stale.
Sourcefn set_pointer_mode(
&mut self,
window: WindowId,
mode: PointerMode,
) -> Result<(), ShellError>
fn set_pointer_mode( &mut self, window: WindowId, mode: PointerMode, ) -> Result<(), ShellError>
Frees, confines or locks the pointer.
§Errors
ShellError::Unsupported if caps lacks
PointerMode::required_cap, or ShellError::InvalidWindow for a
stale handle.
Sourcefn set_cursor(
&mut self,
window: WindowId,
cursor: Option<CursorIcon>,
) -> Result<(), ShellError>
fn set_cursor( &mut self, window: WindowId, cursor: Option<CursorIcon>, ) -> Result<(), ShellError>
Sets the cursor shape, or hides the cursor with None.
Visibility and capture are separate axes; see cursor.
Hiding works on every backend. A shape is seen only where
ShellCaps::CURSOR_SHAPE is set; elsewhere it is accepted and
recorded rather than refused, because a UI calls this on every hover.
§Errors
ShellError::InvalidWindow if the handle is stale.
Sourcefn warp_pointer(
&mut self,
window: WindowId,
position: PhysicalPoint,
) -> Result<(), ShellError>
fn warp_pointer( &mut self, window: WindowId, position: PhysicalPoint, ) -> Result<(), ShellError>
Moves the pointer to a position in the window.
Requires ShellCaps::POINTER_WARP, which Wayland does not have and
will not get. Anything reaching for this to implement a camera should
use PointerMode::Locked instead; warping is for a UI that needs to
reposition a cursor (a slider snapping to a value), not for input.
§Errors
ShellError::Unsupported without the capability, or
ShellError::InvalidWindow for a stale handle.
Sourcefn reply_close_request(
&mut self,
window: WindowId,
reply: CloseReply,
) -> Result<(), ShellError>
fn reply_close_request( &mut self, window: WindowId, reply: CloseReply, ) -> Result<(), ShellError>
Answers a ShellEvent::CloseRequested.
Until this is called the window stays open and the request stays
outstanding. See CloseReply.
§Errors
ShellError::NoPendingCloseRequest if nothing was asked, or
ShellError::InvalidWindow for a stale handle.
Sourcefn clipboard_offer(
&mut self,
window: WindowId,
offers: &[ClipboardOffer<'_>],
) -> Result<(), ShellError>
fn clipboard_offer( &mut self, window: WindowId, offers: &[ClipboardOffer<'_>], ) -> Result<(), ShellError>
Publishes clipboard content in one or more formats.
Synchronous: every platform’s write is “claim the selection”, and the
bytes transfer later, on demand. Offer both MimeType::TextUtf8 and
MimeType::CrcblRon for engine data; see clipboard.
An empty offers slice releases the clipboard, where the platform can
express that.
§Errors
ShellError::Unsupported without ShellCaps::CLIPBOARD,
ShellError::InvalidWindow for a stale handle, or
ShellError::NeedsUserInteraction where the window system requires a
recent input event to claim the clipboard and there has not been one —
implementor obligation 6 above, and not a failure a caller should
retry blindly.
Sourcefn clipboard_request(
&mut self,
window: WindowId,
mime: MimeType,
) -> Result<ClipboardRequestId, ShellError>
fn clipboard_request( &mut self, window: WindowId, mime: MimeType, ) -> Result<ClipboardRequestId, ShellError>
Asks for the clipboard’s content in mime.
Asynchronous by necessity — the answer arrives as
ShellEvent::ClipboardData carrying the returned id, and exactly one
answer arrives for every Ok return (implementor obligations 4 and 5).
clipboard has the full argument; briefly, X11 INCR transfers,
Wayland file descriptors and the browser’s Promise make the synchronous
shape unimplementable on three of five backends.
The answer may be several frames away, and on a backend whose clipboard
is not readable at the moment of asking it is held until it is, rather
than being answered Empty. A caller
therefore never needs to poll or retry: ask once, handle the event.
clipboard_readable is the way to find out
in advance that the answer will not be immediate.
§Errors
ShellError::Unsupported without ShellCaps::CLIPBOARD, or
ShellError::InvalidWindow for a stale handle. An empty clipboard is
not an error — it is an answer.
Sourcefn request_frame(&mut self, window: WindowId) -> Result<(), ShellError>
fn request_frame(&mut self, window: WindowId) -> Result<(), ShellError>
Asks for a ShellEvent::FrameReady when window should present its
next frame.
For a loop that presents only when told to: a status bar on an output the compositor has turned off is never asked for a frame there, and a FIFO present to it can block the loop for as long as the output stays off. Ask before presenting the frame the answer paces, then present the next one once it comes. The first frame needs no answer.
let mut may_present = true;
for _ in 0..3 {
shell.pump(&mut |event| {
if let ShellEvent::FrameReady { window: ready } = event {
may_present |= ready == window;
}
});
if may_present {
shell.request_frame(window)?;
// … record and present …
may_present = false;
}
}
// With no compositor to hold it back, each answer came at the next pump.
assert_eq!(presented, 3);Requests made before the answer comes share it: one FrameReady
answers them all. A window destroyed with a request outstanding gets no
answer.
Where ShellCaps::FRAME_CALLBACK is set — Wayland, as
wl_surface.frame — the compositor answers. The request is surface
state that rides the next commit, which is the one the swapchain’s
present makes, and this call commits nothing itself, so a window that
asks and then never presents may never be answered. Everywhere else
the answer comes at the next pump, and
wait_events does not sleep while one is due.
A required method, unlike its neighbours: a default could validate the handle but not keep the request, and a request nothing answers stalls the loop waiting for it.
§Errors
ShellError::InvalidWindow if the handle is stale.
Provided Methods§
Sourcefn reposition_popup(
&mut self,
popup: WindowId,
anchor: LogicalRect,
size: LogicalSize,
) -> Result<(), ShellError>
fn reposition_popup( &mut self, popup: WindowId, anchor: LogicalRect, size: LogicalSize, ) -> Result<(), ShellError>
Moves a live popup against a new anchor in its parent and gives it
size, placed by the PopupPlacement it was created with: flipped
or slid to stay on screen, as when it opened.
For a popup whose anchor moved — a bar’s clock grew and its calendar
should follow — or whose content changed size. A request, like the
rest of a window’s geometry: the new size arrives as the next
ShellEvent::Resized, once the window system has placed it.
Requires ShellCaps::POPUP_REPOSITION. Without it, close the popup
and open another.
§Errors
ShellError::Unsupported without the capability,
ShellError::InvalidWindow for a stale handle, and
ShellError::InvalidDescriptor for a window that is not a popup.
Sourcefn set_panel(
&mut self,
window: WindowId,
size: LogicalSize,
panel: &PanelDesc<'_>,
) -> Result<(), ShellError>
fn set_panel( &mut self, window: WindowId, size: LogicalSize, panel: &PanelDesc<'_>, ) -> Result<(), ShellError>
Gives a live panel a new size and a new PanelDesc: its layer,
anchor, reserve, margins and keyboard change in place, with the same
surface and the same swapchain, where destroying it and creating
another would flicker.
size means what WindowDesc::size means for a panel: ignored along
an axis anchored to both opposite edges. The new descriptor is checked
as create_window checks one, so a reserving
panel must still name one edge. A request, like the rest of a window’s
geometry: the size the panel gets arrives as the next
ShellEvent::Resized, as its first one did, and none arrives when
the size did not change.
The namespace and the monitor cannot change. wlr-layer-shell
fixes both when the surface is made, and every backend refuses a
change to either alike; close the panel and open another for that.
A visible panel changed to PanelKeyboard::Exclusive takes the
keyboard at once on Wayland, where the compositor hands it over; on
Win32 and AppKit it takes it when it is next shown, as a new one does.
A provided method answering ShellError::Unsupported, as
create_window answers a panel on a backend
without ShellCaps::PANEL, once the handle has been checked; every
backend with panels implements it.
§Errors
ShellError::InvalidWindow for a stale handle,
ShellError::InvalidDescriptor for a window that is not a panel or a
descriptor that changes its namespace or its monitor, and whatever
create_window refuses a panel with:
ShellError::Unsupported for what the backend cannot build, and
ShellError::NoSuchMonitor if the panel’s monitor is gone.
Sourcefn monitor(&self, id: MonitorId) -> Option<&MonitorInfo>
fn monitor(&self, id: MonitorId) -> Option<&MonitorInfo>
One monitor by id, or None if it is not connected.
A provided method rather than a required one: it is a lookup over
monitors, and every backend would write the same
three lines.
Sourcefn wait_events(&mut self, timeout: Option<Duration>)
fn wait_events(&mut self, timeout: Option<Duration>)
Blocks until an event arrives or timeout elapses.
Advisory. Returning immediately is always correct, and backends
without ShellCaps::EVENT_WAIT — a browser above all — do exactly
that. A caller must treat this as “sleep if you can” and must not assume
an event is pending afterwards; pump is still what
delivers them.
timeout of None means “until something happens”, which on a backend
without the capability still means “immediately”.
Sourcefn waker(&mut self) -> Option<ShellWaker>
fn waker(&mut self) -> Option<ShellWaker>
A handle that wakes wait_events from another
thread — see ShellWaker.
Every call hands out a handle to the same doorbell, so a program can ask
once and clone, or ask wherever it needs one. None from a backend
whose wait never blocks, which is the browser: there, nothing sleeps and
there is nothing to wake.
Sourcefn align_event_clock(&mut self, elapsed: Duration)
fn align_event_clock(&mut self, elapsed: Duration)
Puts input timestamps on the engine’s clock.
Call this once, at startup, with the reading of the
TimeSource that will drive
FrameClock::update.
EventTime’s epoch is defined as “the same origin as” that source,
and no backend can know it: a shell is created some time after the
clock starts, and the window system’s own clock has a third origin
again. Without this call, timestamps are measured from the shell’s own
creation — internally consistent, so durations between two input events
are already correct, but offset from a
FrameClock reading by however long startup
took. That offset is exactly what docs/plan/26-prediction.md’s input-to-photon
latency measurement is a subtraction across.
A provided method with a no-op default, because it is only meaningful
for a backend whose event clock is not already the engine’s — the
browser’s event.timeStamp needs nothing done to it. The obligation it
discharges is the “Timestamps are rebased” one in this trait’s
implementor notes, which previously had no way to be satisfied
from outside the crate.
let mut shell = HeadlessShell::new();
// The engine clock has been running for 40 ms by the time the window
// system is up; input stamped "now" should read as 40 ms, not as zero.
shell.align_event_clock(Duration::from_millis(40));Sourcefn clipboard_readable(&self, window: WindowId) -> bool
fn clipboard_readable(&self, window: WindowId) -> bool
Whether a clipboard_request issued for
window right now could be answered without waiting.
What a “Paste” menu item greys out on, and the visible form of a
platform rule that is otherwise invisible: on Wayland a client is told
what is on the clipboard only while one of its windows has keyboard
focus, and only asynchronously, so a background window genuinely
cannot read the clipboard. clipboard_request still works there — it
holds the request — but it may take until focus arrives, and a UI that
would rather not offer the action than offer a slow one asks here first.
false for a stale handle, and for a backend without
ShellCaps::CLIPBOARD.
§A provided method, because most platforms have nothing to say
The default is “readable whenever the capability is present and the
handle is live”, which is exactly right for X11 (any window may
ConvertSelection at any time, focus is not involved), for Win32, and
for HeadlessShell in its default configuration. Only a backend that
really has a gate overrides it — so this is a fact a consumer can rely
on, not ceremony every backend has to perform.
The staleness half goes through
window_state rather than being left to each
implementation. P0.6 found the earlier default — which ignored window
entirely — contradicting the “false for a stale handle” sentence
above: both backends that existed had overridden it and so had
covered for it, and the first backend to accept the default inherited
the bug. A default that cannot keep its own promise is worse than no
default.
Sourcefn activation_token(
&mut self,
window: WindowId,
) -> Result<Option<String>, ShellError>
fn activation_token( &mut self, window: WindowId, ) -> Result<Option<String>, ShellError>
A token another program can raise its own window with, made from
window and the latest input this program received.
What a notification daemon sends as the notification spec’s
ActivationToken before ActionInvoked, and what a launcher puts in a
child’s XDG_ACTIVATION_TOKEN: the receiver hands it back to its window
system, which raises the window if it accepts the token. Ask for it in
answer to the click that warrants it, since the window system judges a
token by the input it was made from.
Ok(None) where the window system has no such thing: Wayland without
xdg-activation-v1, and every other backend, whose default this is.
Wayland waits for the compositor’s answer, a round trip or more.
§Errors
ShellError::InvalidWindow for a stale handle, or
ShellError::Backend where the window system has the mechanism but
gave no token.
Sourcefn set_text_input_area(
&mut self,
window: WindowId,
area: Option<PhysicalRect>,
) -> Result<(), ShellError>
fn set_text_input_area( &mut self, window: WindowId, area: Option<PhysicalRect>, ) -> Result<(), ShellError>
Tells the input method where text is being entered, so it can put its composition window and candidate list there instead of at a corner of the screen.
area is the text field’s caret, or the line it sits on, in the
window’s client device pixels; the candidate list opens beside it
without covering it. None hands placement back to the input method’s
default. Call it when a field gains focus and whenever its caret moves.
A hint: the input method may place its windows elsewhere, and nothing
reports where they went.
§A provided method, and a no-op where there is nothing to place
Only a backend with an input method that draws its own windows has
anything to do here — Win32’s IMM and TSF, a Wayland compositor’s
text-input-v3 cursor rectangle, AppKit’s firstRectForCharacterRange:.
The default validates the handle and does nothing else, which is exactly
right for the rest. Win32, Wayland and AppKit override it. Wayland
sends the area only while set_text_input
names a field, since text-input-v3 has nowhere to put it otherwise;
AppKit answers firstRectForCharacterRange: with it whenever asked.
§Errors
ShellError::InvalidWindow if the handle is stale.
Sourcefn set_input_region(
&mut self,
window: WindowId,
region: Option<&[PhysicalRect]>,
) -> Result<(), ShellError>
fn set_input_region( &mut self, window: WindowId, region: Option<&[PhysicalRect]>, ) -> Result<(), ShellError>
Limits where window takes the pointer to a union of rectangles, so
the pointer anywhere else goes to whatever is behind the window.
For a transparent window that draws a shape smaller than itself: a launcher’s rounded panel, whose transparent corners should let a click through to the program beneath. A pixel of alpha zero is otherwise the window’s on every desktop backend; nothing hit-tests by alpha, because that would read the frame back from the GPU on every pointer move.
region is in the window’s client device pixels, the units of
set_text_input_area. Empty rectangles
are ignored, and parts outside the window take nothing; an empty slice
leaves the window no pointer input at all. None gives the whole window
back, which is where every window starts. Keyboard focus is not
affected. The rectangles are the caller’s layout, so send them again
after a ShellEvent::Resized or ShellEvent::ScaleFactorChanged
that moves the shape. PhysicalRect::rounded builds them for a
rounded rectangle.
Give the outer bound of what the window draws, antialiased edge included. On Win32 the region is a window region, which also clips the window’s drawing to it, so a region inside the edge’s blend cuts the edge off. Elsewhere a tighter region only loses the pointer over the edge.
A Passthrough popup stays passthrough: a
region given to it is validated and has no effect.
§A provided method
The default validates the handle and does nothing else, which leaves
the whole window taking the pointer. Wayland, X11 and Win32 override it,
and ShellCaps::INPUT_REGION is set only where it is acted on; a
caller that must have the click-through checks the bit rather than the
platform.
§Errors
ShellError::InvalidWindow if the handle is stale.
Sourcefn set_idle_inhibit(
&mut self,
window: WindowId,
inhibit: bool,
) -> Result<(), ShellError>
fn set_idle_inhibit( &mut self, window: WindowId, inhibit: bool, ) -> Result<(), ShellError>
Keeps the display on and the screensaver from starting while window
asks: true to ask, false to stop.
For a game played on a gamepad, or a cutscene, which nothing the system counts as user activity interrupts. Ask while the game is being played and stop in the menus, as a video player stops at pause; asking for the whole session keeps a desktop awake that its user walked away from.
Per window, because Wayland’s zwp_idle_inhibit_manager_v1 inhibits
per surface, and its compositor honours that only while the surface is
shown; Win32 keeps the display on whether or not the window is. The
display is kept on while any window of the shell asks. Asking twice
is asking once, and stopping a window that never asked does nothing.
Destroying a window ends its request, and dropping the shell ends them
all.
§A provided method
The default validates the handle and answers
ShellError::Unsupported, since a request nothing acts on would let
the display sleep while the caller thinks otherwise.
ShellCaps::IDLE_INHIBIT is set only where it is acted on, and says
which backends that is.
§Errors
ShellError::InvalidWindow if the handle is stale,
ShellError::Unsupported without ShellCaps::IDLE_INHIBIT, and
ShellError::Backend if the system refused.
Sourcefn open_url(&mut self, window: WindowId, url: &WebUrl) -> Result<(), ShellError>
fn open_url(&mut self, window: WindowId, url: &WebUrl) -> Result<(), ShellError>
Opens url in the user’s web browser, for a store page, a community
link, or the end-user licence and privacy policy.
Only a WebUrl is taken: an absolute http or https URL, checked
by WebUrl::parse before any backend sees it. The system’s own
“open” would also run a program, open a file with whatever is
associated with it, or start any registered protocol handler, and a
game passing on a link a server sent it must never reach any of that;
see the url module.
window owns whatever the system shows while it opens the browser,
such as Win32’s message box when no browser is registered, as Wayland’s
org.freedesktop.portal.OpenURI takes a parent window. Whether the
browser opened the page is not reported back: success means the system
accepted the request. Leave the browser’s window to come forward on its
own; a fullscreen game may want to leave fullscreen first.
§A provided method
The default validates the handle and answers
ShellError::Unsupported, since a link that silently does nothing
leaves the player clicking it again. ShellCaps::OPEN_URL is set
only where it is acted on, and says which backends that is.
§Errors
ShellError::InvalidWindow if the handle is stale,
ShellError::Unsupported without ShellCaps::OPEN_URL, and
ShellError::Backend if the system refused.
Sourcefn set_text_input(
&mut self,
window: WindowId,
field: Option<TextPurpose>,
) -> Result<(), ShellError>
fn set_text_input( &mut self, window: WindowId, field: Option<TextPurpose>, ) -> Result<(), ShellError>
Tells the input method what text field in window is taking typing:
Some(purpose) as a field gains the keyboard focus, None as it loses
it.
While a field is taking typing, a platform input method composes what
is typed in the window, reporting the composition as
TextPreedit and the result as
TextCommit. While none is, the input method
keeps out of the way and keys reach the window as keys: one in its
native mode would otherwise turn a game’s WASD into a candidate list. A
window starts with none.
The TextPurpose says what the field is for. A password or a PIN is
sensitive: nothing typed into it may be
learned, stored or suggested back.
§A provided method
The default validates the handle and does nothing else. Wayland acts on
it with text-input-v3’s enable, set_content_type and disable;
Win32 associates the window’s input context only for a
Normal field, keeping it off for a password or
a PIN as a Windows password box does. AppKit draws the same line by
holding the view’s input context to the keyboard layouts for no field
and for a sensitive one, and also holds secure event input while a
password or PIN field’s window has the keyboard.
ShellCaps::TEXT_IME is set only where this is acted on.
§Errors
ShellError::InvalidWindow if the handle is stale.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".