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