153 lines
4.1 KiB
Rust
153 lines
4.1 KiB
Rust
use super::{
|
|
state::{ClientState, WaylandState},
|
|
utils::{ChildInfoExt, WlSurfaceExt},
|
|
xdg_shell::surface_panel_item,
|
|
};
|
|
use crate::{
|
|
nodes::items::panel::{ChildInfo, Geometry, SurfaceId},
|
|
wayland::surface::CoreSurface,
|
|
};
|
|
use parking_lot::Mutex;
|
|
use rand::Rng;
|
|
use smithay::{
|
|
backend::renderer::utils::{RendererSurfaceStateUserData, on_commit_buffer_handler},
|
|
delegate_compositor,
|
|
desktop::PopupKind,
|
|
reexports::wayland_server::{Client, protocol::wl_surface::WlSurface},
|
|
wayland::compositor::{
|
|
CompositorClientState, CompositorHandler, CompositorState, add_post_commit_hook,
|
|
},
|
|
};
|
|
use std::sync::Arc;
|
|
use tracing::{debug, warn};
|
|
|
|
pub struct ConfiguredSurface;
|
|
|
|
impl CompositorHandler for WaylandState {
|
|
fn compositor_state(&mut self) -> &mut CompositorState {
|
|
&mut self.compositor_state
|
|
}
|
|
|
|
fn commit(&mut self, surface: &WlSurface) {
|
|
debug!(?surface, "Surface commit");
|
|
|
|
on_commit_buffer_handler::<WaylandState>(surface);
|
|
|
|
if let Some(toplevel) = self
|
|
.xdg_shell
|
|
.toplevel_surfaces()
|
|
.iter()
|
|
.find(|s| s.wl_surface() == surface)
|
|
{
|
|
if !toplevel.is_initial_configure_sent() {
|
|
debug!("Sending initial configure for toplevel surface");
|
|
toplevel.send_configure();
|
|
surface.insert_data(ConfiguredSurface);
|
|
}
|
|
}
|
|
|
|
self.popup_manager.commit(surface);
|
|
if let Some(PopupKind::Xdg(popup)) = self.popup_manager.find_popup(surface) {
|
|
if surface.insert_data(ConfiguredSurface) {
|
|
debug!("Configuring popup surface");
|
|
let _ = popup.send_configure();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
|
|
&client.get_data::<ClientState>().unwrap().compositor_state
|
|
}
|
|
|
|
fn new_subsurface(&mut self, surface: &WlSurface, parent: &WlSurface) {
|
|
let id = rand::thread_rng().gen_range(0..u64::MAX);
|
|
surface.insert_data(SurfaceId::Child(id));
|
|
CoreSurface::add_to(surface);
|
|
let Some(parent_surface_id) = parent.get_data::<SurfaceId>() else {
|
|
warn!("Parent surface has no SurfaceId");
|
|
return;
|
|
};
|
|
surface.insert_data(Mutex::new(ChildInfo {
|
|
id,
|
|
parent: parent_surface_id,
|
|
geometry: Geometry {
|
|
origin: [0; 2].into(),
|
|
size: [256; 2].into(),
|
|
},
|
|
z_order: 1,
|
|
receives_input: false,
|
|
}));
|
|
|
|
let Some(panel_item) = surface_panel_item(parent) else {
|
|
warn!("Parent has no panel item");
|
|
return;
|
|
};
|
|
let panel_item_weak = Arc::downgrade(&panel_item);
|
|
add_post_commit_hook(surface, move |_: &mut WaylandState, _dh, surf| {
|
|
if surface_panel_item(surf).is_some() {
|
|
return;
|
|
}
|
|
debug!("Linking surface to panel item");
|
|
surf.insert_data(panel_item_weak.clone());
|
|
|
|
let Some(panel_item) = surface_panel_item(surf) else {
|
|
warn!("Failed to link surface to panel item");
|
|
return;
|
|
};
|
|
|
|
surf.with_child_info(|_info| {
|
|
panel_item.backend.reposition_child(surf);
|
|
});
|
|
|
|
debug!("Adding new child to panel item");
|
|
panel_item.backend.new_child(surf);
|
|
});
|
|
|
|
add_post_commit_hook(surface, move |_: &mut WaylandState, _dh, surf| {
|
|
let Some(view) = surf
|
|
.get_data_raw::<RendererSurfaceStateUserData, _, _>(|s| s.lock().ok()?.view())
|
|
.flatten()
|
|
else {
|
|
debug!("No view data for surface");
|
|
return;
|
|
};
|
|
let mut changed = false;
|
|
surf.with_child_info(|info| {
|
|
if info.geometry.origin.x != view.offset.x
|
|
&& info.geometry.origin.y != view.offset.y
|
|
{
|
|
changed = true;
|
|
debug!("Surface position changed");
|
|
}
|
|
if info.geometry.size.x != view.dst.w as u32
|
|
&& info.geometry.size.y != view.dst.h as u32
|
|
{
|
|
changed = true;
|
|
debug!("Surface size changed");
|
|
}
|
|
info.geometry.size = [view.dst.w as u32, view.dst.h as u32].into();
|
|
});
|
|
|
|
let Some(panel_item) = surface_panel_item(surf) else {
|
|
return;
|
|
};
|
|
if changed {
|
|
debug!("Repositioning child due to geometry change");
|
|
panel_item.backend.reposition_child(surf);
|
|
}
|
|
});
|
|
}
|
|
|
|
fn destroyed(&mut self, surface: &WlSurface) {
|
|
let Some(panel_item) = surface_panel_item(surface) else {
|
|
return;
|
|
};
|
|
if surface.get_child_info().is_some() {
|
|
debug!("Dropping destroyed child surface");
|
|
panel_item.backend.drop_child(surface);
|
|
}
|
|
}
|
|
}
|
|
|
|
delegate_compositor!(WaylandState);
|