iced-yoda/winit/src/platform_specific/wayland/mod.rs
Votre Nom 8a7a32ff92
Some checks are pending
Audit / vulnerabilities (push) Waiting to run
Check / wasm (push) Waiting to run
Check / widget (push) Waiting to run
Document / all (push) Waiting to run
Format / all (push) Waiting to run
Lint / all (push) Waiting to run
Test / all (macOS-latest, 1.88) (push) Waiting to run
Test / all (macOS-latest, beta) (push) Waiting to run
Test / all (macOS-latest, stable) (push) Waiting to run
Test / all (ubuntu-latest, 1.88) (push) Waiting to run
Test / all (ubuntu-latest, beta) (push) Waiting to run
Test / all (ubuntu-latest, stable) (push) Waiting to run
Test / all (windows-latest, 1.88) (push) Waiting to run
Test / all (windows-latest, beta) (push) Waiting to run
Test / all (windows-latest, stable) (push) Waiting to run
yoda: cargo fix --lib across all crates — drop ~115 trivial warnings
Auto-applied suggestions (unused imports, _-prefixed unused params,
redundant mutability) on iced_core, iced_widget, iced_runtime, iced_winit,
iced_wgpu, iced_graphics, iced_tiny_skia. From 170 warnings down to 55.

Leyoda 2026 – GPLv3
2026-05-05 16:45:37 +02:00

334 lines
11 KiB
Rust

