Skip to main content

iced_runtime/
window.rs

1//! Build window-based GUI applications.
2use crate::core::time::Instant;
3use crate::core::window::{
4    Direction, Event, Icon, Id, Level, Mode, Screenshot, Settings, UserAttention,
5};
6use crate::core::{Point, Size, Window};
7use crate::futures::Subscription;
8use crate::futures::event;
9use crate::futures::futures::channel::oneshot;
10use crate::task::{self, Task};
11
12/// An operation to be performed on some window.
13pub enum Action {
14    /// Open a new window with some [`Settings`].
15    Open(Id, Settings, oneshot::Sender<Id>),
16
17    /// Close the window and exits the application.
18    Close(Id),
19
20    /// Gets the [`Id`] of the oldest window.
21    GetOldest(oneshot::Sender<Option<Id>>),
22
23    /// Gets the [`Id`] of the latest window.
24    GetLatest(oneshot::Sender<Option<Id>>),
25
26    /// Move the window with the left mouse button until the button is
27    /// released.
28    ///
29    /// There's no guarantee that this will work unless the left mouse
30    /// button was pressed immediately before this function is called.
31    Drag(Id),
32
33    /// Resize the window with the left mouse button until the button is
34    /// released.
35    ///
36    /// There's no guarantee that this will work unless the left mouse
37    /// button was pressed immediately before this function is called.
38    DragResize(Id, Direction),
39
40    /// Resize the window to the given logical dimensions.
41    Resize(Id, Size),
42
43    /// Get the current logical dimensions of the window.
44    GetSize(Id, oneshot::Sender<Size>),
45
46    /// Get if the current window is maximized or not.
47    GetMaximized(Id, oneshot::Sender<bool>),
48
49    /// Set the window to maximized or back
50    Maximize(Id, bool),
51
52    /// Get if the current window is minimized or not.
53    ///
54    /// ## Platform-specific
55    /// - **Wayland:** Always `None`.
56    GetMinimized(Id, oneshot::Sender<Option<bool>>),
57
58    /// Set the window to minimized or back
59    Minimize(Id, bool),
60
61    /// Get the current logical coordinates of the window.
62    GetPosition(Id, oneshot::Sender<Option<Point>>),
63
64    /// Get the current scale factor (DPI) of the window.
65    GetScaleFactor(Id, oneshot::Sender<f32>),
66
67    /// Move the window to the given logical coordinates.
68    ///
69    /// Unsupported on Wayland.
70    Move(Id, Point),
71
72    /// Change the [`Mode`] of the window.
73    SetMode(Id, Mode),
74
75    /// Get the current [`Mode`] of the window.
76    GetMode(Id, oneshot::Sender<Mode>),
77
78    /// Toggle the window to maximized or back
79    ToggleMaximize(Id),
80
81    /// Toggle whether window has decorations.
82    ///
83    /// ## Platform-specific
84    /// - **X11:** Not implemented.
85    /// - **Web:** Unsupported.
86    ToggleDecorations(Id),
87
88    /// Request user attention to the window, this has no effect if the application
89    /// is already focused. How requesting for user attention manifests is platform dependent,
90    /// see [`UserAttention`] for details.
91    ///
92    /// Providing `None` will unset the request for user attention. Unsetting the request for
93    /// user attention might not be done automatically by the WM when the window receives input.
94    ///
95    /// ## Platform-specific
96    ///
97    /// - **iOS / Android / Web:** Unsupported.
98    /// - **macOS:** `None` has no effect.
99    /// - **X11:** Requests for user attention must be manually cleared.
100    /// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.
101    RequestUserAttention(Id, Option<UserAttention>),
102
103    /// Bring the window to the front and sets input focus. Has no effect if the window is
104    /// already in focus, minimized, or not visible.
105    ///
106    /// This method steals input focus from other applications. Do not use this method unless
107    /// you are certain that's what the user wants. Focus stealing can cause an extremely disruptive
108    /// user experience.
109    ///
110    /// ## Platform-specific
111    ///
112    /// - **Web / Wayland:** Unsupported.
113    GainFocus(Id),
114
115    /// Change the window [`Level`].
116    SetLevel(Id, Level),
117
118    /// Show the system menu at cursor position.
119    ///
120    /// ## Platform-specific
121    /// Android / iOS / macOS / Orbital / Web / X11: Unsupported.
122    ShowSystemMenu(Id),
123
124    /// Get the raw identifier unique to the window.
125    GetRawId(Id, oneshot::Sender<u64>),
126
127    /// Change the window [`Icon`].
128    ///
129    /// On Windows and X11, this is typically the small icon in the top-left
130    /// corner of the titlebar.
131    ///
132    /// ## Platform-specific
133    ///
134    /// - **Web / Wayland / macOS:** Unsupported.
135    ///
136    /// - **Windows:** Sets `ICON_SMALL`. The base size for a window icon is 16x16, but it's
137    ///   recommended to account for screen scaling and pick a multiple of that, i.e. 32x32.
138    ///
139    /// - **X11:** Has no universal guidelines for icon sizes, so you're at the whims of the WM. That
140    ///   said, it's usually in the same ballpark as on Windows.
141    SetIcon(Id, Icon),
142
143    /// Runs the closure with a reference to the [`Window`] with the given [`Id`].
144    Run(Id, Box<dyn FnOnce(&dyn Window) + Send>),
145
146    /// Screenshot the viewport of the window.
147    Screenshot(Id, oneshot::Sender<Screenshot>),
148
149    /// Enable mouse passthrough for the given window.
150    ///
151    /// This disables mouse events for the window and passes mouse events
152    /// through to whatever window is underneath.
153    EnableMousePassthrough(Id),
154
155    /// Disable mouse passthrough for the given window.
156    ///
157    /// This enables mouse events for the window and stops mouse events
158    /// from being passed to whatever is underneath.
159    DisableMousePassthrough(Id),
160
161    /// Set the minimum inner window size.
162    SetMinSize(Id, Option<Size>),
163
164    /// Set the maximum inner window size.
165    SetMaxSize(Id, Option<Size>),
166
167    /// Set the window to be resizable or not.
168    SetResizable(Id, bool),
169
170    /// Set the window size increment.
171    SetResizeIncrements(Id, Option<Size>),
172
173    /// Get the logical dimensions of the monitor containing the window with the given [`Id`].
174    GetMonitorSize(Id, oneshot::Sender<Option<Size>>),
175
176    /// Set whether the system can automatically organize windows into tabs.
177    ///
178    /// See <https://developer.apple.com/documentation/appkit/nswindow/1646657-allowsautomaticwindowtabbing>
179    SetAllowAutomaticTabbing(bool),
180
181    /// Redraw all the windows.
182    RedrawAll,
183
184    /// Recompute the layouts of all the windows.
185    RelayoutAll,
186}
187
188/// Subscribes to the frames of the window of the running application.
189///
190/// The resulting [`Subscription`] will produce items at a rate equal to the
191/// refresh rate of the first application window. Note that this rate may be variable, as it is
192/// normally managed by the graphics driver and/or the OS.
193///
194/// In any case, this [`Subscription`] is useful to smoothly draw application-driven
195/// animations without missing any frames.
196pub fn frames() -> Subscription<Instant> {
197    event::listen_raw(|event, _status, _window| match event {
198        crate::core::Event::Window(Event::RedrawRequested(at)) => Some(at),
199        _ => None,
200    })
201}
202
203/// Subscribes to all window events of the running application.
204pub fn events() -> Subscription<(Id, Event)> {
205    event::listen_with(|event, _status, id| {
206        if let crate::core::Event::Window(event) = event {
207            Some((id, event))
208        } else {
209            None
210        }
211    })
212}
213
214/// Subscribes to all [`Event::Opened`] occurrences in the running application.
215pub fn open_events() -> Subscription<Id> {
216    event::listen_with(|event, _status, id| {
217        if let crate::core::Event::Window(Event::Opened { .. }) = event {
218            Some(id)
219        } else {
220            None
221        }
222    })
223}
224
225/// Subscribes to all [`Event::Closed`] occurrences in the running application.
226pub fn close_events() -> Subscription<Id> {
227    event::listen_with(|event, _status, id| {
228        if let crate::core::Event::Window(Event::Closed) = event {
229            Some(id)
230        } else {
231            None
232        }
233    })
234}
235
236/// Subscribes to all [`Event::Resized`] occurrences in the running application.
237pub fn resize_events() -> Subscription<(Id, Size)> {
238    event::listen_with(|event, _status, id| {
239        if let crate::core::Event::Window(Event::Resized(size)) = event {
240            Some((id, size))
241        } else {
242            None
243        }
244    })
245}
246
247/// Subscribes to all [`Event::CloseRequested`] occurrences in the running application.
248pub fn close_requests() -> Subscription<Id> {
249    event::listen_with(|event, _status, id| {
250        if let crate::core::Event::Window(Event::CloseRequested) = event {
251            Some(id)
252        } else {
253            None
254        }
255    })
256}
257
258/// Opens a new window with the given [`Settings`]; producing the [`Id`]
259/// of the new window on completion.
260pub fn open(settings: Settings) -> (Id, Task<Id>) {
261    let id = Id::unique();
262
263    (
264        id,
265        task::oneshot(|channel| crate::Action::Window(Action::Open(id, settings, channel))),
266    )
267}
268
269/// Closes the window with `id`.
270pub fn close<T>(id: Id) -> Task<T> {
271    task::effect(crate::Action::Window(Action::Close(id)))
272}
273
274/// Gets the window [`Id`] of the oldest window.
275pub fn oldest() -> Task<Option<Id>> {
276    task::oneshot(|channel| crate::Action::Window(Action::GetOldest(channel)))
277}
278
279/// Gets the window [`Id`] of the latest window.
280pub fn latest() -> Task<Option<Id>> {
281    task::oneshot(|channel| crate::Action::Window(Action::GetLatest(channel)))
282}
283
284/// Begins dragging the window while the left mouse button is held.
285pub fn drag<T>(id: Id) -> Task<T> {
286    task::effect(crate::Action::Window(Action::Drag(id)))
287}
288
289/// Begins resizing the window while the left mouse button is held.
290pub fn drag_resize<T>(id: Id, direction: Direction) -> Task<T> {
291    task::effect(crate::Action::Window(Action::DragResize(id, direction)))
292}
293
294/// Resizes the window to the given logical dimensions.
295pub fn resize<T>(id: Id, new_size: Size) -> Task<T> {
296    task::effect(crate::Action::Window(Action::Resize(id, new_size)))
297}
298
299/// Set the window to be resizable or not.
300pub fn set_resizable<T>(id: Id, resizable: bool) -> Task<T> {
301    task::effect(crate::Action::Window(Action::SetResizable(id, resizable)))
302}
303
304/// Set the inner maximum size of the window.
305pub fn set_max_size<T>(id: Id, size: Option<Size>) -> Task<T> {
306    task::effect(crate::Action::Window(Action::SetMaxSize(id, size)))
307}
308
309/// Set the inner minimum size of the window.
310pub fn set_min_size<T>(id: Id, size: Option<Size>) -> Task<T> {
311    task::effect(crate::Action::Window(Action::SetMinSize(id, size)))
312}
313
314/// Set the window size increment.
315///
316/// This is usually used by apps such as terminal emulators that need "blocky" resizing.
317pub fn set_resize_increments<T>(id: Id, increments: Option<Size>) -> Task<T> {
318    task::effect(crate::Action::Window(Action::SetResizeIncrements(
319        id, increments,
320    )))
321}
322
323/// Gets the window size in logical dimensions.
324pub fn size(id: Id) -> Task<Size> {
325    task::oneshot(move |channel| crate::Action::Window(Action::GetSize(id, channel)))
326}
327
328/// Gets the maximized state of the window with the given [`Id`].
329pub fn is_maximized(id: Id) -> Task<bool> {
330    task::oneshot(move |channel| crate::Action::Window(Action::GetMaximized(id, channel)))
331}
332
333/// Maximizes the window.
334pub fn maximize<T>(id: Id, maximized: bool) -> Task<T> {
335    task::effect(crate::Action::Window(Action::Maximize(id, maximized)))
336}
337
338/// Gets the minimized state of the window with the given [`Id`].
339pub fn is_minimized(id: Id) -> Task<Option<bool>> {
340    task::oneshot(move |channel| crate::Action::Window(Action::GetMinimized(id, channel)))
341}
342
343/// Minimizes the window.
344pub fn minimize<T>(id: Id, minimized: bool) -> Task<T> {
345    task::effect(crate::Action::Window(Action::Minimize(id, minimized)))
346}
347
348/// Gets the position in logical coordinates of the window with the given [`Id`].
349pub fn position(id: Id) -> Task<Option<Point>> {
350    task::oneshot(move |channel| crate::Action::Window(Action::GetPosition(id, channel)))
351}
352
353/// Gets the scale factor of the window with the given [`Id`].
354pub fn scale_factor(id: Id) -> Task<f32> {
355    task::oneshot(move |channel| crate::Action::Window(Action::GetScaleFactor(id, channel)))
356}
357
358/// Moves the window to the given logical coordinates.
359pub fn move_to<T>(id: Id, position: Point) -> Task<T> {
360    task::effect(crate::Action::Window(Action::Move(id, position)))
361}
362
363/// Gets the current [`Mode`] of the window.
364pub fn mode(id: Id) -> Task<Mode> {
365    task::oneshot(move |channel| crate::Action::Window(Action::GetMode(id, channel)))
366}
367
368/// Changes the [`Mode`] of the window.
369pub fn set_mode<T>(id: Id, mode: Mode) -> Task<T> {
370    task::effect(crate::Action::Window(Action::SetMode(id, mode)))
371}
372
373/// Toggles the window to maximized or back.
374pub fn toggle_maximize<T>(id: Id) -> Task<T> {
375    task::effect(crate::Action::Window(Action::ToggleMaximize(id)))
376}
377
378/// Toggles the window decorations.
379pub fn toggle_decorations<T>(id: Id) -> Task<T> {
380    task::effect(crate::Action::Window(Action::ToggleDecorations(id)))
381}
382
383/// Requests user attention to the window. This has no effect if the application
384/// is already focused. How requesting for user attention manifests is platform dependent,
385/// see [`UserAttention`] for details.
386///
387/// Providing `None` will unset the request for user attention. Unsetting the request for
388/// user attention might not be done automatically by the WM when the window receives input.
389pub fn request_user_attention<T>(id: Id, user_attention: Option<UserAttention>) -> Task<T> {
390    task::effect(crate::Action::Window(Action::RequestUserAttention(
391        id,
392        user_attention,
393    )))
394}
395
396/// Brings the window to the front and sets input focus. Has no effect if the window is
397/// already in focus, minimized, or not visible.
398///
399/// This [`Task`] steals input focus from other applications. Do not use this method unless
400/// you are certain that's what the user wants. Focus stealing can cause an extremely disruptive
401/// user experience.
402pub fn gain_focus<T>(id: Id) -> Task<T> {
403    task::effect(crate::Action::Window(Action::GainFocus(id)))
404}
405
406/// Changes the window [`Level`].
407pub fn set_level<T>(id: Id, level: Level) -> Task<T> {
408    task::effect(crate::Action::Window(Action::SetLevel(id, level)))
409}
410
411/// Shows the [system menu] at cursor position.
412///
413/// [system menu]: https://en.wikipedia.org/wiki/Common_menus_in_Microsoft_Windows#System_menu
414pub fn show_system_menu<T>(id: Id) -> Task<T> {
415    task::effect(crate::Action::Window(Action::ShowSystemMenu(id)))
416}
417
418/// Gets an identifier unique to the window, provided by the underlying windowing system. This is
419/// not to be confused with [`Id`].
420pub fn raw_id<Message>(id: Id) -> Task<u64> {
421    task::oneshot(|channel| crate::Action::Window(Action::GetRawId(id, channel)))
422}
423
424/// Changes the [`Icon`] of the window.
425pub fn set_icon<T>(id: Id, icon: Icon) -> Task<T> {
426    task::effect(crate::Action::Window(Action::SetIcon(id, icon)))
427}
428
429/// Runs the given callback with a reference to the [`Window`] with the given [`Id`].
430///
431/// Note that if the window closes before this call is processed the callback will not be run.
432pub fn run<T>(id: Id, f: impl FnOnce(&dyn Window) -> T + Send + 'static) -> Task<T>
433where
434    T: Send + 'static,
435{
436    task::oneshot(move |channel| {
437        crate::Action::Window(Action::Run(
438            id,
439            Box::new(move |handle| {
440                let _ = channel.send(f(handle));
441            }),
442        ))
443    })
444}
445
446/// Captures a [`Screenshot`] from the window.
447pub fn screenshot(id: Id) -> Task<Screenshot> {
448    task::oneshot(move |channel| crate::Action::Window(Action::Screenshot(id, channel)))
449}
450
451/// Enables mouse passthrough for the given window.
452///
453/// This disables mouse events for the window and passes mouse events
454/// through to whatever window is underneath.
455pub fn enable_mouse_passthrough<Message>(id: Id) -> Task<Message> {
456    task::effect(crate::Action::Window(Action::EnableMousePassthrough(id)))
457}
458
459/// Disables mouse passthrough for the given window.
460///
461/// This enables mouse events for the window and stops mouse events
462/// from being passed to whatever is underneath.
463pub fn disable_mouse_passthrough<Message>(id: Id) -> Task<Message> {
464    task::effect(crate::Action::Window(Action::DisableMousePassthrough(id)))
465}
466
467/// Gets the logical dimensions of the monitor containing the window with the given [`Id`].
468pub fn monitor_size(id: Id) -> Task<Option<Size>> {
469    task::oneshot(move |channel| crate::Action::Window(Action::GetMonitorSize(id, channel)))
470}
471
472/// Sets whether the system can automatically organize windows into tabs.
473///
474/// See <https://developer.apple.com/documentation/appkit/nswindow/1646657-allowsautomaticwindowtabbing>
475pub fn allow_automatic_tabbing<T>(enabled: bool) -> Task<T> {
476    task::effect(crate::Action::Window(Action::SetAllowAutomaticTabbing(
477        enabled,
478    )))
479}