iced/
daemon.rs

1//! Create and run daemons that run in the background.
2use crate::application;
3use crate::program::{self, Program};
4#[cfg(feature = "winit")]
5pub use crate::shell::program::{Appearance, DefaultStyle};
6use crate::window;
7use crate::{Element, Executor, Font, Settings, Subscription, Task};
8
9#[cfg(not(feature = "winit"))]
10use crate::runtime::{Appearance, DefaultStyle};
11
12use std::borrow::Cow;
13
14/// Creates an iced [`Daemon`] given its title, update, and view logic.
15///
16/// A [`Daemon`] will not open a window by default, but will run silently
17/// instead until a [`Task`] from [`window::open`] is returned by its update logic.
18///
19/// Furthermore, a [`Daemon`] will not stop running when all its windows are closed.
20/// In order to completely terminate a [`Daemon`], its process must be interrupted or
21/// its update logic must produce a [`Task`] from [`exit`].
22///
23/// [`exit`]: crate::exit
24pub fn daemon<State, Message, Theme, Renderer>(
25    title: impl Title<State>,
26    update: impl application::Update<State, Message>,
27    view: impl for<'a> self::View<'a, State, Message, Theme, Renderer>,
28) -> Daemon<impl Program<State = State, Message = Message, Theme = Theme>>
29where
30    State: 'static,
31    Message: Send + std::fmt::Debug + 'static,
32    Theme: Default + DefaultStyle,
33    Renderer: program::Renderer,
34{
35    use std::marker::PhantomData;
36
37    struct Instance<State, Message, Theme, Renderer, Update, View> {
38        update: Update,
39        view: View,
40        _state: PhantomData<State>,
41        _message: PhantomData<Message>,
42        _theme: PhantomData<Theme>,
43        _renderer: PhantomData<Renderer>,
44    }
45
46    impl<State, Message, Theme, Renderer, Update, View> Program
47        for Instance<State, Message, Theme, Renderer, Update, View>
48    where
49        Message: Send + std::fmt::Debug + 'static,
50        Theme: Default + DefaultStyle,
51        Renderer: program::Renderer,
52        Update: application::Update<State, Message>,
53        View: for<'a> self::View<'a, State, Message, Theme, Renderer>,
54    {
55        type State = State;
56        type Message = Message;
57        type Theme = Theme;
58        type Renderer = Renderer;
59        type Executor = iced_futures::backend::default::Executor;
60
61        fn update(
62            &self,
63            state: &mut Self::State,
64            message: Self::Message,
65        ) -> Task<Self::Message> {
66            self.update.update(state, message).into()
67        }
68
69        fn view<'a>(
70            &self,
71            state: &'a Self::State,
72            window: window::Id,
73        ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
74            self.view.view(state, window).into()
75        }
76    }
77
78    Daemon {
79        raw: Instance {
80            update,
81            view,
82            _state: PhantomData,
83            _message: PhantomData,
84            _theme: PhantomData,
85            _renderer: PhantomData,
86        },
87        settings: Settings::default(),
88    }
89    .title(title)
90}
91
92/// The underlying definition and configuration of an iced daemon.
93///
94/// You can use this API to create and run iced applications
95/// step by step—without coupling your logic to a trait
96/// or a specific type.
97///
98/// You can create a [`Daemon`] with the [`daemon`] helper.
99#[derive(Debug)]
100pub struct Daemon<P: Program> {
101    raw: P,
102    settings: Settings,
103}
104
105impl<P: Program> Daemon<P> {
106    #[cfg(feature = "winit")]
107    /// Runs the [`Daemon`].
108    ///
109    /// The state of the [`Daemon`] must implement [`Default`].
110    /// If your state does not implement [`Default`], use [`run_with`]
111    /// instead.
112    ///
113    /// [`run_with`]: Self::run_with
114    pub fn run(self) -> crate::Result
115    where
116        Self: 'static,
117        P::State: Default,
118    {
119        self.raw.run(self.settings, None)
120    }
121
122    #[cfg(feature = "winit")]
123    /// Runs the [`Daemon`] with a closure that creates the initial state.
124    pub fn run_with<I>(self, initialize: I) -> crate::Result
125    where
126        Self: 'static,
127        I: FnOnce() -> (P::State, Task<P::Message>) + 'static,
128    {
129        self.raw.run_with(self.settings, None, initialize)
130    }
131
132    /// Sets the [`Settings`] that will be used to run the [`Daemon`].
133    pub fn settings(self, settings: Settings) -> Self {
134        Self { settings, ..self }
135    }
136
137    /// Sets the [`Settings::antialiasing`] of the [`Daemon`].
138    pub fn antialiasing(self, antialiasing: bool) -> Self {
139        Self {
140            settings: Settings {
141                antialiasing,
142                ..self.settings
143            },
144            ..self
145        }
146    }
147
148    /// Sets the default [`Font`] of the [`Daemon`].
149    pub fn default_font(self, default_font: Font) -> Self {
150        Self {
151            settings: Settings {
152                default_font,
153                ..self.settings
154            },
155            ..self
156        }
157    }
158
159    /// Adds a font to the list of fonts that will be loaded at the start of the [`Daemon`].
160    pub fn font(mut self, font: impl Into<Cow<'static, [u8]>>) -> Self {
161        self.settings.fonts.push(font.into());
162        self
163    }
164
165    /// Sets the [`Title`] of the [`Daemon`].
166    pub(crate) fn title(
167        self,
168        title: impl Title<P::State>,
169    ) -> Daemon<
170        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
171    > {
172        Daemon {
173            raw: program::with_title(self.raw, move |state, window| {
174                title.title(state, window)
175            }),
176            settings: self.settings,
177        }
178    }
179
180    /// Sets the subscription logic of the [`Daemon`].
181    pub fn subscription(
182        self,
183        f: impl Fn(&P::State) -> Subscription<P::Message>,
184    ) -> Daemon<
185        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
186    > {
187        Daemon {
188            raw: program::with_subscription(self.raw, f),
189            settings: self.settings,
190        }
191    }
192
193    /// Sets the theme logic of the [`Daemon`].
194    pub fn theme(
195        self,
196        f: impl Fn(&P::State, window::Id) -> P::Theme,
197    ) -> Daemon<
198        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
199    > {
200        Daemon {
201            raw: program::with_theme(self.raw, f),
202            settings: self.settings,
203        }
204    }
205
206    /// Sets the style logic of the [`Daemon`].
207    pub fn style(
208        self,
209        f: impl Fn(&P::State, &P::Theme) -> Appearance,
210    ) -> Daemon<
211        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
212    > {
213        Daemon {
214            raw: program::with_style(self.raw, f),
215            settings: self.settings,
216        }
217    }
218
219    /// Sets the scale factor of the [`Daemon`].
220    pub fn scale_factor(
221        self,
222        f: impl Fn(&P::State, window::Id) -> f64,
223    ) -> Daemon<
224        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
225    > {
226        Daemon {
227            raw: program::with_scale_factor(self.raw, f),
228            settings: self.settings,
229        }
230    }
231
232    /// Sets the executor of the [`Daemon`].
233    pub fn executor<E>(
234        self,
235    ) -> Daemon<
236        impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
237    >
238    where
239        E: Executor,
240    {
241        Daemon {
242            raw: program::with_executor::<P, E>(self.raw),
243            settings: self.settings,
244        }
245    }
246}
247
248/// The title logic of some [`Daemon`].
249///
250/// This trait is implemented both for `&static str` and
251/// any closure `Fn(&State, window::Id) -> String`.
252///
253/// This trait allows the [`daemon`] builder to take any of them.
254pub trait Title<State> {
255    /// Produces the title of the [`Daemon`].
256    fn title(&self, state: &State, window: window::Id) -> String;
257}
258
259impl<State> Title<State> for &'static str {
260    fn title(&self, _state: &State, _window: window::Id) -> String {
261        self.to_string()
262    }
263}
264
265impl<T, State> Title<State> for T
266where
267    T: Fn(&State, window::Id) -> String,
268{
269    fn title(&self, state: &State, window: window::Id) -> String {
270        self(state, window)
271    }
272}
273
274/// The view logic of some [`Daemon`].
275///
276/// This trait allows the [`daemon`] builder to take any closure that
277/// returns any `Into<Element<'_, Message>>`.
278pub trait View<'a, State, Message, Theme, Renderer> {
279    /// Produces the widget of the [`Daemon`].
280    fn view(
281        &self,
282        state: &'a State,
283        window: window::Id,
284    ) -> impl Into<Element<'a, Message, Theme, Renderer>>;
285}
286
287impl<'a, T, State, Message, Theme, Renderer, Widget>
288    View<'a, State, Message, Theme, Renderer> for T
289where
290    T: Fn(&'a State, window::Id) -> Widget,
291    State: 'static,
292    Widget: Into<Element<'a, Message, Theme, Renderer>>,
293{
294    fn view(
295        &self,
296        state: &'a State,
297        window: window::Id,
298    ) -> impl Into<Element<'a, Message, Theme, Renderer>> {
299        self(state, window)
300    }
301}