slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.55k stars 601 forks source link

Timer example does not work correctly on current branch #3875

Closed ogoffart closed 1 year ago

ogoffart commented 1 year ago

Discussed in https://github.com/slint-ui/slint/discussions/3873

Originally posted by **HitecExports** November 7, 2023 Hello! Platform: Windows 11 Rust 1.73 slint = { git = "https://github.com/slint-ui/slint.git", branch = "master" } Timer example does not work properly in current slint branch "Elapsed Time" progress bar updates only while moving mouse in any area (even outside the main window) **So timer does not fire event automatically.** I noticed this problem for a week ago. Before there were no such problem. **On Slint 1.2.2 same Timer Example works fine** ![image](https://github.com/slint-ui/slint/assets/19405195/a1aae535-1fa5-4a00-91e6-bd0fb740f5f5) Code (copied from Timer example) ``` // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: MIT use slint::{Timer, TimerMode}; slint::slint!( import { LineEdit, Button, Slider, HorizontalBox, VerticalBox } from "std-widgets.slint"; export component MainWindow inherits Window { in-out property total-time: slider.value * 1s; in-out property elapsed-time; callback tick(duration); tick(passed-time) => { root.elapsed-time += passed-time; root.elapsed-time = min(root.elapsed-time, root.total-time); } VerticalBox { HorizontalBox { padding-left: 0; Text { text: "Elapsed Time:"; } Rectangle { min-width: 200px; max-height: 30px; background: gray; Rectangle { x:0; height: 100%; width: parent.width * (root.elapsed-time/root.total-time); background: lightblue; } } } Text{ text: (root.total-time / 1s) + "s"; } HorizontalBox { padding-left: 0; Text { text: "Duration:"; vertical-alignment: center; } slider := Slider { maximum: 30s / 1s; value: 10s / 1s; changed(new-duration) => { root.total-time = new-duration * 1s; root.elapsed-time = min(root.elapsed-time, root.total-time); } } } Button { text: "Reset"; clicked => { root.elapsed-time = 0 } } } } ); pub fn main() { let main_window = MainWindow::new().unwrap(); let timer = Timer::default(); { let main_window_weak = main_window.as_weak(); timer.start( TimerMode::Repeated, std::time::Duration::from_millis(10), move || { let main_window = main_window_weak.unwrap(); main_window.invoke_tick(10); }, ); } main_window.run().unwrap(); } ```
ogoffart commented 1 year ago

I've tried to debug to figure out what's wrong.

In the event loop, we get a AboutToWait event, and the next_timer is about to fire so the next_timer is very low value:

https://github.com/slint-ui/slint/blob/d82e3d4e5ce4e67a4d417ebcaf204680bf432072/internal/backends/winit/event_loop.rs#L571-573

We set control flow to ControlFlow with a wait duration of a a few, or 0ms. But we're never woken up. Changing that to ControlFlow::Poll doesn't help.

tronical commented 1 year ago

I think winit uses SetTimer and the minimum resolution of that is around 16ms (USER_TIMER_MINIMUM). It might make sense for winit to use multimedia timers instead (timeSetEvent with a callback that wakes up winit), they offer a higher resolution. (That’s what Qt defaults to)

ogoffart commented 1 year ago

Filled https://github.com/rust-windowing/winit/issues/3215