feat: add nested Phase 0 compositor
This commit is contained in:
1 parent
aab447ef25
commit
475d433ec4
8 files changed
+2710
-2
No files matched your search
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user