feat: subsurfaces

This commit is contained in:
Ashley Wulber 2025-03-14 11:16:25 -04:00 committed by Ashley Wulber
parent 0f37c9922d
commit 93bc4bbd88
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
33 changed files with 1898 additions and 2651 deletions

View file

@ -7,6 +7,7 @@ use crate::core::{
widget::{self, Widget},
};
use std::{
borrow::BorrowMut,
cell::RefCell,
collections::HashMap,
fmt::Debug,
@ -55,6 +56,7 @@ use wayland_protocols::wp::{
wp_viewport::WpViewport, wp_viewporter::WpViewporter,
},
};
use winit::window::WindowId;
use crate::platform_specific::{
SurfaceIdWrapper, event_loop::state::SctkState,
@ -364,7 +366,15 @@ pub struct SubsurfaceState {
pub wp_alpha_modifier: Option<WpAlphaModifierV1>,
pub qh: QueueHandle<SctkState>,
pub(crate) buffers: HashMap<WeakBufferSource, Vec<WlBuffer>>,
pub unmapped_subsurfaces: Vec<SubsurfaceInstance>,
pub(crate) unmapped_subsurfaces: Vec<SubsurfaceInstance>,
pub new_iced_subsurfaces: Vec<(
window::Id,
ObjectId,
window::Id,
WlSubsurface,
WlSurface,
u32,
)>,
}
impl SubsurfaceState {
@ -446,6 +456,8 @@ impl SubsurfaceState {
wl_buffer: None,
bounds: None,
transform: wl_output::Transform::Normal,
z: 0,
parent: parent.id(),
}
}
@ -461,6 +473,14 @@ impl SubsurfaceState {
//
// They should be safe to destroy by the next time `update_subsurfaces`
// is run.
ICED_SUBSURFACES.with_borrow_mut(|surfaces| {
surfaces.retain(|s| {
!self
.unmapped_subsurfaces
.iter()
.any(|unmapped| unmapped.wl_surface == s.4)
})
});
self.unmapped_subsurfaces.clear();
// Remove cached `wl_buffers` for any `BufferSource`s that no longer exist.
@ -479,11 +499,61 @@ impl SubsurfaceState {
subsurface.unmap();
self.unmapped_subsurfaces.push(subsurface);
}
let needs_sorting = subsurfaces.len() < view_subsurfaces.len()
|| !self.new_iced_subsurfaces.is_empty();
// Create new subsurfaces if there aren't enough.
while subsurfaces.len() < view_subsurfaces.len() {
subsurfaces.push(self.create_subsurface(parent));
}
// Attach buffers to subsurfaces, set viewports, and commit.
if needs_sorting {
let mut sorted_subsurfaces: Vec<_> = view_subsurfaces
.iter()
.zip(subsurfaces.iter_mut())
.map(|(_, instance)| {
(
instance.parent.clone(),
instance.wl_subsurface.clone(),
instance.wl_surface.clone(),
instance.z,
)
})
.chain(self.new_iced_subsurfaces.clone().into_iter().map(
|(_, parent, _, wl_subsurface, wl_surface, z)| {
(parent.clone(), wl_subsurface, wl_surface, z)
},
))
.chain(ICED_SUBSURFACES.with(|surfaces| {
let b = surfaces.borrow();
let v: Vec<_> = b
.iter()
.map(move |s| {
(s.1.clone(), s.3.clone(), s.4.clone(), s.5)
})
.collect();
v.into_iter()
}))
.collect();
sorted_subsurfaces.sort_by(|a, b| a.3.cmp(&b.3));
// Attach buffers to subsurfaces, set viewports, and commit.
for i in 1..sorted_subsurfaces.len() {
let prev = &sorted_subsurfaces[0..i];
let subsurface = &sorted_subsurfaces[i];
for prev in prev.iter().rev() {
if prev.0 != subsurface.0 {
continue;
}
subsurface.1.place_above(&prev.2);
}
}
}
if !self.new_iced_subsurfaces.is_empty() {
ICED_SUBSURFACES.with(|surfaces| {
surfaces.borrow_mut().append(&mut self.new_iced_subsurfaces);
})
};
for (subsurface_data, subsurface) in
view_subsurfaces.iter().zip(subsurfaces.iter_mut())
{
@ -540,12 +610,14 @@ impl Drop for SubsurfaceState {
#[derive(Clone, Debug)]
pub(crate) struct SubsurfaceInstance {
pub(crate) wl_surface: WlSurface,
wl_subsurface: WlSubsurface,
wp_viewport: WpViewport,
wp_alpha_modifier_surface: Option<WpAlphaModifierSurfaceV1>,
wl_buffer: Option<WlBuffer>,
bounds: Option<Rectangle<f32>>,
transform: wl_output::Transform,
pub(crate) wl_subsurface: WlSubsurface,
pub(crate) wp_viewport: WpViewport,
pub(crate) wp_alpha_modifier_surface: Option<WpAlphaModifierSurfaceV1>,
pub(crate) wl_buffer: Option<WlBuffer>,
pub(crate) bounds: Option<Rectangle<f32>>,
pub(crate) transform: wl_output::Transform,
pub(crate) z: u32,
pub parent: ObjectId,
}
impl SubsurfaceInstance {
@ -621,6 +693,7 @@ impl SubsurfaceInstance {
self.wl_buffer = Some(buffer);
self.bounds = Some(info.bounds);
self.transform = info.transform;
self.z = info.z;
}
pub fn unmap(&self) {
@ -646,16 +719,46 @@ pub(crate) struct SubsurfaceInfo {
pub bounds: Rectangle<f32>,
pub alpha: f32,
pub transform: wl_output::Transform,
pub z: u32,
}
thread_local! {
static SUBSURFACES: RefCell<Vec<SubsurfaceInfo>> = RefCell::new(Vec::new());
static ICED_SUBSURFACES: RefCell<Vec<(window::Id, ObjectId, window::Id, WlSubsurface, WlSurface, u32)>> = RefCell::new(Vec::new());
}
pub(crate) fn take_subsurfaces() -> Vec<SubsurfaceInfo> {
SUBSURFACES.with(|subsurfaces| mem::take(&mut *subsurfaces.borrow_mut()))
}
pub(crate) fn subsurface_ids(parent: WindowId) -> Vec<WindowId> {
ICED_SUBSURFACES.with(|subsurfaces| {
subsurfaces
.borrow_mut()
.iter()
.filter_map(|s| {
if winit::window::WindowId::from_raw(s.1.as_ptr() as usize)
== parent
{
Some(winit::window::WindowId::from_raw(
s.4.id().as_ptr() as usize
))
} else {
None
}
})
.collect()
})
}
pub(crate) fn remove_iced_subsurface(surface: &WlSurface) {
ICED_SUBSURFACES.with(|surfaces| {
surfaces
.borrow_mut()
.retain(|(_, _, _, _, s, _)| s != surface)
})
}
#[must_use]
pub struct Subsurface {
buffer: SubsurfaceBuffer,
@ -664,6 +767,7 @@ pub struct Subsurface {
content_fit: ContentFit,
alpha: f32,
transform: wl_output::Transform,
pub z: u32,
}
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Subsurface
@ -729,6 +833,7 @@ where
bounds: layout.bounds(),
alpha: self.alpha,
transform: self.transform,
z: self.z,
})
});
}
@ -744,6 +849,7 @@ impl Subsurface {
content_fit: ContentFit::Contain,
alpha: 1.,
transform: wl_output::Transform::Normal,
z: 0,
}
}
@ -767,6 +873,11 @@ impl Subsurface {
self
}
pub fn z(mut self, z: u32) -> Self {
self.z = z;
self
}
pub fn transform(mut self, transform: wl_output::Transform) -> Self {
self.transform = transform;
self