feat: add nested Phase 0 compositor

This commit is contained in:
Samuel Onoja committed 2026-09-24 05:38:18 +01:00
1 parent aab447ef25
commit 475d433ec4
8 files changed
+2710 -2

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
use smithay::{
backend::renderer::utils::on_commit_buffer_handler,
reexports::wayland_server::{
Client,
protocol::{wl_buffer, wl_surface::WlSurface},
},
wayland::{
buffer::BufferHandler,
compositor::{
CompositorClientState, CompositorHandler, CompositorState, get_parent,
is_sync_subsurface,
},
shm::{ShmHandler, ShmState},
},
};
use super::xdg_shell;
use crate::{Ferese, state::ClientState};
impl CompositorHandler for Ferese {
fn compositor_state(&mut self) -> &mut CompositorState {
&mut self.compositor_state
}
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
&client
.get_data::<ClientState>()
.expect("all clients have Ferese client state")
.compositor_state
}
fn commit(&mut self, surface: &WlSurface) {
on_commit_buffer_handler::<Self>(surface);
if !is_sync_subsurface(surface) {
let mut root = surface.clone();
while let Some(parent) = get_parent(&root) {
root = parent;
}
if let Some(window) = self.space.elements().find(|window| {
window
.toplevel()
.is_some_and(|toplevel| toplevel.wl_surface() == &root)
}) {
window.on_commit();
}
}
xdg_shell::handle_commit(&mut self.popups, &self.space, surface);
}
}
impl BufferHandler for Ferese {
fn buffer_destroyed(&mut self, _buffer: &wl_buffer::WlBuffer) {}
}
impl ShmHandler for Ferese {
fn shm_state(&self) -> &ShmState {
&self.shm_state
}
}
+30
View File
@@ -0,0 +1,30 @@
mod compositor;
mod xdg_shell;
use smithay::{
input::{Seat, SeatHandler, SeatState, pointer::CursorImageStatus},
reexports::wayland_server::protocol::wl_surface::WlSurface,
wayland::output::OutputHandler,
};
use crate::Ferese;
impl SeatHandler for Ferese {
type KeyboardFocus = WlSurface;
type PointerFocus = WlSurface;
type TouchFocus = WlSurface;
fn seat_state(&mut self) -> &mut SeatState<Self> {
&mut self.seat_state
}
fn cursor_image(&mut self, _seat: &Seat<Self>, _image: CursorImageStatus) {}
}
impl OutputHandler for Ferese {}
smithay::delegate_compositor!(Ferese);
smithay::delegate_output!(Ferese);
smithay::delegate_seat!(Ferese);
smithay::delegate_shm!(Ferese);
smithay::delegate_xdg_shell!(Ferese);
+129
View File
@@ -0,0 +1,129 @@
use smithay::{
desktop::{
PopupKind, PopupManager, Space, Window, find_popup_root_surface, get_popup_toplevel_coords,
},
reexports::wayland_server::protocol::{wl_seat, wl_surface::WlSurface},
utils::Serial,
wayland::{
compositor::with_states,
shell::xdg::{
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
XdgToplevelSurfaceData,
},
},
};
use crate::Ferese;
impl XdgShellHandler for Ferese {
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
&mut self.xdg_shell_state
}
fn new_toplevel(&mut self, surface: ToplevelSurface) {
self.space
.map_element(Window::new_wayland_window(surface), (0, 0), true);
}
fn new_popup(&mut self, surface: PopupSurface, _positioner: PositionerState) {
self.unconstrain_popup(&surface);
if let Err(error) = self.popups.track_popup(PopupKind::Xdg(surface)) {
tracing::warn!(?error, "failed to track xdg popup");
}
}
fn reposition_request(
&mut self,
surface: PopupSurface,
positioner: PositionerState,
token: u32,
) {
surface.with_pending_state(|state| {
state.geometry = positioner.get_geometry();
state.positioner = positioner;
});
self.unconstrain_popup(&surface);
surface.send_repositioned(token);
}
fn move_request(&mut self, _: ToplevelSurface, _: wl_seat::WlSeat, _: Serial) {}
fn resize_request(
&mut self,
_: ToplevelSurface,
_: wl_seat::WlSeat,
_: Serial,
_: smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
) {
}
fn grab(&mut self, _: PopupSurface, _: wl_seat::WlSeat, _: Serial) {}
}
pub fn handle_commit(popups: &mut PopupManager, space: &Space<Window>, surface: &WlSurface) {
if let Some(window) = space
.elements()
.find(|window| {
window
.toplevel()
.is_some_and(|toplevel| toplevel.wl_surface() == surface)
})
.cloned()
{
let configured = with_states(surface, |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("xdg toplevel state exists")
.lock()
.expect("xdg toplevel state is not poisoned")
.initial_configure_sent
});
if !configured {
window
.toplevel()
.expect("mapped window has a toplevel")
.send_configure();
}
}
popups.commit(surface);
if let Some(PopupKind::Xdg(popup)) = popups.find_popup(surface)
&& !popup.is_initial_configure_sent()
{
popup
.send_configure()
.expect("initial popup configure is valid");
}
}
impl Ferese {
fn unconstrain_popup(&self, popup: &PopupSurface) {
let Ok(root) = find_popup_root_surface(&PopupKind::Xdg(popup.clone())) else {
return;
};
let Some(window) = self.space.elements().find(|window| {
window
.toplevel()
.is_some_and(|toplevel| toplevel.wl_surface() == &root)
}) else {
return;
};
let Some(output) = self.space.outputs().next() else {
return;
};
let Some(output_geometry) = self.space.output_geometry(output) else {
return;
};
let Some(window_geometry) = self.space.element_geometry(window) else {
return;
};
let mut target = output_geometry;
target.loc -= get_popup_toplevel_coords(&PopupKind::Xdg(popup.clone()));
target.loc -= window_geometry.loc;
popup.with_pending_state(|state| {
state.geometry = state.positioner.get_unconstrained_geometry(target);
});
}
}