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.08k stars 575 forks source link

Feature Request: Add `poll_events` API to cooperate with other event loop #2763

Open zuoxinyu opened 1 year ago

zuoxinyu commented 1 year ago

I'm using C++ API, need a slint::poll_events API to integrate with other event system like SDL2 or libuv. Currently there is a workaround by using a repeat timer. But I'm glad to see there would be a dedicate API for this purpose.

tronical commented 1 year ago

Yes, perhaps this is doable. What's a little tricky is that neither with Qt nor with Winit we can get the file descriptors needed for polling. Could you describe a little how your ideal setup would look like?

zuoxinyu commented 1 year ago

Yes, perhaps this is doable. What's a little tricky is that neither with Qt nor with Winit we can get the file descriptors needed for polling. Could you describe a little how your ideal setup would look like?

I don't think it has anything to do with file descriptors here.

A poll() API typically is used as while (true) { slint::poll(); } instead of slint::run_event_loop(). Inner the loop users can do some other stuffs.

tronical commented 1 year ago

At what point should slint::poll(); return? Only when an event was received? If no event was received, then after a timeout? What do you do after the timeout? Poll libuv? If you want to poll both simultaneously then, then it sounds like you end up spinning the CPU needlessly?

zuoxinyu commented 1 year ago

There are several strategies:

  1. return after a fixed timeout such as 16ms, e.g. an overloaded version poll(duration) in c++ or a poll_timeout(duration) in rust.
  2. after processing all the queued events, return a true or an int indicates the number of processed events.
  3. if the event queue is empty, then return a false or zero immediately.

These are very common usecases in an eventloop based programming model. In other frameworks, an event loop is always combined with a poll semantic such as SDL2, libuv, Qt, asio.

If you want to poll both simultaneously then, then it sounds like you end up spinning the CPU needlessly?

It's the users' duty to avoid a busy loop in case of using a poll semantic.

tronical commented 1 year ago

Right, so you'd basically run a while loop that first polls Slint, then polls SDL, then maybe libuv - each with a timeout one after the other? It's not optimal, but probably acceptable for many :-)

We could offer this, indeed - using processEvents() with Qt and run_return() with winit - despite all the caveats.

zuoxinyu commented 1 year ago

Yes, users who use this api should take care about the caveats themeselves.

willglynn commented 1 year ago

These are very common usecases in an eventloop based programming model. In other frameworks, an event loop is always combined with a poll semantic such as SDL2, libuv, Qt, asio.

This is specifically incompatible with target environments where the platform owns the event loop. This includes every web browser, Windows, MacOS, and both major mobile platforms. winit was originally built the way you describe, with the user running a loop {} in fn main(), but ultimately was rearchitected to invert the control flow. Having the platform loop call the application always works, while having an application loop call the platform doesn't.

Slint could offer a poll_events() API in at least some configurations, but I don't think it's viable to offer it in all configurations.

zuoxinyu commented 1 year ago

These are very common usecases in an eventloop based programming model. In other frameworks, an event loop is always combined with a poll semantic such as SDL2, libuv, Qt, asio.

This is specifically incompatible with target environments where the platform owns the event loop. This includes every web browser, Windows, MacOS, and both major mobile platforms. winit was originally built the way you describe, with the user running a loop {} in fn main(), but ultimately was rearchitected to invert the control flow. Having the platform loop call the application always works, while having an application loop call the platform doesn't.

Slint could offer a poll_events() API in at least some configurations, but I don't think it's viable to offer it in all configurations.

Then alternatively, Slint could provide a hook method to support this.

ogoffart commented 1 year ago

Maybe it would be useful to understand the exact use-case and how we can solve it. What are we trying to solve? Can this be solved by using thread and callbacks? (slint::invoke_from_event_loop or slint::blocking_invoke_from_event_loop