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

+122
View File
@@ -0,0 +1,122 @@
use std::{error::Error, ffi::OsString, sync::Arc, time::Instant};
use smithay::{
desktop::{PopupManager, Space, Window, WindowSurfaceType},
input::{Seat, SeatState},
reexports::{
calloop::{EventLoop, Interest, LoopSignal, Mode, PostAction, generic::Generic},
wayland_server::{
Display, DisplayHandle,
backend::{ClientData, ClientId, DisconnectReason},
protocol::wl_surface::WlSurface,
},
},
utils::{Logical, Point},
wayland::{
compositor::{CompositorClientState, CompositorState},
output::OutputManagerState,
shell::xdg::XdgShellState,
shm::ShmState,
socket::ListeningSocketSource,
},
};
pub struct Ferese {
pub start_time: Instant,
pub socket_name: OsString,
pub display_handle: DisplayHandle,
pub loop_signal: LoopSignal,
pub space: Space<Window>,
pub popups: PopupManager,
pub seat: Seat<Self>,
pub compositor_state: CompositorState,
pub output_manager_state: OutputManagerState,
pub seat_state: SeatState<Self>,
pub shm_state: ShmState,
pub xdg_shell_state: XdgShellState,
}
impl Ferese {
pub fn new(
event_loop: &mut EventLoop<Self>,
display: Display<Self>,
) -> Result<Self, Box<dyn Error>> {
let display_handle = display.handle();
let compositor_state = CompositorState::new::<Self>(&display_handle);
let xdg_shell_state = XdgShellState::new::<Self>(&display_handle);
let shm_state = ShmState::new::<Self>(&display_handle, Vec::new());
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
let mut seat_state = SeatState::new();
let mut seat = seat_state.new_wl_seat(&display_handle, "ferese-winit");
seat.add_keyboard(Default::default(), 200, 25)?;
seat.add_pointer();
let socket_name = Self::init_wayland_listener(display, event_loop)?;
Ok(Self {
start_time: Instant::now(),
socket_name,
display_handle,
loop_signal: event_loop.get_signal(),
space: Space::default(),
popups: PopupManager::default(),
seat,
compositor_state,
output_manager_state,
seat_state,
shm_state,
xdg_shell_state,
})
}
fn init_wayland_listener(
display: Display<Self>,
event_loop: &mut EventLoop<Self>,
) -> Result<OsString, Box<dyn Error>> {
let listening_socket = ListeningSocketSource::new_auto()?;
let socket_name = listening_socket.socket_name().to_os_string();
let loop_handle = event_loop.handle();
loop_handle.insert_source(listening_socket, |client_stream, _, state| {
if let Err(error) = state
.display_handle
.insert_client(client_stream, Arc::new(ClientState::default()))
{
tracing::warn!(%error, "failed to register Wayland client");
}
})?;
loop_handle.insert_source(
Generic::new(display, Interest::READ, Mode::Level),
|_, display, state| {
// SAFETY: this event source owns the display for the loop lifetime.
unsafe { display.get_mut().dispatch_clients(state)? };
Ok(PostAction::Continue)
},
)?;
Ok(socket_name)
}
pub fn surface_under(
&self,
position: Point<f64, Logical>,
) -> Option<(WlSurface, Point<f64, Logical>)> {
self.space
.element_under(position)
.and_then(|(window, location)| {
window
.surface_under(position - location.to_f64(), WindowSurfaceType::ALL)
.map(|(surface, surface_location)| {
(surface, (surface_location + location).to_f64())
})
})
}
}
#[derive(Default)]
pub struct ClientState {
pub compositor_state: CompositorClientState,
}
impl ClientData for ClientState {
fn initialized(&self, _client_id: ClientId) {}
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {}
}