The daemon function provides a high-level way to create a program by passing it the core application logic. It manages the lifecycle of the application and integrates with the Wayland shell.
To use daemon, you provide:
- A factory function to create your application state.
- A
namespace function. - An
update function. - A
view function.
You can then chain configuration methods like .title(), .subscription(), .on_new_shell(), and .settings() before calling .run().
Monitoring Shell Surfaces
There are two primary ways to react to shell surfaces (windows/layers) created by the runtime:
on_new_shell (Synchronous): This hook runs synchronously before a surface's first frame is rendered. This is critical for use cases like session locks, where the initial frame must be correct to prevent flickering or security bypasses.Settings::shell_broadcast (Asynchronous): This is the asynchronous counterpart. You pass the sending end of iced_wayland_subscriber::shell::channel() to the Settings object, and keep the receiving end (ShellReceiver) in your application state. You can then use this receiver in your subscription to listen for surface and monitor changes as they happen.
Example Usage
use iced_exwlshell::daemon;
use iced_exwlshell::settings::{Settings, LayerShellSettings};
use iced_wayland_subscriber::shell::{ShellReceiver, ShellEvent};
// ... inside main or setup ...
// 1. Create the channel
let (shell_broadcast, shell_events) = iced_wayland_subscriber::shell::channel();
// 2. Initialize daemon
daemon(
move || MyCounter::new("hello", shell_events.clone()),
MyCounter::namespace,
MyCounter::update,
MyCounter::view,
)
.on_new_shell(|info: ShellInfo| {
// Handle synchronous events like session locks
matches!(info.shell, ShellType::SessionLock).then(|| Message::LockAppeared(info.window))
})
.settings(Settings {
shell_broadcast,
// ... other settings
..Default::default()
})
.run()
use iced_exwlshell::daemon;
use iced_exwlshell::settings::{Settings, LayerShellSettings};
use iced_wayland_subscriber::shell::{ShellReceiver, ShellEvent};
// The runtime gets the sending end, the application keeps the receiving one.
let (shell_broadcast, shell_events) = iced_wayland_subscriber::shell::channel();
daemon(
move || Counter::new("hello", shell_events.clone()),
Counter::namespace,
Counter::update,
Counter::view,
)
.title(Counter::title)
.subscription(Counter::subscription)
.on_new_shell(|info: ShellInfo| {
matches!(info.shell, ShellType::SessionLock).then(|| Message::LockAppeared(info.window))
})
.settings(Settings {
layer_settings: LayerShellSettings {
size: LayerSize::fill_width(400),
exclusive_zone: 400,
anchor: Anchor::Bottom | Anchor::Left | Anchor::Right,
start_mode: StartMode::AllScreens,
..Default::default()
},
with_connection: Some(connection.into()),
shell_broadcast,
..Default::default()
})
.run()