Merge pull request #3090 from njust/multi-window-fix-iced-rs

Provide a `Display` handle to `graphics::Compositor`
This commit is contained in:
Héctor 2025-12-01 01:25:59 +01:00 committed by GitHub
commit 2ee5f47f20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 51 additions and 24 deletions

View file

@ -18,23 +18,25 @@ pub trait Compositor: Sized {
type Surface; type Surface;
/// Creates a new [`Compositor`]. /// Creates a new [`Compositor`].
fn new<W: Window + Clone>( fn new(
settings: Settings, settings: Settings,
compatible_window: W, display: impl Display + Clone,
compatible_window: impl Window + Clone,
shell: Shell, shell: Shell,
) -> impl Future<Output = Result<Self, Error>> { ) -> impl Future<Output = Result<Self, Error>> {
Self::with_backend(settings, compatible_window, shell, None) Self::with_backend(settings, display, compatible_window, shell, None)
} }
/// Creates a new [`Compositor`] with a backend preference. /// Creates a new [`Compositor`] with a backend preference.
/// ///
/// If the backend does not match the preference, it will return /// If the backend does not match the preference, it will return
/// [`Error::GraphicsAdapterNotFound`]. /// [`Error::GraphicsAdapterNotFound`].
fn with_backend<W: Window + Clone>( fn with_backend(
_settings: Settings, settings: Settings,
_compatible_window: W, display: impl Display + Clone,
_shell: Shell, compatible_window: impl Window + Clone,
_backend: Option<&str>, shell: Shell,
backend: Option<&str>,
) -> impl Future<Output = Result<Self, Error>>; ) -> impl Future<Output = Result<Self, Error>>;
/// Creates a [`Self::Renderer`] for the [`Compositor`]. /// Creates a [`Self::Renderer`] for the [`Compositor`].
@ -110,6 +112,15 @@ impl<T> Window for T where
{ {
} }
/// An owned display handle that can be used in a [`Compositor`].
///
/// This is just a convenient super trait of the `raw-window-handle`
/// trait.
pub trait Display: HasDisplayHandle + MaybeSend + MaybeSync + 'static {}
impl<T> Display for T where T: HasDisplayHandle + MaybeSend + MaybeSync + 'static
{}
/// Defines the default compositor of a renderer. /// Defines the default compositor of a renderer.
pub trait Default { pub trait Default {
/// The compositor of the renderer. /// The compositor of the renderer.
@ -152,9 +163,10 @@ impl Compositor for () {
type Renderer = (); type Renderer = ();
type Surface = (); type Surface = ();
async fn with_backend<W: Window + Clone>( async fn with_backend(
_settings: Settings, _settings: Settings,
_compatible_window: W, _display: impl Display,
_compatible_window: impl Window + Clone,
_shell: Shell, _shell: Shell,
_preferred_backend: Option<&str>, _preferred_backend: Option<&str>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {

View file

@ -264,9 +264,10 @@ where
type Renderer = Renderer<A::Renderer, B::Renderer>; type Renderer = Renderer<A::Renderer, B::Renderer>;
type Surface = Surface<A::Surface, B::Surface>; type Surface = Surface<A::Surface, B::Surface>;
async fn with_backend<W: compositor::Window + Clone>( async fn with_backend(
settings: graphics::Settings, settings: graphics::Settings,
compatible_window: W, display: impl compositor::Display + Clone,
compatible_window: impl compositor::Window + Clone,
shell: Shell, shell: Shell,
backend: Option<&str>, backend: Option<&str>,
) -> Result<Self, graphics::Error> { ) -> Result<Self, graphics::Error> {
@ -296,6 +297,7 @@ where
for backend in candidates.iter().map(Option::as_deref) { for backend in candidates.iter().map(Option::as_deref) {
match A::with_backend( match A::with_backend(
settings, settings,
display.clone(),
compatible_window.clone(), compatible_window.clone(),
shell.clone(), shell.clone(),
backend, backend,
@ -310,6 +312,7 @@ where
match B::with_backend( match B::with_backend(
settings, settings,
display.clone(),
compatible_window.clone(), compatible_window.clone(),
shell.clone(), shell.clone(),
backend, backend,

View file

@ -9,13 +9,13 @@ use std::collections::VecDeque;
use std::num::NonZeroU32; use std::num::NonZeroU32;
pub struct Compositor { pub struct Compositor {
context: softbuffer::Context<Box<dyn compositor::Window>>, context: softbuffer::Context<Box<dyn compositor::Display>>,
settings: Settings, settings: Settings,
} }
pub struct Surface { pub struct Surface {
window: softbuffer::Surface< window: softbuffer::Surface<
Box<dyn compositor::Window>, Box<dyn compositor::Display>,
Box<dyn compositor::Window>, Box<dyn compositor::Window>,
>, >,
clip_mask: tiny_skia::Mask, clip_mask: tiny_skia::Mask,
@ -28,15 +28,16 @@ impl crate::graphics::Compositor for Compositor {
type Renderer = Renderer; type Renderer = Renderer;
type Surface = Surface; type Surface = Surface;
async fn with_backend<W: compositor::Window>( async fn with_backend(
settings: graphics::Settings, settings: graphics::Settings,
compatible_window: W, display: impl compositor::Display,
_compatible_window: impl compositor::Window,
_shell: Shell, _shell: Shell,
backend: Option<&str>, backend: Option<&str>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
match backend { match backend {
None | Some("tiny-skia") | Some("tiny_skia") => { None | Some("tiny-skia") | Some("tiny_skia") => {
Ok(new(settings.into(), compatible_window)) Ok(new(settings.into(), display))
} }
Some(backend) => Err(Error::GraphicsAdapterNotFound { Some(backend) => Err(Error::GraphicsAdapterNotFound {
backend: "tiny-skia", backend: "tiny-skia",
@ -134,12 +135,12 @@ impl crate::graphics::Compositor for Compositor {
} }
} }
pub fn new<W: compositor::Window>( pub fn new(
settings: Settings, settings: Settings,
compatible_window: W, display: impl compositor::Display,
) -> Compositor { ) -> Compositor {
#[allow(unsafe_code)] #[allow(unsafe_code)]
let context = softbuffer::Context::new(Box::new(compatible_window) as _) let context = softbuffer::Context::new(Box::new(display) as _)
.expect("Create softbuffer context"); .expect("Create softbuffer context");
Compositor { context, settings } Compositor { context, settings }

View file

@ -261,9 +261,10 @@ impl graphics::Compositor for Compositor {
type Renderer = Renderer; type Renderer = Renderer;
type Surface = wgpu::Surface<'static>; type Surface = wgpu::Surface<'static>;
async fn with_backend<W: compositor::Window>( async fn with_backend(
settings: graphics::Settings, settings: graphics::Settings,
compatible_window: W, _display: impl compositor::Display,
compatible_window: impl compositor::Window,
shell: Shell, shell: Shell,
backend: Option<&str>, backend: Option<&str>,
) -> Result<Self, graphics::Error> { ) -> Result<Self, graphics::Error> {

View file

@ -76,11 +76,13 @@ where
let settings = program.settings(); let settings = program.settings();
let window_settings = program.window(); let window_settings = program.window();
let graphics_settings = settings.clone().into();
let event_loop = EventLoop::with_user_event() let event_loop = EventLoop::with_user_event()
.build() .build()
.expect("Create event loop"); .expect("Create event loop");
let graphics_settings = settings.clone().into();
let display_handle = event_loop.owned_display_handle();
let (proxy, worker) = Proxy::new(event_loop.create_proxy()); let (proxy, worker) = Proxy::new(event_loop.create_proxy());
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
@ -131,6 +133,7 @@ where
proxy.clone(), proxy.clone(),
event_receiver, event_receiver,
control_sender, control_sender,
display_handle,
is_daemon, is_daemon,
graphics_settings, graphics_settings,
settings.fonts, settings.fonts,
@ -511,6 +514,7 @@ async fn run_instance<P>(
mut proxy: Proxy<P::Message>, mut proxy: Proxy<P::Message>,
mut event_receiver: mpsc::UnboundedReceiver<Event<Action<P::Message>>>, mut event_receiver: mpsc::UnboundedReceiver<Event<Action<P::Message>>>,
mut control_sender: mpsc::UnboundedSender<Control>, mut control_sender: mpsc::UnboundedSender<Control>,
display_handle: winit::event_loop::OwnedDisplayHandle,
is_daemon: bool, is_daemon: bool,
graphics_settings: graphics::Settings, graphics_settings: graphics::Settings,
default_fonts: Vec<Cow<'static, [u8]>>, default_fonts: Vec<Cow<'static, [u8]>>,
@ -595,6 +599,7 @@ async fn run_instance<P>(
let create_compositor = { let create_compositor = {
let window = window.clone(); let window = window.clone();
let display_handle = display_handle.clone();
let proxy = proxy.clone(); let proxy = proxy.clone();
let default_fonts = default_fonts.clone(); let default_fonts = default_fonts.clone();
@ -602,7 +607,12 @@ async fn run_instance<P>(
let shell = Shell::new(proxy.clone()); let shell = Shell::new(proxy.clone());
let mut compositor = let mut compositor =
<P::Renderer as compositor::Default>::Compositor::new(graphics_settings, window, shell).await; <P::Renderer as compositor::Default>::Compositor::new(
graphics_settings,
display_handle,
window,
shell,
).await;
if let Ok(compositor) = &mut compositor { if let Ok(compositor) = &mut compositor {
for font in default_fonts { for font in default_fonts {