use std::{os::unix::io::OwnedFd, sync::Arc}; use ::winit::platform::pump_events::PumpStatus; use smithay::{ backend::{ input::{InputEvent, KeyboardKeyEvent}, renderer::{ element::{ surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, Kind, }, gles::GlesRenderer, utils::{draw_render_elements, on_commit_buffer_handler}, Color32F, Frame, Renderer, }, winit::{self, WinitEvent}, }, delegate_compositor, delegate_data_device, delegate_seat, delegate_shm, delegate_xdg_shell, input::{keyboard::FilterResult, Seat, SeatHandler, SeatState}, reexports::wayland_server::{protocol::wl_seat, Display}, utils::{Rectangle, Serial, Transform}, wayland::{ buffer::BufferHandler, compositor::{ with_surface_tree_downward, CompositorClientState, CompositorHandler, CompositorState, SurfaceAttributes, TraversalAction, }, selection::{ data_device::{ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler}, SelectionHandler, }, shell::xdg::{PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState}, shm::{ShmHandler, ShmState}, }, }; use wayland_protocols::xdg::shell::server::xdg_toplevel; use wayland_server::{ backend::{ClientData, ClientId, DisconnectReason}, protocol::{ wl_buffer, wl_surface::{self, WlSurface}, }, Client, ListeningSocket, }; impl BufferHandler for App { fn buffer_destroyed(&mut self, _buffer: &wl_buffer::WlBuffer) {} } impl XdgShellHandler for App { fn xdg_shell_state(&mut self) -> &mut XdgShellState { &mut self.xdg_shell_state } fn new_toplevel(&mut self, surface: ToplevelSurface) { surface.with_pending_state(|state| { state.states.set(xdg_toplevel::State::Activated); }); surface.send_configure(); } fn new_popup(&mut self, _surface: PopupSurface, _positioner: PositionerState) { // Handle popup creation here } fn grab(&mut self, _surface: PopupSurface, _seat: wl_seat::WlSeat, _serial: Serial) { // Handle popup grab here } fn reposition_request(&mut self, _surface: PopupSurface, _positioner: PositionerState, _token: u32) { // Handle popup reposition here } } impl SelectionHandler for App { type SelectionUserData = (); } impl DataDeviceHandler for App { fn data_device_state(&self) -> &DataDeviceState { &self.data_device_state } } impl ClientDndGrabHandler for App {} impl ServerDndGrabHandler for App { fn send(&mut self, _mime_type: String, _fd: OwnedFd, _seat: Seat) {} } impl CompositorHandler for App { 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); } } impl ShmHandler for App { fn shm_state(&self) -> &ShmState { &self.shm_state } } impl SeatHandler for App { type KeyboardFocus = WlSurface; type PointerFocus = WlSurface; type TouchFocus = WlSurface; fn seat_state(&mut self) -> &mut SeatState { &mut self.seat_state } fn focus_changed(&mut self, _seat: &Seat, _focused: Option<&WlSurface>) {} fn cursor_image(&mut self, _seat: &Seat, _image: smithay::input::pointer::CursorImageStatus) {} } struct App { compositor_state: CompositorState, xdg_shell_state: XdgShellState, shm_state: ShmState, seat_state: SeatState, data_device_state: DataDeviceState, seat: Seat, } fn main() -> Result<(), Box> { if let Ok(env_filter) = tracing_subscriber::EnvFilter::try_from_default_env() { tracing_subscriber::fmt().with_env_filter(env_filter).init(); } else { tracing_subscriber::fmt().init(); } run_winit() } pub fn run_winit() -> Result<(), Box> { let mut display: Display = Display::new()?; let dh = display.handle(); let compositor_state = CompositorState::new::(&dh); let shm_state = ShmState::new::(&dh, vec![]); let mut seat_state = SeatState::new(); let seat = seat_state.new_wl_seat(&dh, "winit"); let mut state = { App { compositor_state, xdg_shell_state: XdgShellState::new::(&dh), shm_state, seat_state, data_device_state: DataDeviceState::new::(&dh), seat, } }; let listener = ListeningSocket::bind("wayland-5").unwrap(); let mut clients = Vec::new(); let (mut backend, mut winit) = winit::init::()?; let start_time = std::time::Instant::now(); let keyboard = state.seat.add_keyboard(Default::default(), 200, 200).unwrap(); std::env::set_var("WAYLAND_DISPLAY", "wayland-5"); std::process::Command::new("weston-terminal").spawn().ok(); loop { let status = winit.dispatch_new_events(|event| match event { WinitEvent::Resized { .. } => {} WinitEvent::Input(event) => match event { InputEvent::Keyboard { event } => { keyboard.input::<(), _>( &mut state, event.key_code(), event.state(), 0.into(), 0, |_, _, _| { // FilterResult::Forward }, ); } InputEvent::PointerMotionAbsolute { .. } => { if let Some(surface) = state.xdg_shell_state.toplevel_surfaces().iter().next().cloned() { let surface = surface.wl_surface().clone(); keyboard.set_focus(&mut state, Some(surface), 0.into()); }; } _ => {} }, _ => (), }); match status { PumpStatus::Continue => (), PumpStatus::Exit(_) => return Ok(()), }; let size = backend.window_size(); let damage = Rectangle::from_size(size); { let (renderer, mut framebuffer) = backend.bind().unwrap(); let elements = state .xdg_shell_state .toplevel_surfaces() .iter() .flat_map(|surface| { render_elements_from_surface_tree( renderer, surface.wl_surface(), (0, 0), 1.0, 1.0, Kind::Unspecified, ) }) .collect::>>(); let mut frame = renderer .render(&mut framebuffer, size, Transform::Flipped180) .unwrap(); frame.clear(Color32F::new(0.1, 0.0, 0.0, 1.0), &[damage]).unwrap(); draw_render_elements(&mut frame, 1.0, &elements, &[damage]).unwrap(); // We rely on the nested compositor to do the sync for us let _ = frame.finish().unwrap(); for surface in state.xdg_shell_state.toplevel_surfaces() { send_frames_surface_tree(surface.wl_surface(), start_time.elapsed().as_millis() as u32); } if let Some(stream) = listener.accept()? { println!("Got a client: {:?}", stream); let client = display .handle() .insert_client(stream, Arc::new(ClientState::default())) .unwrap(); clients.push(client); } display.dispatch_clients(&mut state)?; display.flush_clients()?; } // It is important that all events on the display have been dispatched and flushed to clients before // swapping buffers because this operation may block. backend.submit(Some(&[damage])).unwrap(); } } pub fn send_frames_surface_tree(surface: &wl_surface::WlSurface, time: u32) { with_surface_tree_downward( surface, (), |_, _, &()| TraversalAction::DoChildren(()), |_surf, states, &()| { // the surface may not have any user_data if it is a subsurface and has not // yet been commited for callback in states .cached_state .get::() .current() .frame_callbacks .drain(..) { callback.done(time); } }, |_, _, &()| true, ); } #[derive(Default)] struct ClientState { compositor_state: CompositorClientState, } impl ClientData for ClientState { fn initialized(&self, _client_id: ClientId) { println!("initialized"); } fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) { println!("disconnected"); } } // Macros used to delegate protocol handling to types in the app state. delegate_xdg_shell!(App); delegate_compositor!(App); delegate_shm!(App); delegate_seat!(App); delegate_data_device!(App);