pub mod commands;
pub mod conversion;
pub(crate) mod event_loop;
pub(crate) mod handlers;
pub mod keymap;
pub mod sctk_event;
pub mod subsurface_widget;
pub mod winit_window;
use super::{PlatformSpecific, SurfaceIdWrapper};
use crate::{Control, CreateCompositor, Program, WindowManager};
use crate::platform_specific::UserInterfaces;
use cctk::sctk::reexports::calloop;
use cctk::sctk::reexports::client::protocol::wl_surface::WlSurface;
use cctk::sctk::seat::keyboard::Modifiers;
use cursor_icon::CursorIcon;
use iced_futures::futures::channel::mpsc;
use iced_graphics::{Compositor, compositor};
use iced_runtime::core::{Vector, window};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle};
use sctk_event::SctkEvent;
use std::{collections::HashMap, sync::Arc};
use subsurface_widget::{SubsurfaceInstance, SubsurfaceState};
use wayland_backend::client::ObjectId;
use wayland_client::{Connection, Proxy};
use winit::dpi::Size;
use winit::event_loop::OwnedDisplayHandle;
use winit::window::ImePurpose;
pub(crate) enum Action {
Action(iced_runtime::platform_specific::wayland::Action),
SetCursor(CursorIcon),
RequestRedraw(ObjectId),
TrackWindow(Arc<dyn winit::window::Window>, window::Id),
ResizeWindow(window::Id),
RemoveWindow(window::Id),
Dropped(SurfaceIdWrapper),
SubsurfaceResize(window::Id, Size),
SetImeAllowed(bool),
SetImeCursorArea(i32, i32, i32, i32),
SetImePurpose(ImePurpose),
}
impl std::fmt::Debug for Action {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Action(arg0) => f.debug_tuple("Action").field(arg0).finish(),
Self::SetCursor(arg0) => {
f.debug_tuple("SetCursor").field(arg0).finish()
}
Self::RequestRedraw(arg0) => {
f.debug_tuple("RequestRedraw").field(arg0).finish()
}
Self::TrackWindow(_arg0, arg1) => {
f.debug_tuple("TrackWindow").field(arg1).finish()
}
Self::RemoveWindow(arg0) => {
f.debug_tuple("RemoveWindow").field(arg0).finish()
}
Self::Dropped(_surface_id_wrapper) => write!(f, "Dropped"),
Self::SubsurfaceResize(id, size) => f
.debug_tuple("SubsurfaceResize")
.field(id)
.field(size)
.finish(),
Self::ResizeWindow(arg0) => {
f.debug_tuple("ResizeWindow").field(arg0).finish()
}
Self::SetImeAllowed(allowed) => {
f.debug_tuple("SetImeAllowed").field(allowed).finish()
}
Self::SetImeCursorArea(x, y, width, height) => f
.debug_tuple("SetImeCursorArea")
.field(x)
.field(y)
.field(width)
.field(height)
.finish(),
Self::SetImePurpose(purpose) => {
f.debug_tuple("SetImePurpose").field(purpose).finish()
}
}
}
}
#[derive(Debug, Default)]
pub(crate) struct WaylandSpecific {
winit_event_sender: Option<mpsc::UnboundedSender<Control>>,
proxy: Option<winit::event_loop::EventLoopProxy>,
sender: Option<calloop::channel::Sender<Action>>,
display_handle: Option<OwnedDisplayHandle>,
conn: Option<Connection>,
modifiers: Modifiers,
surface_ids: HashMap<ObjectId, SurfaceIdWrapper>,
subsurface_state: Option<SubsurfaceState>,
surface_subsurfaces: HashMap<window::Id, Vec<SubsurfaceInstance>>,
}
impl PlatformSpecific {
pub(crate) fn with_wayland(
mut self,
tx: mpsc::UnboundedSender<Control>,
raw: winit::event_loop::EventLoopProxy,
display: OwnedDisplayHandle,
) -> Self {
self.wayland.winit_event_sender = Some(tx);
self.wayland.conn = match display.raw_display_handle() {
Ok(raw_window_handle::RawDisplayHandle::Wayland(
wayland_display_handle,
)) => {
let backend = unsafe {
wayland_backend::client::Backend::from_foreign_display(
wayland_display_handle.display.as_ptr().cast(),
)
};
Some(Connection::from_backend(backend))
}
Ok(_) => {
log::warn!("Non-Wayland display handle");
None
}
Err(_) => {
log::error!("No display handle");
None
}
};
self.wayland.display_handle = Some(display);
self.wayland.proxy = Some(raw);
// TODO remove this
self.wayland.sender =
crate::platform_specific::event_loop::SctkEventLoop::new(
self.wayland.winit_event_sender.clone().unwrap(),
self.wayland.proxy.clone().unwrap(),
self.wayland.display_handle.clone().unwrap(),
)
.ok();
self
}
pub(crate) fn send_wayland(&mut self, action: Action) {
if self.wayland.sender.is_none()
&& self.wayland.winit_event_sender.is_some()
&& self.wayland.display_handle.is_some()
&& self.wayland.proxy.is_some()
{
self.wayland.sender =
crate::platform_specific::event_loop::SctkEventLoop::new(
self.wayland.winit_event_sender.clone().unwrap(),
self.wayland.proxy.clone().unwrap(),
self.wayland.display_handle.clone().unwrap(),
)
.ok();
}
if let Some(tx) = self.wayland.sender.as_ref() {
_ = tx.send(action);
} else {
log::info!("Did not process wayland Action.");
}
}
}
impl WaylandSpecific {
pub(crate) fn conn(&self) -> Option<&Connection> {
self.conn.as_ref()
}
pub(crate) async fn handle_event<'a, 'b, P>(
&mut self,
e: SctkEvent,
events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
program: &'a crate::program::Instance<P>,
compositor: &mut Option<
<<P as Program>::Renderer as compositor::Default>::Compositor,
>,
window_manager: &mut WindowManager<
P,
<<P as Program>::Renderer as compositor::Default>::Compositor,
>,
user_interfaces: &mut UserInterfaces<'a, P>,
clipboard: &mut crate::Clipboard,
create_compositor: CreateCompositor<'b, P>,
) where
P: Program,
{
let Self {
winit_event_sender,
proxy,
sender,
display_handle: _,
conn: _,
surface_ids,
modifiers,
subsurface_state,
surface_subsurfaces: _,
} = self;
match e {
sctk_event => {
let Some(sender) = sender.as_ref() else {
log::warn!("Missing calloop sender");
return Default::default();
};
let Some(event_sender) = winit_event_sender.as_mut() else {
log::warn!("Missing control sender");
return Default::default();
};
let Some(proxy) = proxy.as_ref() else {
log::warn!("Missing event loop proxy");
return Default::default();
};
sctk_event
.process(
modifiers,
program,
compositor,
window_manager,
surface_ids,
sender,
event_sender,
proxy,
user_interfaces,
events,
clipboard,
subsurface_state,
create_compositor,
)
.await;
}
};
}
pub(crate) fn retain_subsurfaces<F: Fn(window::Id) -> bool>(
&mut self,
keep: F,
) {
self.surface_subsurfaces.retain(|k, _v| keep(*k))
}
pub(crate) fn clear_subsurface_list(&mut self) {
let _ = crate::subsurface_widget::take_subsurfaces();
}
pub(crate) fn update_subsurfaces(
&mut self,
id: window::Id,
wl_surface: &WlSurface,
) {
let subsurfaces = crate::subsurface_widget::take_subsurfaces();
let entry = self.surface_subsurfaces.entry(id);
let surface_subsurfaces = entry.or_default();
let Some(subsurface_state) = self.subsurface_state.as_mut() else {
return;
};
subsurface_state.update_subsurfaces(
wl_surface,
surface_subsurfaces,
&subsurfaces,
);
}
pub(crate) fn create_surface(
&mut self,
) -> Option<Box<dyn HasWindowHandle + Send + Sync + 'static>> {
if let Some(subsurface_state) = self.subsurface_state.as_mut() {
let wl_surface = subsurface_state.create_surface();
Some(Box::new(Window(wl_surface)))
} else {
None
}
}
pub(crate) fn update_surface_shm(
&mut self,
window: &dyn HasWindowHandle,
width: u32,
height: u32,
scale: f64,
data: &[u8],
offset: Vector,
) {
if let Some(subsurface_state) = self.subsurface_state.as_mut() {
if let RawWindowHandle::Wayland(window) =
window.window_handle().unwrap().as_raw()
{
let id = unsafe {
ObjectId::from_ptr(
WlSurface::interface(),
window.surface.as_ptr().cast(),
)
.unwrap()
};
let surface =
WlSurface::from_id(self.conn.as_ref().unwrap(), id)
.unwrap();
subsurface_state.update_surface_shm(
&surface, width, height, scale, data, offset,
);
}
}
}
}
struct Window(WlSurface);
impl HasWindowHandle for Window {
fn window_handle(
&self,
) -> Result<
raw_window_handle::WindowHandle<'_>,
raw_window_handle::HandleError,
> {
Ok(unsafe {
raw_window_handle::WindowHandle::borrow_raw(
raw_window_handle::RawWindowHandle::Wayland(
raw_window_handle::WaylandWindowHandle::new(
std::ptr::NonNull::new(self.0.id().as_ptr() as *mut _)
.unwrap(),
),
),
)
})
}
}
impl Drop for Window {
fn drop(&mut self) {
self.0.destroy();
}
}