Fix recurring C++ timers

* sixtyfps_timer_start needs to *take* the timer id out of the Rust
  timer to avoid that the subsequent drop stops the timer again
* For the Qt event loop, call `timer_event()` once before entering
  QCoreApplication::exec(), to schedule any timers that were started
  beforehand.
* Added a way to quit the event loop gently, in order to use that
  from the C++ unit test.
This commit is contained in:
Simon Hausmann 2021-03-25 18:31:46 +01:00
parent f4ed0e333b
commit 4cbcf2611f
10 changed files with 50 additions and 2 deletions

View file

@ -670,6 +670,11 @@ void run_event_loop()
cbindgen_private::sixtyfps_run_event_loop(); cbindgen_private::sixtyfps_run_event_loop();
} }
void quit_event_loop()
{
cbindgen_private::sixtyfps_quit_event_loop();
}
/// Registers a font by the specified path. The path must refer to an existing /// Registers a font by the specified path. The path must refer to an existing
/// TrueType font font. /// TrueType font font.
/// \returns an empty optional on success, otherwise an error string /// \returns an empty optional on success, otherwise an error string

View file

@ -37,6 +37,11 @@ pub unsafe extern "C" fn sixtyfps_run_event_loop() {
crate::backend().run_event_loop(); crate::backend().run_event_loop();
} }
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_quit_event_loop() {
crate::backend().quit_event_loop();
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sixtyfps_register_font_from_path( pub unsafe extern "C" fn sixtyfps_register_font_from_path(
path: &sixtyfps_corelib::SharedString, path: &sixtyfps_corelib::SharedString,

View file

@ -8,6 +8,7 @@
Please contact info@sixtyfps.io for more information. Please contact info@sixtyfps.io for more information.
LICENSE END */ LICENSE END */
#include <chrono>
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
@ -63,4 +64,13 @@ TEST_CASE("Property Tracker")
prop.set(100); prop.set(100);
REQUIRE(tracker2.is_dirty()); REQUIRE(tracker2.is_dirty());
REQUIRE(!tracker1.is_dirty()); REQUIRE(!tracker1.is_dirty());
}
TEST_CASE("C++ Timers")
{
using namespace sixtyfps;
Timer testTimer(std::chrono::milliseconds(16), []() { sixtyfps::quit_event_loop(); });
sixtyfps::run_event_loop();
} }

View file

@ -24,6 +24,9 @@ pub trait Backend: Send + Sync {
/// Spins an event loop and renders the visible windows. /// Spins an event loop and renders the visible windows.
fn run_event_loop(&'static self); fn run_event_loop(&'static self);
/// Exits the event loop.
fn quit_event_loop(&'static self);
/// This function can be used to register a custom TrueType font with SixtyFPS, /// This function can be used to register a custom TrueType font with SixtyFPS,
/// for use with the `font-family` property. The provided slice must be a valid TrueType /// for use with the `font-family` property. The provided slice must be a valid TrueType
/// font. /// font.

View file

@ -340,7 +340,7 @@ pub(crate) mod ffi {
timer.start(TimerMode::Repeated, core::time::Duration::from_millis(duration), move || { timer.start(TimerMode::Repeated, core::time::Duration::from_millis(duration), move || {
(wrap.callback)(wrap.user_data) (wrap.callback)(wrap.user_data)
}); });
timer.id.get().map(|x| x as i64).unwrap_or(-1) timer.id.take().map(|x| x as i64).unwrap_or(-1)
} }
/// Execute a callback with a delay in milisecond /// Execute a callback with a delay in milisecond

View file

@ -110,6 +110,7 @@ pub enum CustomEvent {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
WakeUpAndPoll, WakeUpAndPoll,
UpdateWindowProperties(Weak<Window>), UpdateWindowProperties(Weak<Window>),
Exit,
} }
/// Runs the event loop and renders the items in the provided `component` in its /// Runs the event loop and renders the items in the provided `component` in its
@ -400,6 +401,10 @@ pub fn run() {
window.upgrade().map(|window| window.update_window_properties()); window.upgrade().map(|window| window.update_window_properties());
} }
winit::event::Event::UserEvent(CustomEvent::Exit) => {
*control_flow = winit::event_loop::ControlFlow::Exit;
}
_ => (), _ => (),
} }

View file

@ -1487,6 +1487,12 @@ impl sixtyfps_corelib::backend::Backend for Backend {
crate::eventloop::run(); crate::eventloop::run();
} }
fn quit_event_loop(&'static self) {
crate::eventloop::with_window_target(|event_loop| {
event_loop.event_loop_proxy().send_event(crate::eventloop::CustomEvent::Exit).ok();
})
}
fn register_font_from_memory( fn register_font_from_memory(
&'static self, &'static self,
data: &[u8], data: &[u8],

View file

@ -59,4 +59,5 @@ fn main() {
println!("cargo:rerun-if-changed=qt_window.rs"); println!("cargo:rerun-if-changed=qt_window.rs");
println!("cargo:rerun-if-changed=widgets.rs"); println!("cargo:rerun-if-changed=widgets.rs");
println!("cargo:rerun-if-changed=qttypes.rs"); println!("cargo:rerun-if-changed=qttypes.rs");
println!("cargo:rerun-if-changed=lib.rs");
} }

View file

@ -114,6 +114,8 @@ impl sixtyfps_corelib::backend::Backend for Backend {
fn run_event_loop(&'static self) { fn run_event_loop(&'static self) {
#[cfg(not(no_qt))] #[cfg(not(no_qt))]
{ {
// Schedule any timers with Qt that were set up before this event loop start.
crate::qt_window::timer_event();
use cpp::cpp; use cpp::cpp;
cpp! {unsafe [] { cpp! {unsafe [] {
qApp->exec(); qApp->exec();
@ -121,6 +123,16 @@ impl sixtyfps_corelib::backend::Backend for Backend {
}; };
} }
fn quit_event_loop(&'static self) {
#[cfg(not(no_qt))]
{
use cpp::cpp;
cpp! {unsafe [] {
qApp->quit();
} }
};
}
fn register_font_from_memory( fn register_font_from_memory(
&'static self, &'static self,
_data: &[u8], _data: &[u8],

View file

@ -1080,7 +1080,7 @@ thread_local! {
} }
/// Called by C++'s TimerHandler::timerEvent, or everytime a timer might have been started /// Called by C++'s TimerHandler::timerEvent, or everytime a timer might have been started
fn timer_event() { pub(crate) fn timer_event() {
sixtyfps_corelib::animations::update_animations(); sixtyfps_corelib::animations::update_animations();
sixtyfps_corelib::timers::TimerList::maybe_activate_timers(); sixtyfps_corelib::timers::TimerList::maybe_activate_timers();
@ -1113,6 +1113,7 @@ fn timer_event() {
}; };
if let Some(timeout) = timeout { if let Some(timeout) = timeout {
cpp! { unsafe [timeout as "int"] { cpp! { unsafe [timeout as "int"] {
ensure_initialized();
TimerHandler::instance().timer.start(timeout, &TimerHandler::instance()); TimerHandler::instance().timer.start(timeout, &TimerHandler::instance());
}} }}
} }