use std::convert::TryInto;
use smithay_client_toolkit::{
compositor::{CompositorHandler, CompositorState},
delegate_compositor, delegate_keyboard, delegate_output, delegate_pointer, delegate_registry,
delegate_seat, delegate_shm, delegate_xdg_shell, delegate_xdg_window,
output::{OutputHandler, OutputState},
registry::{ProvidesRegistryState, RegistryState},
registry_handlers,
seat::{
keyboard::{KeyEvent, KeyboardHandler, Modifiers, RawModifiers},
pointer::{PointerEvent, PointerEventKind, PointerHandler},
Capability, SeatHandler, SeatState,
},
shell::{
xdg::{
window::{Window, WindowConfigure, WindowDecorations, WindowHandler},
XdgShell,
},
WaylandSurface,
},
shm::{
slot::{Buffer, SlotPool},
Shm, ShmHandler,
},
};
use wayland_client::{
globals::registry_queue_init,
protocol::{wl_keyboard, wl_output, wl_pointer, wl_seat, wl_shm, wl_surface},
Connection, QueueHandle,
};
use xkeysym::Keysym;
fn main() {
env_logger::init();
let conn = Connection::connect_to_env().unwrap();
let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
let qh = event_queue.handle();
let compositor = CompositorState::bind(&globals, &qh).expect("wl_compositor not available");
let xdg_shell = XdgShell::bind(&globals, &qh).expect("xdg shell is not available");
let shm = Shm::bind(&globals, &qh).expect("wl shm is not available.");
let surface = compositor.create_surface(&qh);
let window = xdg_shell.create_window(surface, WindowDecorations::RequestServer, &qh);
window.set_title("A wayland window");
window.set_app_id("io.github.smithay.client-toolkit.SimpleWindow<T>");
window.set_min_size(Some((256, 256)));
window.commit();
let pool = SlotPool::new(256 * 256 * 4, &shm).expect("Failed to create pool");
let mut simple_window = SimpleWindow {
registry_state: RegistryState::new(&globals),
seat_state: SeatState::new(&globals, &qh),
output_state: OutputState::new(&globals, &qh),
shm,
exit: false,
first_configure: true,
pool,
width: 256,
height: 256,
shift: None,
buffer: None,
window,
keyboard: None,
keyboard_focus: false,
pointer: None,
_dummy: MyTest {},
};
loop {
event_queue.blocking_dispatch(&mut simple_window).unwrap();
if simple_window.exit {
println!("exiting example");
break;
}
}
}
pub trait Test {
fn test() {
println!("Test");
}
}
pub struct MyTest {}
impl Test for MyTest {}
struct SimpleWindow<T: Test + 'static> {
registry_state: RegistryState,
seat_state: SeatState,
output_state: OutputState,
shm: Shm,
exit: bool,
first_configure: bool,
pool: SlotPool,
width: u32,
height: u32,
shift: Option<u32>,
buffer: Option<Buffer>,
window: Window,
keyboard: Option<wl_keyboard::WlKeyboard>,
keyboard_focus: bool,
pointer: Option<wl_pointer::WlPointer>,
_dummy: T,
}
impl<T: Test + 'static> CompositorHandler for SimpleWindow<T> {
fn scale_factor_changed(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_new_factor: i32,
) {
}
fn transform_changed(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_new_transform: wl_output::Transform,
) {
}
fn frame(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_time: u32,
) {
self.draw(conn, qh);
}
fn surface_enter(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_output: &wl_output::WlOutput,
) {
}
fn surface_leave(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_surface: &wl_surface::WlSurface,
_output: &wl_output::WlOutput,
) {
}
}
impl<T: Test + 'static> OutputHandler for SimpleWindow<T> {
fn output_state(&mut self) -> &mut OutputState {
&mut self.output_state
}
fn new_output(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
fn update_output(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
fn output_destroyed(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_output: wl_output::WlOutput,
) {
}
}
impl<T: Test + 'static> WindowHandler for SimpleWindow<T> {
fn request_close(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &Window) {
self.exit = true;
}
fn configure(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
_window: &Window,
configure: WindowConfigure,
_serial: u32,
) {
self.buffer = None;
self.width = configure.new_size.0.map(|v| v.get()).unwrap_or(256);
self.height = configure.new_size.1.map(|v| v.get()).unwrap_or(256);
if self.first_configure {
self.first_configure = false;
self.draw(conn, qh);
}
}
}
impl<T: Test + 'static> SeatHandler for SimpleWindow<T> {
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,
_conn: &Connection,
qh: &QueueHandle<Self>,
seat: wl_seat::WlSeat,
capability: Capability,
) {
if capability == Capability::Keyboard && self.keyboard.is_none() {
println!("Set keyboard capability");
let keyboard =
self.seat_state.get_keyboard(qh, &seat, None).expect("Failed to create keyboard");
self.keyboard = Some(keyboard);
}
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,
_conn: &Connection,
_: &QueueHandle<Self>,
_: wl_seat::WlSeat,
capability: Capability,
) {
if capability == Capability::Keyboard && self.keyboard.is_some() {
println!("Unset keyboard capability");
self.keyboard.take().unwrap().release();
}
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<T: Test + 'static> KeyboardHandler for SimpleWindow<T> {
fn enter(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
surface: &wl_surface::WlSurface,
_: u32,
_: &[u32],
keysyms: &[Keysym],
) {
if self.window.wl_surface() == surface {
println!("Keyboard focus on window with pressed syms: {keysyms:?}");
self.keyboard_focus = true;
}
}
fn leave(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
surface: &wl_surface::WlSurface,
_: u32,
) {
if self.window.wl_surface() == surface {
println!("Release keyboard focus on window");
self.keyboard_focus = false;
}
}
fn press_key(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_: u32,
event: KeyEvent,
) {
println!("Key press: {event:?}");
}
fn repeat_key(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_: u32,
event: KeyEvent,
) {
println!("Key repeat: {event:?}");
}
fn release_key(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_: u32,
event: KeyEvent,
) {
println!("Key release: {event:?}");
}
fn update_modifiers(
&mut self,
_: &Connection,
_: &QueueHandle<Self>,
_: &wl_keyboard::WlKeyboard,
_serial: u32,
modifiers: Modifiers,
_raw_modifiers: RawModifiers,
_layout: u32,
) {
println!("Update modifiers: {modifiers:?}");
}
}
impl<T: Test + 'static> PointerHandler for SimpleWindow<T> {
fn pointer_frame(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_pointer: &wl_pointer::WlPointer,
events: &[PointerEvent],
) {
use PointerEventKind::*;
for event in events {
if &event.surface != self.window.wl_surface() {
continue;
}
match event.kind {
Enter { .. } => {
println!("Pointer entered @{:?}", event.position);
}
Leave { .. } => {
println!("Pointer left");
}
Motion { .. } => {}
Press { button, .. } => {
println!("Press {:x} @ {:?}", button, event.position);
self.shift = self.shift.xor(Some(0));
}
Release { button, .. } => {
println!("Release {:x} @ {:?}", button, event.position);
}
Axis { horizontal, vertical, .. } => {
println!("Scroll H:{horizontal:?}, V:{vertical:?}");
}
}
}
}
}
impl<T: Test + 'static> ShmHandler for SimpleWindow<T> {
fn shm_state(&mut self) -> &mut Shm {
&mut self.shm
}
}
impl<T: Test + 'static> SimpleWindow<T> {
pub fn draw(&mut self, _conn: &Connection, qh: &QueueHandle<Self>) {
let width = self.width;
let height = self.height;
let stride = self.width as i32 * 4;
let buffer = self.buffer.get_or_insert_with(|| {
self.pool
.create_buffer(width as i32, height as i32, stride, 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,
stride,
wl_shm::Format::Argb8888,
)
.expect("create buffer");
*buffer = second_buffer;
canvas
}
};
{
let shift = self.shift.unwrap_or(0);
canvas.chunks_exact_mut(4).enumerate().for_each(|(index, chunk)| {
let x = ((index + shift as usize) % width as usize) as u32;
let y = (index / width as usize) as u32;
let a = 0xFF;
let r = u32::min(((width - x) * 0xFF) / width, ((height - y) * 0xFF) / height);
let g = u32::min((x * 0xFF) / width, ((height - y) * 0xFF) / height);
let b = u32::min(((width - x) * 0xFF) / width, (y * 0xFF) / height);
let color = (a << 24) + (r << 16) + (g << 8) + b;
let array: &mut [u8; 4] = chunk.try_into().unwrap();
*array = color.to_le_bytes();
});
if let Some(shift) = &mut self.shift {
*shift = (*shift + 1) % width;
}
}
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!(@<T: Test + 'static> SimpleWindow<T>);
delegate_output!(@<T: Test + 'static> SimpleWindow<T>);
delegate_shm!(@<T: Test + 'static> SimpleWindow<T>);
delegate_seat!(@<T: Test + 'static> SimpleWindow<T>);
delegate_keyboard!(@<T: Test + 'static> SimpleWindow<T>);
delegate_pointer!(@<T: Test + 'static> SimpleWindow<T>);
delegate_xdg_shell!(@<T: Test + 'static> SimpleWindow<T>);
delegate_xdg_window!(@<T: Test + 'static> SimpleWindow<T>);
delegate_registry!(@<T: Test + 'static> SimpleWindow<T>);
impl<T: Test + 'static> ProvidesRegistryState for SimpleWindow<T> {
fn registry(&mut self) -> &mut RegistryState {
&mut self.registry_state
}
registry_handlers![OutputState, SeatState,];
}