use smithay_client_toolkit::reexports::calloop::{EventLoop, LoopHandle}; use smithay_client_toolkit::reexports::calloop_wayland_source::WaylandSource; use smithay_client_toolkit::{ activation::{ActivationState, ActivationHandler, RequestData}, compositor::{CompositorState, CompositorHandler}, output::{OutputHandler, OutputState}, registry::{RegistryState, ProvidesRegistryState}, registry_handlers, seat::{ pointer::{PointerEvent, PointerEventKind, PointerHandler}, SeatState, SeatHandler, Capability }, shell::{ xdg::{ window::{WindowHandler, Window, WindowConfigure, WindowDecorations}, XdgShell, }, WaylandSurface, }, shm::{ slot::{SlotPool, Buffer}, Shm, ShmHandler }, delegate_registry, delegate_compositor, delegate_seat, delegate_output, delegate_xdg_shell, delegate_shm, delegate_activation, delegate_xdg_window, delegate_pointer, }; use wayland_client::{ Connection, QueueHandle, globals::registry_queue_init, protocol::{wl_surface, wl_output, wl_seat, wl_shm, wl_pointer}, }; use std::time::Duration; use rten_tensor::NdTensor; use anyhow::Result; use crate::wayland::{ draw::{DrawPath, Draw}, builder::{TextAreaBuilder, DrawAreaBuilder, ButtonBuilder}, ui::{self, Widget, ButtonType}, Position, }; use crate::process_point::print_words; const WINDOW_HEIGHT: usize = 256; const WINDOW_WIDTH: usize = 512; pub(crate) struct SimpleWindow { registry_state: RegistryState, seat_state: SeatState, output_state: OutputState, shm: Shm, xdg_activation: Option, buffer: Option, pool: SlotPool, window: Window, ui: Option, width: usize, height: usize, cursor_down: bool, exit: bool, first_configure: bool, pointer: Option, _loop_handle: LoopHandle<'static, SimpleWindow>, draw_path: DrawPath, } impl SimpleWindow { pub(crate) fn run() -> Result<()> { let conn = Connection::connect_to_env()?; let (globals, event_queue) = registry_queue_init(&conn)?; let qh = event_queue.handle(); let mut event_loop: EventLoop:: = EventLoop::try_new()?; let loop_handle = event_loop.handle(); WaylandSource::new(conn.clone(), event_queue).insert(loop_handle)?; let compositor = CompositorState::bind(&globals, &qh)?; let xdg_shell = XdgShell::bind(&globals, &qh)?; let shm = Shm::bind(&globals, &qh)?; let xdg_activation = ActivationState::bind(&globals, &qh).ok(); let surface = compositor.create_surface(&qh); let window = xdg_shell.create_window(surface, WindowDecorations::RequestServer, &qh); window.set_title("A window"); window.set_app_id("simmer.simplewindow"); window.set_min_size(Some((WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32))); window.set_max_size(Some((WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32))); window.commit(); if let Some(activation) = xdg_activation.as_ref() { activation.request_token( &qh, RequestData { seat_and_serial: None, surface: Some(window.wl_surface().clone()), app_id: Some(String::from("simmer.waywrite")), }, ) } let pool = SlotPool::new((WINDOW_WIDTH as usize) * (WINDOW_HEIGHT as usize) * 4, &shm)?; let mut simple_window = SimpleWindow { registry_state: RegistryState::new(&globals), seat_state: SeatState::new(&globals, &qh), output_state: OutputState::new(&globals, &qh), xdg_activation, shm, buffer: None, pool, window, ui: None, width: WINDOW_WIDTH, height: WINDOW_HEIGHT, cursor_down: false, exit: false, first_configure: true, pointer: None, _loop_handle: event_loop.handle(), draw_path: DrawPath::new(), }; loop { event_loop.dispatch(Duration::from_millis(16), &mut simple_window)?; if simple_window.exit { println!("exiting"); break; } } Ok(()) } } impl CompositorHandler for SimpleWindow { fn scale_factor_changed( &mut self, _: &Connection, _: &QueueHandle, _: &wl_surface::WlSurface, _: i32) {} fn transform_changed( &mut self, _: &Connection, _: &QueueHandle, _: &wl_surface::WlSurface, _: wl_output::Transform) {} fn frame( &mut self, conn: &Connection, qh: &QueueHandle, _: &wl_surface::WlSurface, _: u32 ) { self.draw(conn, qh); } } impl SeatHandler for SimpleWindow { fn seat_state(&mut self) -> &mut SeatState { &mut self.seat_state } fn new_seat( &mut self, _: &Connection, _: &QueueHandle, _: wl_seat::WlSeat ) {} fn new_capability( &mut self, _: &Connection, qh: &QueueHandle, seat: wl_seat::WlSeat, capability: Capability, ) { if capability == Capability::Pointer && self.pointer.is_none() { println!("Set pointer capability"); let pointer = self.seat_state.get_pointer(qh, &seat).expect("Failed to create pointer"); self.pointer = Some(pointer); } } fn remove_capability( &mut self, _: &Connection, _: &QueueHandle, _: wl_seat::WlSeat, capability: Capability, ) { if capability == Capability::Pointer && self.pointer.is_some() { println!("Unset pointer capability"); self.pointer.take().unwrap().release(); } } fn remove_seat( &mut self, _: &Connection, _: &QueueHandle, _: wl_seat::WlSeat, ) {} } impl OutputHandler for SimpleWindow { fn output_state(&mut self) -> &mut OutputState { &mut self.output_state } fn new_output( &mut self, _: &Connection, _: &QueueHandle, _: wl_output::WlOutput, ) {} fn update_output( &mut self, _: &Connection, _: &QueueHandle, _: wl_output::WlOutput, ) {} fn output_destroyed( &mut self, _: &Connection, _: &QueueHandle, _: wl_output::WlOutput, ) {} } impl WindowHandler for SimpleWindow { fn request_close( &mut self, _: &Connection, _: &QueueHandle, _: &Window ) { self.exit = true; } fn configure( &mut self, conn: &Connection, qh: &QueueHandle, _: &Window, _: WindowConfigure, _: u32, ) { if self.first_configure { self.first_configure = false; self.draw(conn, qh); } if self.ui.is_none() { let mut draw_area = DrawAreaBuilder::new(); draw_area.position(0.0, 50.0); draw_area.width(self.width - 100); draw_area.height(self.height - 50); draw_area.path(&mut self.draw_path); let draw_area = draw_area.finish(); let mut window = ui::Window::new( self.width.try_into().unwrap(), self.height.try_into().unwrap(), draw_area, ); let mut enter_button = ButtonBuilder::new(); enter_button.button_type(ButtonType::Enter); enter_button.position(self.width - 100, 60); enter_button.width(100); enter_button.height(50); let enter_button = enter_button.finish(); let mut clear_button = ButtonBuilder::new(); clear_button.button_type(ButtonType::Clear); clear_button.position(self.width - 100, 120); clear_button.width(100); clear_button.height(50); let clear_button = clear_button.finish(); let mut text_area = TextAreaBuilder::new(); text_area.position(0.0, 0.0); text_area.width(self.width); text_area.height(50); let text_area = text_area.finish(); window.add_widget(enter_button); window.add_widget(clear_button); window.add_widget(text_area); self.ui = Some(window); } } } impl ShmHandler for SimpleWindow { fn shm_state(&mut self) -> &mut Shm { &mut self.shm } } impl ActivationHandler for SimpleWindow { type RequestData = RequestData; fn new_token(&mut self, token: String, _: &Self::RequestData) { self.xdg_activation .as_ref() .unwrap() .activate::(self.window.wl_surface(), token); } } impl PointerHandler for SimpleWindow { fn pointer_frame( &mut self, _conn: &Connection, _qh: &QueueHandle, _pointer: &wl_pointer::WlPointer, events: &[PointerEvent], ) { use PointerEventKind::*; for event in events { // Ignore events for other surfaces if &event.surface != self.window.wl_surface() { continue; } match event.kind { Enter { .. } => { println!("Pointer entered @{:?}", event.position); } Leave { .. } => { println!("Pointer left"); } Motion { .. } => { if self.cursor_down { if let Some(window) = &mut self.ui { let pos = Position::new(event.position.0 as f32, event.position.1 as f32); if window.draw_area.contains_point(pos) { window.draw_area.path.add_point(pos, false); } } } } Press { button, .. } => { println!("Press {:x} @ {:?}", button, event.position); self.cursor_down = true; if let Some(window) = &mut self.ui { let pos = Position::new(event.position.0 as f32, event.position.1 as f32); if window.draw_area.contains_point(pos) { window.draw_area.path.add_point(pos, true); } for button in window.widgets .iter() .filter_map(|widget| { if let Widget::Button(button) = widget { Some(button) } else { None } }) { match button.button_type { ButtonType::Clear if button.contains_point(pos) => { window.draw_area.path = DrawPath::default(); }, ButtonType::Enter if button.contains_point(pos) => { print_words((&window.draw_area).into()).unwrap() }, _ => (), } } } } Release { button, .. } => { println!("Release {:x} @ {:?}", button, event.position); self.cursor_down = false; if let Some(window) = &mut self.ui { let pos = Position::new(event.position.0 as f32, event.position.1 as f32); if window.draw_area.contains_point(pos) { window.draw_area.path.add_point(pos, false); } else { println!("Does not contain point") } } } Axis { horizontal, vertical, .. } => { println!("Scroll H:{horizontal:?}, V:{vertical:?}"); } } } } } impl SimpleWindow { fn draw(&mut self, _: &Connection, qh: &QueueHandle) { let buffer = self.buffer.get_or_insert_with(|| { self.pool .create_buffer(self.width as i32, self.height as i32, (self.width as i32) * 4, wl_shm::Format::Argb8888) .expect("create buffer") .0 }); let canvas = match self.pool.canvas(buffer) { Some(canvas) => canvas, None => { let (second_buffer, canvas) = self .pool .create_buffer( self.width as i32, self.height as i32, (self.width as i32) * 4, wl_shm::Format::Argb8888, ) .expect("create buffer"); *buffer = second_buffer; canvas } }; if let Some(window) = &mut self.ui { window.render(canvas); } self.window.wl_surface().damage_buffer(0, 0, self.width as i32, self.height as i32); self.window.wl_surface().frame(qh, self.window.wl_surface().clone()); buffer.attach_to(self.window.wl_surface()).expect("buffer attach"); self.window.commit(); } } delegate_compositor!(SimpleWindow); delegate_output!(SimpleWindow); delegate_shm!(SimpleWindow); delegate_seat!(SimpleWindow); delegate_xdg_shell!(SimpleWindow); delegate_xdg_window!(SimpleWindow); delegate_activation!(SimpleWindow); delegate_pointer!(SimpleWindow); delegate_registry!(SimpleWindow); impl ProvidesRegistryState for SimpleWindow { fn registry(&mut self) -> &mut RegistryState { &mut self.registry_state } registry_handlers![OutputState, SeatState,]; }