From ad3c3f8cefd38d2bf26b466d8e34eccde3bca443 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Mon, 7 Aug 2023 19:44:40 +0400 Subject: Init from smallvil --- src/handlers/compositor.rs | 57 ++++++++++++++++ src/handlers/mod.rs | 54 +++++++++++++++ src/handlers/xdg_shell.rs | 163 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+) create mode 100644 src/handlers/compositor.rs create mode 100644 src/handlers/mod.rs create mode 100644 src/handlers/xdg_shell.rs (limited to 'src/handlers') diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs new file mode 100644 index 00000000..fcb0dc02 --- /dev/null +++ b/src/handlers/compositor.rs @@ -0,0 +1,57 @@ +use crate::{grabs::resize_grab, state::ClientState, Smallvil}; +use smithay::{ + backend::renderer::utils::on_commit_buffer_handler, + delegate_compositor, delegate_shm, + reexports::wayland_server::{ + protocol::{wl_buffer, wl_surface::WlSurface}, + Client, + }, + wayland::{ + buffer::BufferHandler, + compositor::{ + get_parent, is_sync_subsurface, CompositorClientState, CompositorHandler, CompositorState, + }, + shm::{ShmHandler, ShmState}, + }, +}; + +use super::xdg_shell; + +impl CompositorHandler for Smallvil { + 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::().unwrap().compositor_state + } + + fn commit(&mut self, surface: &WlSurface) { + on_commit_buffer_handler::(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(|w| w.toplevel().wl_surface() == &root) { + window.on_commit(); + } + }; + + xdg_shell::handle_commit(&self.space, surface); + resize_grab::handle_commit(&mut self.space, surface); + } +} + +impl BufferHandler for Smallvil { + fn buffer_destroyed(&mut self, _buffer: &wl_buffer::WlBuffer) {} +} + +impl ShmHandler for Smallvil { + fn shm_state(&self) -> &ShmState { + &self.shm_state + } +} + +delegate_compositor!(Smallvil); +delegate_shm!(Smallvil); diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs new file mode 100644 index 00000000..bc2cd23f --- /dev/null +++ b/src/handlers/mod.rs @@ -0,0 +1,54 @@ +mod compositor; +mod xdg_shell; + +use crate::Smallvil; + +// +// Wl Seat +// + +use smithay::input::{SeatHandler, SeatState}; +use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; +use smithay::wayland::data_device::{ClientDndGrabHandler, DataDeviceHandler, ServerDndGrabHandler}; +use smithay::{delegate_data_device, delegate_output, delegate_seat}; + +impl SeatHandler for Smallvil { + type KeyboardFocus = WlSurface; + type PointerFocus = WlSurface; + + fn seat_state(&mut self) -> &mut SeatState { + &mut self.seat_state + } + + fn cursor_image( + &mut self, + _seat: &smithay::input::Seat, + _image: smithay::input::pointer::CursorImageStatus, + ) { + } + fn focus_changed(&mut self, _seat: &smithay::input::Seat, _focused: Option<&WlSurface>) {} +} + +delegate_seat!(Smallvil); + +// +// Wl Data Device +// + +impl DataDeviceHandler for Smallvil { + type SelectionUserData = (); + fn data_device_state(&self) -> &smithay::wayland::data_device::DataDeviceState { + &self.data_device_state + } +} + +impl ClientDndGrabHandler for Smallvil {} +impl ServerDndGrabHandler for Smallvil {} + +delegate_data_device!(Smallvil); + +// +// Wl Output & Xdg Output +// + +delegate_output!(Smallvil); diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs new file mode 100644 index 00000000..7351d3bf --- /dev/null +++ b/src/handlers/xdg_shell.rs @@ -0,0 +1,163 @@ +use smithay::{ + delegate_xdg_shell, + desktop::{Space, Window}, + input::{ + pointer::{Focus, GrabStartData as PointerGrabStartData}, + Seat, + }, + reexports::{ + wayland_protocols::xdg::shell::server::xdg_toplevel, + wayland_server::{ + protocol::{wl_seat, wl_surface::WlSurface}, + Resource, + }, + }, + utils::{Rectangle, Serial}, + wayland::{ + compositor::with_states, + shell::xdg::{ + PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState, + XdgToplevelSurfaceData, + }, + }, +}; + +use crate::{ + grabs::{MoveSurfaceGrab, ResizeSurfaceGrab}, + Smallvil, +}; + +impl XdgShellHandler for Smallvil { + fn xdg_shell_state(&mut self) -> &mut XdgShellState { + &mut self.xdg_shell_state + } + + fn new_toplevel(&mut self, surface: ToplevelSurface) { + let window = Window::new(surface); + self.space.map_element(window, (0, 0), false); + } + + fn new_popup(&mut self, _surface: PopupSurface, _positioner: PositionerState) { + // TODO: Popup handling using PopupManager + } + + fn move_request(&mut self, surface: ToplevelSurface, seat: wl_seat::WlSeat, serial: Serial) { + let seat = Seat::from_resource(&seat).unwrap(); + + let wl_surface = surface.wl_surface(); + + if let Some(start_data) = check_grab(&seat, wl_surface, serial) { + let pointer = seat.get_pointer().unwrap(); + + let window = self + .space + .elements() + .find(|w| w.toplevel().wl_surface() == wl_surface) + .unwrap() + .clone(); + let initial_window_location = self.space.element_location(&window).unwrap(); + + let grab = MoveSurfaceGrab { + start_data, + window, + initial_window_location, + }; + + pointer.set_grab(self, grab, serial, Focus::Clear); + } + } + + fn resize_request( + &mut self, + surface: ToplevelSurface, + seat: wl_seat::WlSeat, + serial: Serial, + edges: xdg_toplevel::ResizeEdge, + ) { + let seat = Seat::from_resource(&seat).unwrap(); + + let wl_surface = surface.wl_surface(); + + if let Some(start_data) = check_grab(&seat, wl_surface, serial) { + let pointer = seat.get_pointer().unwrap(); + + let window = self + .space + .elements() + .find(|w| w.toplevel().wl_surface() == wl_surface) + .unwrap() + .clone(); + let initial_window_location = self.space.element_location(&window).unwrap(); + let initial_window_size = window.geometry().size; + + surface.with_pending_state(|state| { + state.states.set(xdg_toplevel::State::Resizing); + }); + + surface.send_pending_configure(); + + let grab = ResizeSurfaceGrab::start( + start_data, + window, + edges.into(), + Rectangle::from_loc_and_size(initial_window_location, initial_window_size), + ); + + pointer.set_grab(self, grab, serial, Focus::Clear); + } + } + + fn grab(&mut self, _surface: PopupSurface, _seat: wl_seat::WlSeat, _serial: Serial) { + // TODO popup grabs + } +} + +// Xdg Shell +delegate_xdg_shell!(Smallvil); + +fn check_grab( + seat: &Seat, + surface: &WlSurface, + serial: Serial, +) -> Option> { + let pointer = seat.get_pointer()?; + + // Check that this surface has a click grab. + if !pointer.has_grab(serial) { + return None; + } + + let start_data = pointer.grab_start_data()?; + + let (focus, _) = start_data.focus.as_ref()?; + // If the focus was for a different surface, ignore the request. + if !focus.id().same_client_as(&surface.id()) { + return None; + } + + Some(start_data) +} + +/// Should be called on `WlSurface::commit` +pub fn handle_commit(space: &Space, surface: &WlSurface) -> Option<()> { + let window = space + .elements() + .find(|w| w.toplevel().wl_surface() == surface) + .cloned()?; + + let initial_configure_sent = with_states(surface, |states| { + states + .data_map + .get::() + .unwrap() + .lock() + .unwrap() + .initial_configure_sent + }); + + if !initial_configure_sent { + window.toplevel().send_configure(); + } + + Some(()) +} -- cgit