Skip to main content

cosmic/surface/
action.rs

1// Copyright 2025 System76 <info@system76.com>
2// SPDX-License-Identifier: MPL-2.0
3
4use super::Action;
5#[cfg(feature = "winit")]
6use crate::Application;
7
8use iced::window;
9use std::any::Any;
10use std::sync::Arc;
11
12/// Used to produce a destroy popup message from within a widget.
13#[cfg(all(feature = "wayland", target_os = "linux"))]
14#[must_use]
15pub fn destroy_popup(id: iced_core::window::Id) -> Action {
16    Action::DestroyPopup(id)
17}
18
19#[cfg(all(feature = "wayland", target_os = "linux"))]
20#[must_use]
21pub fn destroy_subsurface(id: iced_core::window::Id) -> Action {
22    Action::DestroySubsurface(id)
23}
24
25#[cfg(all(feature = "wayland", target_os = "linux"))]
26#[must_use]
27pub fn destroy_window(id: iced_core::window::Id) -> Action {
28    Action::DestroyWindow(id)
29}
30
31#[cfg(all(feature = "wayland", target_os = "linux", feature = "winit"))]
32#[must_use]
33pub fn app_window<App: Application>(
34    settings: impl Fn(&mut App) -> window::Settings + Send + Sync + 'static,
35    view: Option<
36        Box<
37            dyn for<'a> Fn(&'a App) -> crate::Element<'a, crate::Action<App::Message>>
38                + Send
39                + Sync
40                + 'static,
41        >,
42    >,
43) -> (window::Id, Action) {
44    let id = window::Id::unique();
45
46    let boxed: Box<dyn Fn(&mut App) -> window::Settings + Send + Sync + 'static> =
47        Box::new(settings);
48    let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(boxed);
49
50    (
51        id,
52        Action::AppWindow(
53            id,
54            Arc::new(boxed),
55            view.map(|view| {
56                let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(view);
57                Arc::new(boxed)
58            }),
59        ),
60    )
61}
62
63/// Used to create a window message from within a widget.
64#[cfg(all(feature = "wayland", target_os = "linux", feature = "winit"))]
65#[must_use]
66pub fn simple_window<Message: 'static>(
67    settings: impl Fn() -> window::Settings + Send + Sync + 'static,
68    view: Option<
69        impl Fn() -> crate::Element<'static, crate::Action<Message>> + Send + Sync + 'static,
70    >,
71) -> (window::Id, Action) {
72    let id = window::Id::unique();
73
74    let boxed: Box<dyn Fn() -> window::Settings + Send + Sync + 'static> = Box::new(settings);
75    let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(boxed);
76
77    (
78        id,
79        Action::Window(
80            id,
81            Arc::new(boxed),
82            view.map(|view| {
83                let boxed: Box<
84                    dyn Fn() -> crate::Element<'static, crate::Action<Message>>
85                        + Send
86                        + Sync
87                        + 'static,
88                > = Box::new(view);
89                let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(boxed);
90                Arc::new(boxed)
91            }),
92        ),
93    )
94}
95
96#[cfg(all(feature = "wayland", target_os = "linux", feature = "winit"))]
97#[must_use]
98pub fn app_popup<App: Application>(
99    settings: impl Fn(&mut App) -> iced_runtime::platform_specific::wayland::popup::SctkPopupSettings
100    + Send
101    + Sync
102    + 'static,
103    view: Option<
104        Box<
105            dyn for<'a> Fn(&'a App) -> crate::Element<'a, crate::Action<App::Message>>
106                + Send
107                + Sync
108                + 'static,
109        >,
110    >,
111) -> Action {
112    let boxed: Box<
113        dyn Fn(&mut App) -> iced_runtime::platform_specific::wayland::popup::SctkPopupSettings
114            + Send
115            + Sync
116            + 'static,
117    > = Box::new(settings);
118    let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(boxed);
119
120    Action::AppPopup(
121        Arc::new(boxed),
122        view.map(|view| {
123            let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(view);
124            Arc::new(boxed)
125        }),
126    )
127}
128
129/// Used to create a subsurface message from within a widget.
130#[cfg(all(feature = "wayland", target_os = "linux", feature = "winit"))]
131#[must_use]
132pub fn simple_subsurface<Message: 'static, V>(
133    settings: impl Fn() -> iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings
134    + Send
135    + Sync
136    + 'static,
137    view: Option<
138        Box<dyn Fn() -> crate::Element<'static, crate::Action<Message>> + Send + Sync + 'static>,
139    >,
140) -> Action {
141    let boxed: Box<
142        dyn Fn() -> iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings
143            + Send
144            + Sync
145            + 'static,
146    > = Box::new(settings);
147    let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(boxed);
148
149    Action::Subsurface(
150        Arc::new(boxed),
151        view.map(|view| {
152            let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(view);
153            Arc::new(boxed)
154        }),
155    )
156}
157
158/// Used to create a popup message from within a widget.
159#[cfg(all(feature = "wayland", target_os = "linux", feature = "winit"))]
160#[must_use]
161pub fn simple_popup<Message: 'static>(
162    settings: impl Fn() -> iced_runtime::platform_specific::wayland::popup::SctkPopupSettings
163    + Send
164    + Sync
165    + 'static,
166    view: Option<
167        impl Fn() -> crate::Element<'static, crate::Action<Message>> + Send + Sync + 'static,
168    >,
169) -> Action {
170    let boxed: Box<
171        dyn Fn() -> iced_runtime::platform_specific::wayland::popup::SctkPopupSettings
172            + Send
173            + Sync
174            + 'static,
175    > = Box::new(settings);
176    let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(boxed);
177
178    Action::Popup(
179        Arc::new(boxed),
180        view.map(|view| {
181            let boxed: Box<
182                dyn Fn() -> crate::Element<'static, crate::Action<Message>> + Send + Sync + 'static,
183            > = Box::new(view);
184            let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(boxed);
185            Arc::new(boxed)
186        }),
187    )
188}
189
190#[cfg(all(feature = "wayland", target_os = "linux", feature = "winit"))]
191#[must_use]
192pub fn subsurface<App: Application>(
193    settings: impl Fn(
194        &mut App,
195    )
196        -> iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings
197    + Send
198    + Sync
199    + 'static,
200    // XXX Boxed trait object is required for less cumbersome type inference, but we box it anyways.
201    view: Option<
202        Box<
203            dyn for<'a> Fn(&'a App) -> crate::Element<'a, crate::Action<App::Message>>
204                + Send
205                + Sync
206                + 'static,
207        >,
208    >,
209) -> Action {
210    let boxed: Box<
211        dyn Fn(
212                &mut App,
213            )
214                -> iced_runtime::platform_specific::wayland::subsurface::SctkSubsurfaceSettings
215            + Send
216            + Sync
217            + 'static,
218    > = Box::new(settings);
219    let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(boxed);
220
221    Action::AppSubsurface(
222        Arc::new(boxed),
223        view.map(|view| {
224            let boxed: Box<dyn Any + Send + Sync + 'static> = Box::new(view);
225            Arc::new(boxed)
226        }),
227    )
228}