From a941b80aa99bce0047f1b5d5219807704776b237 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 24 Sep 2026 05:41:38 +0100 Subject: [PATCH] feat: add selection and decoration protocols --- compositor/src/handlers/mod.rs | 44 ++++++++++++++++++++++++++-- compositor/src/handlers/xdg_shell.rs | 27 +++++++++++++++++ compositor/src/state.rs | 11 +++++++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/compositor/src/handlers/mod.rs b/compositor/src/handlers/mod.rs index 1192d76..12e9f84 100644 --- a/compositor/src/handlers/mod.rs +++ b/compositor/src/handlers/mod.rs @@ -3,8 +3,20 @@ mod xdg_shell; use smithay::{ input::{Seat, SeatHandler, SeatState, pointer::CursorImageStatus}, - reexports::wayland_server::protocol::wl_surface::WlSurface, - wayland::output::OutputHandler, + reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface}, + wayland::{ + output::OutputHandler, + selection::{ + SelectionHandler, + data_device::{ + ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler, + set_data_device_focus, + }, + primary_selection::{ + PrimarySelectionHandler, PrimarySelectionState, set_primary_focus, + }, + }, + }, }; use crate::Ferese; @@ -19,12 +31,40 @@ impl SeatHandler for Ferese { } fn cursor_image(&mut self, _seat: &Seat, _image: CursorImageStatus) {} + + fn focus_changed(&mut self, seat: &Seat, focused: Option<&WlSurface>) { + let client = focused.and_then(|surface| self.display_handle.get_client(surface.id()).ok()); + set_data_device_focus(&self.display_handle, seat, client.clone()); + set_primary_focus(&self.display_handle, seat, client); + } } impl OutputHandler for Ferese {} +impl SelectionHandler for Ferese { + type SelectionUserData = (); +} + +impl ClientDndGrabHandler for Ferese {} +impl ServerDndGrabHandler for Ferese {} + +impl DataDeviceHandler for Ferese { + fn data_device_state(&self) -> &DataDeviceState { + &self.data_device_state + } +} + +impl PrimarySelectionHandler for Ferese { + fn primary_selection_state(&self) -> &PrimarySelectionState { + &self.primary_selection_state + } +} + smithay::delegate_compositor!(Ferese); +smithay::delegate_data_device!(Ferese); smithay::delegate_output!(Ferese); +smithay::delegate_primary_selection!(Ferese); smithay::delegate_seat!(Ferese); smithay::delegate_shm!(Ferese); +smithay::delegate_xdg_decoration!(Ferese); smithay::delegate_xdg_shell!(Ferese); diff --git a/compositor/src/handlers/xdg_shell.rs b/compositor/src/handlers/xdg_shell.rs index adfecff..fb06d5a 100644 --- a/compositor/src/handlers/xdg_shell.rs +++ b/compositor/src/handlers/xdg_shell.rs @@ -2,10 +2,12 @@ use smithay::{ desktop::{ PopupKind, PopupManager, Space, Window, find_popup_root_surface, get_popup_toplevel_coords, }, + reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, reexports::wayland_server::protocol::{wl_seat, wl_surface::WlSurface}, utils::Serial, wayland::{ compositor::with_states, + shell::xdg::decoration::XdgDecorationHandler, shell::xdg::{ PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState, XdgToplevelSurfaceData, @@ -60,6 +62,31 @@ impl XdgShellHandler for Ferese { fn grab(&mut self, _: PopupSurface, _: wl_seat::WlSeat, _: Serial) {} } +impl XdgDecorationHandler for Ferese { + fn new_decoration(&mut self, toplevel: ToplevelSurface) { + set_decoration_mode(&toplevel, Mode::ClientSide); + } + + fn request_mode(&mut self, toplevel: ToplevelSurface, mode: Mode) { + // Phase 1 negotiates decorations but does not yet draw a server frame. + // Honor CSD and safely fall back to CSD for premature SSD requests. + let mode = match mode { + Mode::ClientSide | Mode::ServerSide => Mode::ClientSide, + _ => Mode::ClientSide, + }; + set_decoration_mode(&toplevel, mode); + } + + fn unset_mode(&mut self, toplevel: ToplevelSurface) { + set_decoration_mode(&toplevel, Mode::ClientSide); + } +} + +fn set_decoration_mode(toplevel: &ToplevelSurface, mode: Mode) { + toplevel.with_pending_state(|state| state.decoration_mode = Some(mode)); + toplevel.send_pending_configure(); +} + pub fn handle_commit(popups: &mut PopupManager, space: &Space, surface: &WlSurface) { if let Some(window) = space .elements() diff --git a/compositor/src/state.rs b/compositor/src/state.rs index a7f73b7..2b9e5a0 100644 --- a/compositor/src/state.rs +++ b/compositor/src/state.rs @@ -15,7 +15,9 @@ use smithay::{ wayland::{ compositor::{CompositorClientState, CompositorState}, output::OutputManagerState, + selection::{data_device::DataDeviceState, primary_selection::PrimarySelectionState}, shell::xdg::XdgShellState, + shell::xdg::decoration::XdgDecorationState, shm::ShmState, socket::ListeningSocketSource, }, @@ -30,7 +32,10 @@ pub struct Ferese { pub popups: PopupManager, pub seat: Seat, pub compositor_state: CompositorState, + pub data_device_state: DataDeviceState, + pub decoration_state: XdgDecorationState, pub output_manager_state: OutputManagerState, + pub primary_selection_state: PrimarySelectionState, pub seat_state: SeatState, pub shm_state: ShmState, pub xdg_shell_state: XdgShellState, @@ -44,8 +49,11 @@ impl Ferese { let display_handle = display.handle(); let compositor_state = CompositorState::new::(&display_handle); let xdg_shell_state = XdgShellState::new::(&display_handle); + let decoration_state = XdgDecorationState::new::(&display_handle); let shm_state = ShmState::new::(&display_handle, Vec::new()); let output_manager_state = OutputManagerState::new_with_xdg_output::(&display_handle); + let data_device_state = DataDeviceState::new::(&display_handle); + let primary_selection_state = PrimarySelectionState::new::(&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)?; @@ -61,7 +69,10 @@ impl Ferese { popups: PopupManager::default(), seat, compositor_state, + data_device_state, + decoration_state, output_manager_state, + primary_selection_state, seat_state, shm_state, xdg_shell_state,