Create iced_futures and wire everything up
This commit is contained in:
parent
d50ff9b5d9
commit
b5b17ed4d8
23 changed files with 196 additions and 195 deletions
|
|
@ -14,11 +14,17 @@ categories = ["gui"]
|
|||
debug = []
|
||||
|
||||
[dependencies]
|
||||
iced_native = { version = "0.1.0-alpha", path = "../native" }
|
||||
winit = { version = "0.20.0-alpha3", git = "https://github.com/hecrj/winit", rev = "709808eb4e69044705fcb214bcc30556db761405"}
|
||||
window_clipboard = { git = "https://github.com/hecrj/window_clipboard", rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf" }
|
||||
futures = { version = "0.3", features = ["thread-pool"] }
|
||||
log = "0.4"
|
||||
futures = { version = "0.3", features = ["thread-pool"] }
|
||||
|
||||
[dependencies.iced_native]
|
||||
version = "0.1.0-alpha"
|
||||
path = "../native"
|
||||
|
||||
[dependencies.window_clipboard]
|
||||
git = "https://github.com/hecrj/window_clipboard"
|
||||
rev = "22c6dd6c04cd05d528029b50a30c56417cd4bebf"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies.winapi]
|
||||
version = "0.3.6"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use crate::{
|
||||
conversion,
|
||||
input::{keyboard, mouse},
|
||||
subscription, window, Cache, Clipboard, Command, Debug, Element, Event,
|
||||
Mode, MouseCursor, Settings, Size, Subscription, UserInterface,
|
||||
window, Cache, Clipboard, Command, Debug, Element, Event, Mode,
|
||||
MouseCursor, Proxy, Settings, Size, Subscription, UserInterface,
|
||||
};
|
||||
use iced_native::Runtime;
|
||||
|
||||
/// An interactive, native cross-platform application.
|
||||
///
|
||||
|
|
@ -109,17 +110,19 @@ pub trait Application: Sized {
|
|||
|
||||
debug.startup_started();
|
||||
let event_loop = EventLoop::with_user_event();
|
||||
let proxy = event_loop.create_proxy();
|
||||
let mut thread_pool =
|
||||
futures::executor::ThreadPool::new().expect("Create thread pool");
|
||||
let mut subscription_pool = subscription::Pool::new();
|
||||
let mut runtime = {
|
||||
let thread_pool = futures::executor::ThreadPool::new()
|
||||
.expect("Create thread pool");
|
||||
|
||||
Runtime::new(thread_pool, Proxy::new(event_loop.create_proxy()))
|
||||
};
|
||||
let mut external_messages = Vec::new();
|
||||
|
||||
let (mut application, init_command) = Self::new();
|
||||
spawn(init_command, &mut thread_pool, &proxy);
|
||||
runtime.spawn(init_command);
|
||||
|
||||
let subscription = application.subscription();
|
||||
subscription_pool.update(subscription, &mut thread_pool, &proxy);
|
||||
runtime.track(subscription);
|
||||
|
||||
let mut title = application.title();
|
||||
let mut mode = application.mode();
|
||||
|
|
@ -212,7 +215,7 @@ pub trait Application: Sized {
|
|||
events
|
||||
.iter()
|
||||
.cloned()
|
||||
.for_each(|event| subscription_pool.broadcast_event(event));
|
||||
.for_each(|event| runtime.broadcast(event));
|
||||
|
||||
let mut messages = user_interface.update(
|
||||
&renderer,
|
||||
|
|
@ -241,17 +244,15 @@ pub trait Application: Sized {
|
|||
debug.log_message(&message);
|
||||
|
||||
debug.update_started();
|
||||
let command = application.update(message);
|
||||
spawn(command, &mut thread_pool, &proxy);
|
||||
let command =
|
||||
runtime.enter(|| application.update(message));
|
||||
runtime.spawn(command);
|
||||
debug.update_finished();
|
||||
}
|
||||
|
||||
let subscription = application.subscription();
|
||||
subscription_pool.update(
|
||||
subscription,
|
||||
&mut thread_pool,
|
||||
&proxy,
|
||||
);
|
||||
let subscription =
|
||||
runtime.enter(|| application.subscription());
|
||||
runtime.track(subscription);
|
||||
|
||||
// Update window title
|
||||
let new_title = application.title();
|
||||
|
|
@ -463,28 +464,6 @@ fn to_physical(size: winit::dpi::LogicalSize, dpi: f64) -> (u16, u16) {
|
|||
)
|
||||
}
|
||||
|
||||
fn spawn<Message: Send>(
|
||||
command: Command<Message>,
|
||||
thread_pool: &mut futures::executor::ThreadPool,
|
||||
proxy: &winit::event_loop::EventLoopProxy<Message>,
|
||||
) {
|
||||
use futures::FutureExt;
|
||||
|
||||
let futures = command.futures();
|
||||
|
||||
for future in futures {
|
||||
let proxy = proxy.clone();
|
||||
|
||||
let future = future.map(move |message| {
|
||||
proxy
|
||||
.send_event(message)
|
||||
.expect("Send command result to event loop");
|
||||
});
|
||||
|
||||
thread_pool.spawn_ok(future);
|
||||
}
|
||||
}
|
||||
|
||||
// As defined in: http://www.unicode.org/faq/private_use.html
|
||||
// TODO: Remove once https://github.com/rust-windowing/winit/pull/1254 lands
|
||||
fn is_private_use_character(c: char) -> bool {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ pub mod settings;
|
|||
mod application;
|
||||
mod clipboard;
|
||||
mod mode;
|
||||
mod subscription;
|
||||
mod proxy;
|
||||
|
||||
// We disable debug capabilities on release builds unless the `debug` feature
|
||||
// is explicitly enabled.
|
||||
|
|
@ -48,3 +48,4 @@ pub use settings::Settings;
|
|||
|
||||
use clipboard::Clipboard;
|
||||
use debug::Debug;
|
||||
use proxy::Proxy;
|
||||
|
|
|
|||
57
winit/src/proxy.rs
Normal file
57
winit/src/proxy.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use futures::{
|
||||
task::{Context, Poll},
|
||||
Sink,
|
||||
};
|
||||
use std::pin::Pin;
|
||||
|
||||
pub struct Proxy<Message: 'static> {
|
||||
raw: winit::event_loop::EventLoopProxy<Message>,
|
||||
}
|
||||
|
||||
impl<Message: 'static> Clone for Proxy<Message> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
raw: self.raw.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message: 'static> Proxy<Message> {
|
||||
pub fn new(raw: winit::event_loop::EventLoopProxy<Message>) -> Self {
|
||||
Self { raw }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message: 'static> Sink<Message> for Proxy<Message> {
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn poll_ready(
|
||||
self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn start_send(
|
||||
self: Pin<&mut Self>,
|
||||
message: Message,
|
||||
) -> Result<(), Self::Error> {
|
||||
let _ = self.raw.send_event(message);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn poll_flush(
|
||||
self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn poll_close(
|
||||
self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
use iced_native::{Event, Hasher, Subscription};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct Pool {
|
||||
alive: HashMap<u64, Handle>,
|
||||
}
|
||||
|
||||
pub struct Handle {
|
||||
_cancel: futures::channel::oneshot::Sender<()>,
|
||||
listener: Option<futures::channel::mpsc::Sender<Event>>,
|
||||
}
|
||||
|
||||
impl Pool {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
alive: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update<Message: Send>(
|
||||
&mut self,
|
||||
subscription: Subscription<Message>,
|
||||
thread_pool: &mut futures::executor::ThreadPool,
|
||||
proxy: &winit::event_loop::EventLoopProxy<Message>,
|
||||
) {
|
||||
use futures::{future::FutureExt, stream::StreamExt};
|
||||
|
||||
let recipes = subscription.recipes();
|
||||
let mut alive = std::collections::HashSet::new();
|
||||
|
||||
for recipe in recipes {
|
||||
let id = {
|
||||
use std::hash::Hasher as _;
|
||||
|
||||
let mut hasher = Hasher::default();
|
||||
recipe.hash(&mut hasher);
|
||||
|
||||
hasher.finish()
|
||||
};
|
||||
|
||||
let _ = alive.insert(id);
|
||||
|
||||
if !self.alive.contains_key(&id) {
|
||||
let (cancel, cancelled) = futures::channel::oneshot::channel();
|
||||
|
||||
// TODO: Use bus if/when it supports async
|
||||
let (event_sender, event_receiver) =
|
||||
futures::channel::mpsc::channel(100);
|
||||
|
||||
let stream = recipe.stream(event_receiver.boxed());
|
||||
let proxy = proxy.clone();
|
||||
|
||||
let future = futures::future::select(
|
||||
cancelled,
|
||||
stream.for_each(move |message| {
|
||||
proxy
|
||||
.send_event(message)
|
||||
.expect("Send subscription result to event loop");
|
||||
|
||||
futures::future::ready(())
|
||||
}),
|
||||
)
|
||||
.map(|_| ());
|
||||
|
||||
thread_pool.spawn_ok(future);
|
||||
|
||||
let _ = self.alive.insert(
|
||||
id,
|
||||
Handle {
|
||||
_cancel: cancel,
|
||||
listener: if event_sender.is_closed() {
|
||||
None
|
||||
} else {
|
||||
Some(event_sender)
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.alive.retain(|id, _| alive.contains(&id));
|
||||
}
|
||||
|
||||
pub fn broadcast_event(&mut self, event: Event) {
|
||||
self.alive
|
||||
.values_mut()
|
||||
.filter_map(|connection| connection.listener.as_mut())
|
||||
.for_each(|listener| {
|
||||
if let Err(error) = listener.try_send(event.clone()) {
|
||||
log::error!(
|
||||
"Error sending event to subscription: {:?}",
|
||||
error
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue