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