//! A windowing shell for Iced, on top of [`winit`].
//!
//! 
//!
//! `iced_winit` offers some convenient abstractions on top of [`iced_runtime`]
//! to quickstart development when using [`winit`].
//!
//! It exposes a renderer-agnostic [`Program`] trait that can be implemented
//! and then run with a simple call. The use of this trait is optional.
//!
//! Additionally, a [`conversion`] module is available for users that decide to
//! implement a custom event loop.
//!
//! [`iced_runtime`]: https://github.com/iced-rs/iced/tree/0.14/runtime
//! [`winit`]: https://github.com/rust-windowing/winit
//! [`conversion`]: crate::conversion
#![doc(
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use dnd::DndSurface;
pub use iced_debug as debug;
pub use iced_program as program;
pub use program::core;
pub use program::graphics;
pub use program::runtime;
use raw_window_handle::HasWindowHandle;
pub use runtime::futures;
use window_clipboard::mime::ClipboardStoreData;
pub use winit;
#[cfg(feature = "a11y")]
pub mod a11y;
pub mod clipboard;
pub mod conversion;
pub mod platform_specific;
#[cfg(feature = "program")]
pub mod program;
#[cfg(feature = "system")]
pub mod system;
mod error;
mod proxy;
mod window;
pub use clipboard::Clipboard;
pub use error::Error;
pub use proxy::Proxy;
use winit::dpi::LogicalSize;
use winit::dpi::PhysicalPosition;
use winit::dpi::PhysicalSize;
use crate::core::mouse;
use crate::core::renderer;
use crate::core::theme;
use crate::core::time::Instant;
use crate::core::widget::operation;
use crate::core::{Point, Size};
use crate::futures::futures::channel::mpsc;
use crate::futures::futures::channel::oneshot;
use crate::futures::futures::task;
use crate::futures::futures::{Future, StreamExt};
use crate::futures::subscription;
use crate::futures::{Executor, Runtime};
use crate::graphics::{Compositor, Shell, compositor};
use crate::runtime::image;
use crate::runtime::system;
use crate::runtime::user_interface::{self, UserInterface};
use crate::runtime::{Action, Task};
use program::Program;
use window::WindowManager;
use rustc_hash::FxHashMap;
use std::borrow::Cow;
use std::mem::ManuallyDrop;
use std::slice;
use std::sync::Arc;
/// Runs a [`Program`] with the provided settings.
pub fn run
(program: P) -> Result<(), Error>
where
P: Program + 'static,
P::Theme: theme::Base,
{
use winit::event_loop::EventLoop;
let boot_span = debug::boot();
let settings = program.settings();
let window_settings = program.window();
let event_loop = EventLoop::new().expect("Create event loop");
#[cfg(feature = "wayland")]
let is_wayland =
winit::platform::wayland::EventLoopExtWayland::is_wayland(&event_loop);
#[cfg(not(feature = "wayland"))]
let is_wayland = false;
// TODO this is new..
let graphics_settings = settings.clone().into();
let display_handle = event_loop.owned_display_handle();
let (event_sender, event_receiver) = mpsc::unbounded();
let (proxy, worker): (Proxy<
::Message>, _) =
Proxy::new(event_loop.create_proxy(), event_sender.clone());
#[cfg(feature = "debug")]
{
let proxy = proxy.clone();
debug::on_hotpatch(move || {
proxy.send_action(Action::Reload);
});
}
let mut runtime = {
let executor =
P::Executor::new().map_err(Error::ExecutorCreationFailed)?;
executor.spawn(worker);
Runtime::new(executor, proxy.clone())
};
let (program, task) = runtime.enter(|| program::Instance::new(program));
let is_daemon = settings.is_daemon || window_settings.is_none();
let task = if let Some(window_settings) = window_settings {
let mut task = Some(task);
let (_id, open) = runtime::window::open(window_settings);
open.then(move |_| task.take().unwrap_or_else(Task::none))
} else {
task
};
if let Some(stream) = runtime::task::into_stream(task) {
runtime.run(stream);
}
runtime.track(subscription::into_recipes(
runtime.enter(|| program.subscription().map(Action::Output)),
));
let (boot_sender, boot_receiver) = oneshot::channel();
let (control_sender, control_receiver) = mpsc::unbounded();
let (system_theme_sender, system_theme_receiver) = oneshot::channel();
let instance = Box::pin(run_instance::
(
program,
runtime,
proxy.clone(),
boot_receiver,
event_receiver,
control_sender.clone(),
display_handle,
is_daemon,
is_wayland,
graphics_settings,
settings.fonts.clone(),
system_theme_receiver,
));
let context = task::Context::from_waker(task::noop_waker_ref());
struct BootConfig {
sender: oneshot::Sender<()>,
fonts: Vec>,
graphics_settings: graphics::Settings,
control_sender: mpsc::UnboundedSender,
is_wayland: bool,
}
struct Runner {
instance: std::pin::Pin>,
context: task::Context<'static>,
id: Option,
boot: Option,
sender: mpsc::UnboundedSender>,
receiver: mpsc::UnboundedReceiver,
error: Option,
system_theme: Option>,
#[cfg(target_arch = "wasm32")]
is_booted: std::rc::Rc>,
#[cfg(target_arch = "wasm32")]
canvas: Option,
}
let runner = Runner {
instance,
context,
boot: Some(BootConfig {
sender: boot_sender,
fonts: settings.fonts,
graphics_settings,
control_sender,
is_wayland,
}),
id: settings.id,
sender: event_sender,
receiver: control_receiver,
error: None,
system_theme: Some(system_theme_sender),
#[cfg(target_arch = "wasm32")]
canvas: None,
};
boot_span.finish();
impl winit::application::ApplicationHandler for Runner
where
F: Future