473 lines
14 KiB
Rust
473 lines
14 KiB
Rust
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<ActivationState>,
|
|
|
|
buffer: Option<Buffer>,
|
|
pool: SlotPool,
|
|
window: Window,
|
|
ui: Option<ui::Window>,
|
|
width: usize,
|
|
height: usize,
|
|
cursor_down: bool,
|
|
exit: bool,
|
|
first_configure: bool,
|
|
pointer: Option<wl_pointer::WlPointer>,
|
|
_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::<SimpleWindow> =
|
|
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<Self>,
|
|
_: &wl_surface::WlSurface,
|
|
_: i32) {}
|
|
fn transform_changed(
|
|
&mut self,
|
|
_: &Connection,
|
|
_: &QueueHandle<Self>,
|
|
_: &wl_surface::WlSurface,
|
|
_: wl_output::Transform) {}
|
|
fn frame(
|
|
&mut self,
|
|
conn: &Connection,
|
|
qh: &QueueHandle<Self>,
|
|
_: &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<Self>,
|
|
_: wl_seat::WlSeat
|
|
) {}
|
|
fn new_capability(
|
|
&mut self,
|
|
_: &Connection,
|
|
qh: &QueueHandle<Self>,
|
|
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<Self>,
|
|
_: 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<Self>,
|
|
_: 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<Self>,
|
|
_: wl_output::WlOutput,
|
|
) {}
|
|
fn update_output(
|
|
&mut self,
|
|
_: &Connection,
|
|
_: &QueueHandle<Self>,
|
|
_: wl_output::WlOutput,
|
|
) {}
|
|
fn output_destroyed(
|
|
&mut self,
|
|
_: &Connection,
|
|
_: &QueueHandle<Self>,
|
|
_: wl_output::WlOutput,
|
|
) {}
|
|
}
|
|
|
|
impl WindowHandler for SimpleWindow {
|
|
fn request_close(
|
|
&mut self,
|
|
_: &Connection,
|
|
_: &QueueHandle<Self>,
|
|
_: &Window
|
|
) {
|
|
self.exit = true;
|
|
}
|
|
|
|
fn configure(
|
|
&mut self,
|
|
conn: &Connection,
|
|
qh: &QueueHandle<Self>,
|
|
_: &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::<SimpleWindow>(self.window.wl_surface(), token);
|
|
}
|
|
}
|
|
|
|
impl PointerHandler for SimpleWindow {
|
|
fn pointer_frame(
|
|
&mut self,
|
|
_conn: &Connection,
|
|
_qh: &QueueHandle<Self>,
|
|
_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<Self>) {
|
|
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,];
|
|
}
|