mirror of https://github.com/linebender/xilem
Async experimentation
This commit imports some of the infrastructure from the idiopath_async branch. It should still be considered experimental.
This commit is contained in:
parent
c0f725d972
commit
b1e57b02d2
|
@ -8,3 +8,5 @@ edition = "2021"
|
|||
[dependencies]
|
||||
"druid-shell" = { path = "../druid-shell" }
|
||||
bitflags = "1.3.2"
|
||||
futures-task = "0.3"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
|
|
@ -18,7 +18,8 @@ fn app_logic(_: &mut ()) -> impl View<()> {
|
|||
scroll_view(list(1000, 20.0, |i| format!("{}", i)))
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let app = App::new((), app_logic);
|
||||
AppLauncher::new(app).run();
|
||||
}
|
||||
|
|
35
src/app.rs
35
src/app.rs
|
@ -12,10 +12,14 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use druid_shell::kurbo::Size;
|
||||
use druid_shell::piet::{Color, Piet, RenderContext};
|
||||
use druid_shell::WindowHandle;
|
||||
|
||||
use crate::event::AsyncWake;
|
||||
use crate::id::IdPath;
|
||||
use crate::widget::{CxState, EventCx, LayoutCx, PaintCx, Pod, UpdateCx, WidgetState};
|
||||
use crate::{
|
||||
event::Event,
|
||||
|
@ -36,8 +40,12 @@ pub struct App<T, V: View<T>, F: FnMut(&mut T) -> V> {
|
|||
root_pod: Option<Pod>,
|
||||
size: Size,
|
||||
cx: Cx,
|
||||
wake_queue: WakeQueue,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct WakeQueue(Arc<Mutex<Vec<IdPath>>>);
|
||||
|
||||
const BG_COLOR: Color = Color::rgb8(0x27, 0x28, 0x22);
|
||||
|
||||
impl<T, V: View<T>, F: FnMut(&mut T) -> V> App<T, V, F>
|
||||
|
@ -45,7 +53,8 @@ where
|
|||
V::Element: Widget + 'static,
|
||||
{
|
||||
pub fn new(data: T, app_logic: F) -> Self {
|
||||
let cx = Cx::new();
|
||||
let wake_queue = Default::default();
|
||||
let cx = Cx::new(&wake_queue);
|
||||
App {
|
||||
data,
|
||||
app_logic,
|
||||
|
@ -58,6 +67,7 @@ where
|
|||
root_state: Default::default(),
|
||||
size: Default::default(),
|
||||
cx,
|
||||
wake_queue,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +86,7 @@ where
|
|||
pub fn connect(&mut self, window_handle: WindowHandle) {
|
||||
self.window_handle = window_handle.clone();
|
||||
// This will be needed for wiring up async but is a stub for now.
|
||||
//self.cx.set_handle(window_handle.get_idle_handle());
|
||||
self.cx.set_handle(window_handle.get_idle_handle());
|
||||
}
|
||||
|
||||
pub fn size(&mut self, size: Size) {
|
||||
|
@ -154,4 +164,25 @@ where
|
|||
}
|
||||
self.view = Some(view);
|
||||
}
|
||||
|
||||
pub fn wake_async(&mut self) {
|
||||
for id_path in self.wake_queue.take() {
|
||||
self.events.push(Event::new(id_path, AsyncWake));
|
||||
}
|
||||
self.run_app_logic();
|
||||
}
|
||||
}
|
||||
|
||||
impl WakeQueue {
|
||||
// Returns true if the queue was empty.
|
||||
pub fn push_wake(&self, id_path: IdPath) -> bool {
|
||||
let mut queue = self.0.lock().unwrap();
|
||||
let was_empty = queue.is_empty();
|
||||
queue.push(id_path);
|
||||
was_empty
|
||||
}
|
||||
|
||||
pub fn take(&self) -> Vec<IdPath> {
|
||||
std::mem::replace(&mut self.0.lock().unwrap(), Vec::new())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
use std::any::Any;
|
||||
|
||||
use druid_shell::{
|
||||
kurbo::Size, Application, Cursor, HotKey, Menu, MouseEvent, Region, SysMods, WinHandler,
|
||||
WindowBuilder, WindowHandle,
|
||||
kurbo::Size, Application, Cursor, HotKey, IdleToken, Menu, MouseEvent, Region, SysMods,
|
||||
WinHandler, WindowBuilder, WindowHandle,
|
||||
};
|
||||
|
||||
use crate::{app::App, widget::RawEvent, View, Widget};
|
||||
|
@ -135,6 +135,12 @@ where
|
|||
Application::global().quit()
|
||||
}
|
||||
|
||||
fn idle(&mut self, _token: IdleToken) {
|
||||
self.app.wake_async();
|
||||
// TODO: wire up invalidation through widget hierarchy
|
||||
self.handle.invalidate();
|
||||
}
|
||||
|
||||
fn as_any(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ pub enum EventResult<A> {
|
|||
Stale,
|
||||
}
|
||||
|
||||
pub struct AsyncWake;
|
||||
|
||||
impl<A> EventResult<A> {
|
||||
#[allow(unused)]
|
||||
pub fn map<B>(self, f: impl FnOnce(A) -> B) -> EventResult<B> {
|
||||
|
|
43
src/view.rs
43
src/view.rs
|
@ -23,9 +23,13 @@ pub mod text;
|
|||
pub mod use_state;
|
||||
pub mod vstack;
|
||||
|
||||
use std::any::Any;
|
||||
use std::{any::Any, sync::Arc};
|
||||
|
||||
use druid_shell::{IdleHandle, IdleToken};
|
||||
use futures_task::{ArcWake, Waker};
|
||||
|
||||
use crate::{
|
||||
app::WakeQueue,
|
||||
event::EventResult,
|
||||
id::{Id, IdPath},
|
||||
widget::Widget,
|
||||
|
@ -84,12 +88,35 @@ pub trait View<T, A = ()> {
|
|||
#[derive(Clone)]
|
||||
pub struct Cx {
|
||||
id_path: IdPath,
|
||||
idle_handle: Option<IdleHandle>,
|
||||
wake_queue: WakeQueue,
|
||||
}
|
||||
|
||||
struct MyWaker {
|
||||
id_path: IdPath,
|
||||
idle_handle: IdleHandle,
|
||||
wake_queue: WakeQueue,
|
||||
}
|
||||
|
||||
impl ArcWake for MyWaker {
|
||||
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||
println!("path = {:?}", arc_self.id_path);
|
||||
if arc_self.wake_queue.push_wake(arc_self.id_path.clone()) {
|
||||
// The clone shouldn't be needed; schedule_idle should be &self I think
|
||||
arc_self
|
||||
.idle_handle
|
||||
.clone()
|
||||
.schedule_idle(IdleToken::new(42));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cx {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(wake_queue: &WakeQueue) -> Self {
|
||||
Cx {
|
||||
id_path: Vec::new(),
|
||||
idle_handle: None,
|
||||
wake_queue: wake_queue.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,4 +156,16 @@ impl Cx {
|
|||
self.pop();
|
||||
(id, result)
|
||||
}
|
||||
|
||||
pub(crate) fn set_handle(&mut self, idle_handle: Option<IdleHandle>) {
|
||||
self.idle_handle = idle_handle;
|
||||
}
|
||||
|
||||
pub fn waker(&self) -> Waker {
|
||||
futures_task::waker(Arc::new(MyWaker {
|
||||
id_path: self.id_path.clone(),
|
||||
idle_handle: self.idle_handle.as_ref().unwrap().clone(),
|
||||
wake_queue: self.wake_queue.clone(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue