Struct EventLoopProxy

pub struct EventLoopProxy { /* private fields */ }
Expand description

Control the ActiveEventLoop, possibly from a different thread, without referencing it directly.

Implementations§

§

impl EventLoopProxy

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

§

fn clone(&self) -> EventLoopProxy

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
§

impl Debug for EventLoopProxy

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

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>

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)

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)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more