Struct EventLoopProxy
pub struct EventLoopProxy { /* private fields */ }
Expand description
Control the ActiveEventLoop
, possibly from a different thread, without referencing it
directly.
Implementations§
§impl EventLoopProxy
impl EventLoopProxy
pub fn wake_up(&self)
pub fn wake_up(&self)
Wake up the ActiveEventLoop
, resulting in ApplicationHandler::proxy_wake_up()
being
called.
Calls to this method are coalesced into a single call to proxy_wake_up
, see the
documentation on that for details.
If the event loop is no longer running, this is a no-op.
§Platform-specific
- Windows: The wake-up may be ignored under high contention, see #3687.
Examples found in repository?
examples/application.rs (line 69)
49fn main() -> Result<(), Box<dyn Error>> {
50 #[cfg(web_platform)]
51 console_error_panic_hook::set_once();
52
53 tracing::init();
54
55 let event_loop = EventLoop::new()?;
56 let (sender, receiver) = mpsc::channel();
57
58 // Wire the user event from another thread.
59 #[cfg(not(web_platform))]
60 {
61 let event_loop_proxy = event_loop.create_proxy();
62 let sender = sender.clone();
63 std::thread::spawn(move || {
64 // Wake up the `event_loop` once every second and dispatch a custom event
65 // from a different thread.
66 info!("Starting to send user event every second");
67 loop {
68 let _ = sender.send(Action::Message);
69 event_loop_proxy.wake_up();
70 std::thread::sleep(std::time::Duration::from_secs(1));
71 }
72 });
73 }
74
75 let app = Application::new(&event_loop, receiver, sender);
76 Ok(event_loop.run_app(app)?)
77}
78
79/// Application state and event handling.
80struct Application {
81 /// Trigger actions through proxy wake up.
82 receiver: Receiver<Action>,
83 sender: Sender<Action>,
84 /// Custom cursors assets.
85 custom_cursors: Result<Vec<CustomCursor>, RequestError>,
86 /// Application icon.
87 icon: Icon,
88 windows: HashMap<WindowId, WindowState>,
89 /// Drawing context.
90 ///
91 /// With OpenGL it could be EGLDisplay.
92 #[cfg(not(android_platform))]
93 context: Option<Context<DisplayHandle<'static>>>,
94}
95
96impl Application {
97 fn new(event_loop: &EventLoop, receiver: Receiver<Action>, sender: Sender<Action>) -> Self {
98 // SAFETY: we drop the context right before the event loop is stopped, thus making it safe.
99 #[cfg(not(android_platform))]
100 let context = Some(
101 Context::new(unsafe {
102 std::mem::transmute::<DisplayHandle<'_>, DisplayHandle<'static>>(
103 event_loop.display_handle().unwrap(),
104 )
105 })
106 .unwrap(),
107 );
108
109 // You'll have to choose an icon size at your own discretion. On X11, the desired size
110 // varies by WM, and on Windows, you still have to account for screen scaling. Here
111 // we use 32px, since it seems to work well enough in most cases. Be careful about
112 // going too high, or you'll be bitten by the low-quality downscaling built into the
113 // WM.
114 let icon = load_icon(include_bytes!("data/icon.png"));
115
116 info!("Loading cursor assets");
117 let custom_cursors = [
118 event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/cross.png"))),
119 event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/cross2.png"))),
120 event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/gradient.png"))),
121 ]
122 .into_iter()
123 .collect();
124
125 Self {
126 receiver,
127 sender,
128 #[cfg(not(android_platform))]
129 context,
130 custom_cursors,
131 icon,
132 windows: Default::default(),
133 }
134 }
135
136 fn create_window(
137 &mut self,
138 event_loop: &dyn ActiveEventLoop,
139 _tab_id: Option<String>,
140 ) -> Result<WindowId, Box<dyn Error>> {
141 // TODO read-out activation token.
142
143 #[allow(unused_mut)]
144 let mut window_attributes = WindowAttributes::default()
145 .with_title("Winit window")
146 .with_transparent(true)
147 .with_window_icon(Some(self.icon.clone()));
148
149 #[cfg(x11_platform)]
150 if event_loop.is_x11() {
151 window_attributes = window_attributes
152 .with_platform_attributes(Box::new(window_attributes_x11(event_loop)?));
153 }
154
155 #[cfg(wayland_platform)]
156 if event_loop.is_wayland() {
157 window_attributes = window_attributes
158 .with_platform_attributes(Box::new(window_attributes_wayland(event_loop)));
159 }
160
161 #[cfg(macos_platform)]
162 if let Some(tab_id) = _tab_id {
163 let window_attributes_macos =
164 Box::new(WindowAttributesMacOS::default().with_tabbing_identifier(&tab_id));
165 window_attributes = window_attributes.with_platform_attributes(window_attributes_macos);
166 }
167
168 #[cfg(web_platform)]
169 {
170 window_attributes =
171 window_attributes.with_platform_attributes(Box::new(window_attributes_web()));
172 }
173
174 let window = event_loop.create_window(window_attributes)?;
175
176 #[cfg(ios_platform)]
177 {
178 use winit::platform::ios::WindowExtIOS;
179 window.recognize_doubletap_gesture(true);
180 window.recognize_pinch_gesture(true);
181 window.recognize_rotation_gesture(true);
182 window.recognize_pan_gesture(true, 2, 2);
183 }
184
185 let window_state = WindowState::new(self, window)?;
186 let window_id = window_state.window.id();
187 info!("Created new window with id={window_id:?}");
188 self.windows.insert(window_id, window_state);
189 Ok(window_id)
190 }
191
192 fn handle_action_from_proxy(&mut self, _event_loop: &dyn ActiveEventLoop, action: Action) {
193 match action {
194 #[cfg(web_platform)]
195 Action::DumpMonitors => self.dump_monitors(_event_loop),
196 Action::Message => {
197 info!("User wake up");
198 },
199 _ => unreachable!("Tried to execute invalid action without `WindowId`"),
200 }
201 }
202
203 fn handle_action_with_window(
204 &mut self,
205 event_loop: &dyn ActiveEventLoop,
206 window_id: WindowId,
207 action: Action,
208 ) {
209 // let cursor_position = self.cursor_position;
210 let window = self.windows.get_mut(&window_id).unwrap();
211 info!("Executing action: {action:?}");
212 match action {
213 Action::CloseWindow => {
214 let _ = self.windows.remove(&window_id);
215 },
216 Action::CreateNewWindow => {
217 #[cfg(any(x11_platform, wayland_platform))]
218 if let Err(err) = window.window.request_activation_token() {
219 info!("Failed to get activation token: {err}");
220 } else {
221 return;
222 }
223
224 if let Err(err) = self.create_window(event_loop, None) {
225 error!("Error creating new window: {err}");
226 }
227 },
228 Action::ToggleResizeIncrements => window.toggle_resize_increments(),
229 Action::ToggleCursorVisibility => window.toggle_cursor_visibility(),
230 Action::ToggleResizable => window.toggle_resizable(),
231 Action::ToggleDecorations => window.toggle_decorations(),
232 Action::ToggleFullscreen => window.toggle_fullscreen(),
233 #[cfg(macos_platform)]
234 Action::ToggleSimpleFullscreen => {
235 window.window.set_simple_fullscreen(!window.window.simple_fullscreen());
236 },
237 Action::ToggleMaximize => window.toggle_maximize(),
238 Action::ToggleImeInput => window.toggle_ime(),
239 Action::Minimize => window.minimize(),
240 Action::NextCursor => window.next_cursor(),
241 Action::NextCustomCursor => {
242 if let Err(err) = self.custom_cursors.as_ref().map(|c| window.next_custom_cursor(c))
243 {
244 error!("Error creating custom cursor: {err}");
245 }
246 },
247 #[cfg(web_platform)]
248 Action::UrlCustomCursor => {
249 if let Err(err) = window.url_custom_cursor(event_loop) {
250 error!("Error creating custom cursor from URL: {err}");
251 }
252 },
253 #[cfg(web_platform)]
254 Action::AnimationCustomCursor => {
255 if let Err(err) = self
256 .custom_cursors
257 .as_ref()
258 .map(|c| window.animation_custom_cursor(event_loop, c))
259 {
260 error!("Error creating animated custom cursor: {err}");
261 }
262 },
263 Action::CycleCursorGrab => window.cycle_cursor_grab(),
264 Action::DragWindow => window.drag_window(),
265 Action::DragResizeWindow => window.drag_resize_window(),
266 Action::ShowWindowMenu => window.show_menu(),
267 Action::PrintHelp => self.print_help(),
268 #[cfg(macos_platform)]
269 Action::CycleOptionAsAlt => window.cycle_option_as_alt(),
270 Action::SetTheme(theme) => {
271 window.window.set_theme(theme);
272 // Get the resulting current theme to draw with
273 let actual_theme = theme.or_else(|| window.window.theme()).unwrap_or(Theme::Dark);
274 window.set_draw_theme(actual_theme);
275 },
276 #[cfg(macos_platform)]
277 Action::CreateNewTab => {
278 let tab_id = window.window.tabbing_identifier();
279 if let Err(err) = self.create_window(event_loop, Some(tab_id)) {
280 error!("Error creating new window: {err}");
281 }
282 },
283 Action::RequestResize => window.swap_dimensions(),
284 #[cfg(web_platform)]
285 Action::DumpMonitors => {
286 let future = event_loop.request_detailed_monitor_permission();
287 let proxy = event_loop.create_proxy();
288 let sender = self.sender.clone();
289 wasm_bindgen_futures::spawn_local(async move {
290 if let Err(error) = future.await {
291 error!("{error}")
292 }
293
294 let _ = sender.send(Action::DumpMonitors);
295 proxy.wake_up();
296 });
297 },
298 #[cfg(not(web_platform))]
299 Action::DumpMonitors => self.dump_monitors(event_loop),
300 Action::Message => {
301 self.sender.send(Action::Message).unwrap();
302 event_loop.create_proxy().wake_up();
303 },
304 Action::ToggleAnimatedFillColor => {
305 window.animated_fill_color = !window.animated_fill_color;
306 },
307 Action::ToggleContinuousRedraw => {
308 window.continuous_redraw = !window.continuous_redraw;
309 window.window.request_redraw();
310 },
311 }
312 }
pub fn new(proxy: Arc<dyn EventLoopProxyProvider>) -> EventLoopProxy
Trait Implementations§
§impl Clone for EventLoopProxy
impl Clone for EventLoopProxy
§fn clone(&self) -> EventLoopProxy
fn clone(&self) -> EventLoopProxy
Returns a copy of the value. Read more
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source
. Read moreAuto Trait Implementations§
impl Freeze for EventLoopProxy
impl !RefUnwindSafe for EventLoopProxy
impl Send for EventLoopProxy
impl Sync for EventLoopProxy
impl Unpin for EventLoopProxy
impl !UnwindSafe for EventLoopProxy
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.