rewrite in rust
This commit is contained in:
parent
d43f61ec76
commit
4a6b261be0
51 changed files with 3104 additions and 9319 deletions
191
src/wayland/buffer.rs
Normal file
191
src/wayland/buffer.rs
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||
*/
|
||||
|
||||
extern crate libc;
|
||||
extern crate memmap2;
|
||||
|
||||
use core::imgref::ImgRef;
|
||||
use core::imgref::ImgRefMut;
|
||||
use core::rgb::alt::BGRA;
|
||||
use core::rgb::FromSlice;
|
||||
use self::memmap2::MmapMut;
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::io::Error;
|
||||
use std::io::ErrorKind;
|
||||
use std::iter;
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::os::fd::AsFd;
|
||||
use std::process;
|
||||
use wayland::wayland_client::protocol::wl_buffer::WlBuffer;
|
||||
use wayland::wayland_client::protocol::wl_shm_pool::WlShmPool;
|
||||
use wayland::wayland_client::protocol::wl_shm;
|
||||
use wayland::wayland_client::protocol::wl_surface::WlSurface;
|
||||
use wayland::wayland_client::Dispatch;
|
||||
use wayland::wayland_client::QueueHandle;
|
||||
|
||||
pub struct Buffer<T> {
|
||||
file: File,
|
||||
map: MmapMut,
|
||||
|
||||
id: u32,
|
||||
capacity: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
|
||||
queue: QueueHandle<T>,
|
||||
pool: WlShmPool,
|
||||
buf: WlBuffer,
|
||||
used: bool,
|
||||
resizing: bool,
|
||||
}
|
||||
|
||||
impl<T: Dispatch<WlShmPool, u32>
|
||||
+ Dispatch<WlBuffer, u32>
|
||||
+ 'static> Buffer<T> {
|
||||
pub fn new(queue: QueueHandle<T>, shm: &wl_shm::WlShm, id: u32) -> Result<Self, Error>
|
||||
{
|
||||
// Integers are normally not represented as text using NUL.
|
||||
let name = match CString::new(format!("/ufkbd_pid{}_{}", process::id(), id)) {
|
||||
Ok(name) => name,
|
||||
Err(e) => return Err(Error::new(ErrorKind::InvalidInput, e)),
|
||||
};
|
||||
|
||||
let file = unsafe {
|
||||
let fd = libc::shm_open(name.as_ptr(),
|
||||
libc::O_RDWR | libc::O_CREAT | libc::O_EXCL,
|
||||
libc::S_IRUSR | libc::S_IWUSR);
|
||||
if fd == -1 {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
|
||||
File::from_raw_fd(fd)
|
||||
};
|
||||
|
||||
/*
|
||||
* A buffer must be at least 1x1, and 32 bits per pixel
|
||||
* (ARGB8888 and XRGB8888) is supported on all Wayland compositors.
|
||||
*/
|
||||
file.set_len(4)?;
|
||||
|
||||
let map = unsafe { MmapMut::map_mut(&file) }?;
|
||||
|
||||
let pool = shm.create_pool(file.as_fd(), 4, &queue, id);
|
||||
let buf = pool.create_buffer(0, 1, 1, 4, wl_shm::Format::Xrgb8888,
|
||||
&queue, id);
|
||||
|
||||
/*
|
||||
* This can happen before expanding the file. The shm_unlink(3p) manual
|
||||
* says:
|
||||
*
|
||||
* If one or more references to the shared memory object exist when
|
||||
* the object is unlinked, the name shall be removed before
|
||||
* shm_unlink() returns, but the removal of the memory object
|
||||
* contents shall be postponed until all open and map references to
|
||||
* the shared memory object have been removed.
|
||||
*/
|
||||
unsafe {
|
||||
libc::shm_unlink(name.as_ptr());
|
||||
};
|
||||
|
||||
Ok(Buffer {
|
||||
file, map,
|
||||
id, capacity: 4, width: 1, height: 1,
|
||||
queue, pool, buf,
|
||||
used: false, resizing: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn commit_resize(&mut self)
|
||||
{
|
||||
if self.resizing {
|
||||
self.buf = self.pool.create_buffer(0, self.width, self.height,
|
||||
self.width * 4,
|
||||
wl_shm::Format::Xrgb8888,
|
||||
&self.queue, self.id);
|
||||
self.resizing = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, width: i32, height: i32) -> Result<(), Error>
|
||||
{
|
||||
if width <= 0 || height <= 0 {
|
||||
return Err(Error::new(ErrorKind::InvalidInput, "Buffer must be at least 1x1"));
|
||||
}
|
||||
|
||||
// Expand as necessary. Shrinking is not supported by wl_shm_pool.resize().
|
||||
if self.capacity < width * height * 4 {
|
||||
self.capacity = width * height * 4;
|
||||
|
||||
// Failure is a bug in the above check or the capacity calculation.
|
||||
let filelen = self.capacity as u64;
|
||||
self.file.set_len(filelen)?;
|
||||
|
||||
self.pool.resize(self.capacity);
|
||||
|
||||
self.map = unsafe { MmapMut::map_mut(&self.file) }?;
|
||||
}
|
||||
|
||||
// Try to resize the buffer now, otherwise defer it.
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self.resizing = true;
|
||||
if !self.used {
|
||||
self.commit_resize();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn image(&self) -> ImgRef<BGRA<u8>>
|
||||
{
|
||||
let ptr = self.map.as_ref().as_bgra();
|
||||
ImgRef::new(ptr, self.width as usize, self.height as usize)
|
||||
}
|
||||
|
||||
pub fn consume(&mut self, surface: &WlSurface) -> Option<ImgRefMut<BGRA<u8>>>
|
||||
{
|
||||
if self.used {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.used = true;
|
||||
surface.attach(Some(&self.buf), 0, 0);
|
||||
|
||||
// The ARGB format is in little endian.
|
||||
let ptr = self.map.as_mut().as_bgra_mut();
|
||||
let img = ImgRefMut::new(ptr, self.width as usize, self.height as usize);
|
||||
|
||||
Some(img)
|
||||
}
|
||||
|
||||
pub fn release(&mut self)
|
||||
{
|
||||
self.used = false;
|
||||
self.commit_resize();
|
||||
}
|
||||
|
||||
pub fn writeback(&mut self, src: &ImgRef<BGRA<u8>>, x: usize, y: usize)
|
||||
{
|
||||
if self.used {
|
||||
panic!("Writeback must always be on an inactive buffer");
|
||||
}
|
||||
|
||||
// The ARGB format is in little endian.
|
||||
let ptr = self.map.as_mut().as_bgra_mut();
|
||||
let mut img = ImgRefMut::new(ptr, self.width as usize, self.height as usize);
|
||||
let mut subimg = img.sub_image_mut(x, y, src.width(), src.height());
|
||||
|
||||
for (dest, src) in iter::zip(subimg.pixels_mut(), src.pixels()) {
|
||||
*dest = src;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn size(&self) -> (i32, i32)
|
||||
{
|
||||
(self.width, self.height)
|
||||
}
|
||||
}
|
||||
391
src/wayland/dispatcher.rs
Normal file
391
src/wayland/dispatcher.rs
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||
*/
|
||||
|
||||
use core::Button;
|
||||
use core::Display;
|
||||
use core::Graphics;
|
||||
use core::Layout;
|
||||
use std::io::Error;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use wayland::Seat;
|
||||
use wayland::Surface;
|
||||
use wayland::wayland_client::globals::GlobalList;
|
||||
use wayland::wayland_client::globals::GlobalListContents;
|
||||
use wayland::wayland_client::protocol::wl_buffer;
|
||||
use wayland::wayland_client::protocol::wl_compositor;
|
||||
use wayland::wayland_client::protocol::wl_pointer;
|
||||
use wayland::wayland_client::protocol::wl_registry;
|
||||
use wayland::wayland_client::protocol::wl_seat;
|
||||
use wayland::wayland_client::protocol::wl_shm;
|
||||
use wayland::wayland_client::protocol::wl_shm_pool;
|
||||
use wayland::wayland_client::protocol::wl_surface;
|
||||
use wayland::wayland_client::protocol::wl_touch;
|
||||
use wayland::wayland_client::Connection;
|
||||
use wayland::wayland_client::Dispatch;
|
||||
use wayland::wayland_client::Proxy;
|
||||
use wayland::wayland_client::QueueHandle;
|
||||
use wayland::wayland_client::WEnum;
|
||||
use wayland::wlr_layer_shell_unstable_v1::zwlr_layer_shell_v1;
|
||||
use wayland::wlr_layer_shell_unstable_v1::zwlr_layer_surface_v1;
|
||||
use wayland::fractional_scale_v1::wp_fractional_scale_manager_v1;
|
||||
use wayland::fractional_scale_v1::wp_fractional_scale_v1;
|
||||
use wayland::viewporter::wp_viewporter;
|
||||
use wayland::viewporter::wp_viewport;
|
||||
use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_manager_v1;
|
||||
use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_v1;
|
||||
use wayland::VirtualKeyboard;
|
||||
|
||||
pub struct Dispatcher {
|
||||
seat: Seat<Surface<Self>, VirtualKeyboard, Self>,
|
||||
gfx: Arc<Mutex<Graphics<Surface<Self>>>>,
|
||||
}
|
||||
|
||||
impl Dispatcher {
|
||||
pub fn new(layout: Layout, queue: QueueHandle<Self>, globals: &GlobalList) -> Result<Self, Error>
|
||||
{
|
||||
let shm = globals.bind(&queue, 1..=1, ())
|
||||
.expect("Compositor must implement wl_shm");
|
||||
let compositor = globals.bind(&queue, 4..=6, ())
|
||||
.expect("Compositor must implement wl_compositor");
|
||||
let seat = globals.bind(&queue, 5..=9, ())
|
||||
.expect("Compositor must implement wl_seat");
|
||||
let layer_shell = globals.bind(&queue, 3..=4, ())
|
||||
.expect("Compositor must implement zwlr_layer_shell_v1");
|
||||
let vk_man = globals.bind(&queue, 1..=1, ())
|
||||
.expect("Compositor must implement zwp_virtual_keyboard_manager_v1");
|
||||
|
||||
let frac_scale_man = match globals.bind(&queue, 1..=1, ()) {
|
||||
Ok(g) => Some(g),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let vper = match globals.bind(&queue, 1..=1, ()) {
|
||||
Ok(g) => Some(g),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let disp = Surface::new(queue.clone(),
|
||||
&shm, &compositor, &layer_shell,
|
||||
frac_scale_man, vper, 185)?;
|
||||
let gfx = Graphics::new(disp);
|
||||
let gfx = Mutex::new(gfx);
|
||||
let gfx = Arc::new(gfx);
|
||||
|
||||
let vk = VirtualKeyboard::new(&queue, &vk_man, &seat);
|
||||
|
||||
let seat = Seat::new(layout, vk, gfx.clone(), queue.clone(), seat);
|
||||
|
||||
Ok(Dispatcher {
|
||||
seat,
|
||||
gfx,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn button(&self) -> &Button<Surface<Self>, VirtualKeyboard>
|
||||
{
|
||||
self.seat.button()
|
||||
}
|
||||
|
||||
pub fn dispatch_timers(&mut self)
|
||||
{
|
||||
self.seat.button_mut().dispatch_timers();
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_buffer::WlBuffer, u32> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_buf: &wl_buffer::WlBuffer,
|
||||
_evt: <wl_buffer::WlBuffer as Proxy>::Event,
|
||||
_data: &u32,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_compositor::WlCompositor, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_comp: &wl_compositor::WlCompositor,
|
||||
_evt: <wl_compositor::WlCompositor as Proxy>::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_pointer::WlPointer, ()> for Dispatcher {
|
||||
fn event(ctx: &mut Dispatcher,
|
||||
_ptr: &wl_pointer::WlPointer,
|
||||
evt: <wl_pointer::WlPointer as Proxy>::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
match evt {
|
||||
wl_pointer::Event::Motion { surface_x, surface_y, .. } => {
|
||||
ctx.seat.ptr_motion(surface_x, surface_y);
|
||||
},
|
||||
wl_pointer::Event::Button { state: WEnum::Value(state), .. } => {
|
||||
ctx.seat.ptr_button(state);
|
||||
},
|
||||
wl_pointer::Event::Frame => {
|
||||
ctx.seat.commit();
|
||||
},
|
||||
wl_pointer::Event::Enter { .. } => (),
|
||||
wl_pointer::Event::Leave { .. } => (),
|
||||
_ => eprintln!("warn: unknown wl_pointer event emitted"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_reg: &wl_registry::WlRegistry,
|
||||
_evt: <wl_registry::WlRegistry as Proxy>::Event,
|
||||
_data: &GlobalListContents,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_seat::WlSeat, ()> for Dispatcher {
|
||||
fn event(ctx: &mut Dispatcher,
|
||||
_seat: &wl_seat::WlSeat,
|
||||
evt: <wl_seat::WlSeat as Proxy>::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
match evt {
|
||||
wl_seat::Event::Name { .. } => (),
|
||||
wl_seat::Event::Capabilities { capabilities: WEnum::Value(caps) } => {
|
||||
ctx.seat.set_capabilities(caps);
|
||||
},
|
||||
_ => eprintln!("warn: unknown wl_seat event emitted"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_shm::WlShm, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_shm: &wl_shm::WlShm,
|
||||
evt: <wl_shm::WlShm as Proxy>::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
match evt {
|
||||
wl_shm::Event::Format { .. } => (),
|
||||
_ => eprintln!("warn: unknown wl_shm event emitted"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_shm_pool::WlShmPool, u32> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_pool: &wl_shm_pool::WlShmPool,
|
||||
_evt: <wl_shm_pool::WlShmPool as Proxy>::Event,
|
||||
_data: &u32,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
eprintln!("warn: unknown wl_shm_pool event emitted");
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_surface::WlSurface, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_pool: &wl_surface::WlSurface,
|
||||
evt: <wl_surface::WlSurface as Proxy>::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
match evt {
|
||||
wl_surface::Event::PreferredBufferTransform { .. } => (),
|
||||
wl_surface::Event::PreferredBufferScale { .. } => (), // TODO
|
||||
_ => eprintln!("warn: unknown wl_surface event emitted"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_touch::WlTouch, ()> for Dispatcher {
|
||||
fn event(ctx: &mut Dispatcher,
|
||||
_ptr: &wl_touch::WlTouch,
|
||||
evt: <wl_touch::WlTouch as Proxy>::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
match evt {
|
||||
wl_touch::Event::Down { id, x, y, .. } => {
|
||||
ctx.seat.touch_press(id as u32, x, y);
|
||||
},
|
||||
wl_touch::Event::Motion { id, x, y, .. } => {
|
||||
ctx.seat.touch_pos(id as u32, x, y);
|
||||
},
|
||||
wl_touch::Event::Up { id, .. } => {
|
||||
ctx.seat.touch_release(id as u32);
|
||||
},
|
||||
wl_touch::Event::Frame => {
|
||||
ctx.seat.commit();
|
||||
},
|
||||
_ => eprintln!("warn: unknown wl_touch event emitted"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_pool: &wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
|
||||
_evt: wp_fractional_scale_manager_v1::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
eprintln!("warn: unknown wp_fractional_scale_manager_v1 event emitted");
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ()> for Dispatcher {
|
||||
fn event(ctx: &mut Dispatcher,
|
||||
_pool: &wp_fractional_scale_v1::WpFractionalScaleV1,
|
||||
evt: wp_fractional_scale_v1::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
match evt {
|
||||
wp_fractional_scale_v1::Event::PreferredScale { scale } => {
|
||||
let mut gfx = ctx.gfx.lock().unwrap();
|
||||
|
||||
if scale == gfx.display().scale() {
|
||||
return;
|
||||
}
|
||||
|
||||
let old_scale = gfx.display().scale();
|
||||
let (width, height) = gfx.display().size();
|
||||
let (width, height) = (width * scale / old_scale,
|
||||
height * scale / old_scale);
|
||||
|
||||
gfx.display_mut().update_scale(scale);
|
||||
|
||||
if gfx.display().configured() {
|
||||
let layout = ctx.seat.layout();
|
||||
let mod_state = ctx.seat.mod_state();
|
||||
|
||||
gfx.resize(layout, mod_state, width, height);
|
||||
|
||||
let (width, height) = gfx.display().size();
|
||||
let width = width as f64 * 120.0 / scale as f64;
|
||||
let height = height as f64 * 120.0 / scale as f64;
|
||||
|
||||
ctx.seat.set_scale(layout.width() / width,
|
||||
layout.height() / height);
|
||||
}
|
||||
},
|
||||
_ => eprintln!("warn: unknown wp_fractional_scale_v1 event emitted"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wp_viewporter::WpViewporter, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_pool: &wp_viewporter::WpViewporter,
|
||||
_evt: wp_viewporter::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
eprintln!("warn: unknown wp_viewporter event emitted");
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wp_viewport::WpViewport, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_pool: &wp_viewport::WpViewport,
|
||||
_evt: wp_viewport::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
eprintln!("warn: unknown wp_viewport event emitted");
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<zwlr_layer_shell_v1::ZwlrLayerShellV1, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_pool: &zwlr_layer_shell_v1::ZwlrLayerShellV1,
|
||||
_evt: <zwlr_layer_shell_v1::ZwlrLayerShellV1 as Proxy>::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
eprintln!("warn: unknown zwlr_layer_shell_v1 event emitted");
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for Dispatcher {
|
||||
fn event(ctx: &mut Dispatcher,
|
||||
_surface: &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||
evt: zwlr_layer_surface_v1::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
match evt {
|
||||
zwlr_layer_surface_v1::Event::Configure { width, height, serial } => {
|
||||
let mut gfx = ctx.gfx.lock().unwrap();
|
||||
|
||||
gfx.display_mut().ack_configure(serial);
|
||||
|
||||
let layout = ctx.seat.layout();
|
||||
let mod_state = ctx.seat.mod_state();
|
||||
|
||||
let scale = gfx.display().scale() / 120;
|
||||
let (width, height) = (width * scale, height * scale);
|
||||
gfx.resize(layout, mod_state, width, height);
|
||||
|
||||
let disp = gfx.display();
|
||||
let scale = disp.scale() as f64;
|
||||
let (width, height) = disp.size();
|
||||
let width = width as f64 * 120.0 / scale;
|
||||
let height = height as f64 * 120.0 / scale;
|
||||
|
||||
ctx.seat.set_scale(layout.width() / width,
|
||||
layout.height() / height);
|
||||
},
|
||||
_ => eprintln!("warn: unknown zwlr_layer_surface_v1 event emitted"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_vk_man: &zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1,
|
||||
_evt: zwp_virtual_keyboard_manager_v1::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
eprintln!("warn: unknown zwp_virtual_keyboard_manager_v1 event emitted");
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1, ()> for Dispatcher {
|
||||
fn event(_ctx: &mut Dispatcher,
|
||||
_vk: &zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
|
||||
_evt: zwp_virtual_keyboard_v1::Event,
|
||||
_data: &(),
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Dispatcher>)
|
||||
{
|
||||
eprintln!("warn: unknown zwp_virtual_keyboard_v1 event emitted");
|
||||
}
|
||||
}
|
||||
199
src/wayland/keyboard.rs
Normal file
199
src/wayland/keyboard.rs
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||
*/
|
||||
|
||||
use core::Keyboard;
|
||||
use core::Layout;
|
||||
use core::Part;
|
||||
use core::xkeysym::Keysym;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Seek;
|
||||
use std::io::Write;
|
||||
use std::os::fd::AsFd;
|
||||
use std::process;
|
||||
use wayland::wayland_client::Dispatch;
|
||||
use wayland::wayland_client::QueueHandle;
|
||||
use wayland::wayland_client::protocol::wl_seat::WlSeat;
|
||||
use wayland::wayland_client::protocol::wl_keyboard::KeymapFormat;
|
||||
use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1;
|
||||
use wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1;
|
||||
|
||||
pub struct VirtualKeyboard {
|
||||
vk: ZwpVirtualKeyboardV1,
|
||||
keymap: File,
|
||||
keymap_id: u8,
|
||||
|
||||
keycodes: HashMap<Keysym, u8>,
|
||||
mod_state: u32,
|
||||
}
|
||||
|
||||
impl VirtualKeyboard {
|
||||
pub fn new<T: Dispatch<ZwpVirtualKeyboardV1, ()>
|
||||
+ 'static>(queue: &QueueHandle<T>,
|
||||
vk_man: &ZwpVirtualKeyboardManagerV1,
|
||||
seat: &WlSeat)
|
||||
-> VirtualKeyboard
|
||||
{
|
||||
let vk = vk_man.create_virtual_keyboard(seat, queue, ());
|
||||
|
||||
let path = format!("/tmp/ufkbd-keymap-pid{}-1", process::id());
|
||||
let keymap = File::create(path).unwrap();
|
||||
|
||||
VirtualKeyboard {
|
||||
vk,
|
||||
keymap,
|
||||
keymap_id: 1,
|
||||
|
||||
keycodes: HashMap::new(),
|
||||
mod_state: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn write_key(&mut self, part: &Part, keycode: u8)
|
||||
{
|
||||
let sym = part.sym();
|
||||
let lower = &sym.name().unwrap()[3..];
|
||||
let upper = &Part::modify_shift(sym).name().unwrap()[3..];
|
||||
|
||||
write!(self.keymap, " key <I{:03}> {{ [ {}, {} ] }};\n",
|
||||
keycode, lower, upper).unwrap();
|
||||
|
||||
if sym == Keysym::Shift_L {
|
||||
write!(self.keymap,
|
||||
" modifier_map Shift {{ <I{:03}> }};\n",
|
||||
keycode).unwrap();
|
||||
} else if sym == Keysym::Control_L {
|
||||
write!(self.keymap,
|
||||
" modifier_map Control {{ <I{:03}> }};\n",
|
||||
keycode).unwrap();
|
||||
} else if sym == Keysym::Alt_L {
|
||||
write!(self.keymap,
|
||||
" modifier_map Mod1 {{ <I{:03}> }};\n",
|
||||
keycode).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Keyboard for VirtualKeyboard {
|
||||
fn press(&mut self, sym: Keysym)
|
||||
{
|
||||
if sym == Keysym::NoSymbol || sym == Keysym::XF86_Fn {
|
||||
return;
|
||||
}
|
||||
|
||||
match sym {
|
||||
Keysym::Shift_L => {
|
||||
self.mod_state |= 0x1;
|
||||
self.vk.modifiers(self.mod_state, 0, 0, 0);
|
||||
},
|
||||
Keysym::Control_L => {
|
||||
self.mod_state |= 0x4;
|
||||
self.vk.modifiers(self.mod_state, 0, 0, 0);
|
||||
},
|
||||
Keysym::Alt_L => {
|
||||
self.mod_state |= 0x8;
|
||||
self.vk.modifiers(self.mod_state, 0, 0, 0);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let keycode = *self.keycodes.get(&sym).unwrap();
|
||||
self.vk.key(0, keycode as u32, 1);
|
||||
}
|
||||
|
||||
fn release(&mut self, sym: Keysym)
|
||||
{
|
||||
if sym == Keysym::NoSymbol || sym == Keysym::XF86_Fn {
|
||||
return;
|
||||
}
|
||||
|
||||
match sym {
|
||||
Keysym::Shift_L => {
|
||||
self.mod_state &= !0x1;
|
||||
self.vk.modifiers(self.mod_state, 0, 0, 0);
|
||||
},
|
||||
Keysym::Control_L => {
|
||||
self.mod_state &= !0x4;
|
||||
self.vk.modifiers(self.mod_state, 0, 0, 0);
|
||||
},
|
||||
Keysym::Alt_L => {
|
||||
self.mod_state &= !0x8;
|
||||
self.vk.modifiers(self.mod_state, 0, 0, 0);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let keycode = *self.keycodes.get(&sym).unwrap();
|
||||
self.vk.key(0, keycode as u32, 0);
|
||||
}
|
||||
|
||||
fn change_layout(&mut self, layout: &Layout)
|
||||
{
|
||||
let mut keycode = 8;
|
||||
|
||||
self.keymap_id = match self.keymap_id {
|
||||
0 => 1,
|
||||
1 => 0,
|
||||
_ => panic!("There should only be up to two keymaps"),
|
||||
};
|
||||
|
||||
let path = format!("/tmp/ufkbd-keymap-pid{}-{}",
|
||||
process::id(), self.keymap_id);
|
||||
self.keymap = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(path)
|
||||
.unwrap();
|
||||
|
||||
self.keymap.write(b"xkb_keymap {\n").unwrap();
|
||||
self.keymap.write(b" xkb_symbols \"ufkbd\" {\n").unwrap();
|
||||
|
||||
for row in layout.rows() {
|
||||
for key in row {
|
||||
for part in &key.parts {
|
||||
if part.sym() == Keysym::NoSymbol || part.sym() == Keysym::XF86_Fn {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.keycodes.insert(part.sym(), keycode - 8);
|
||||
self.write_key(part, keycode);
|
||||
keycode += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.keymap.write(b" };\n").unwrap();
|
||||
self.keymap.write(b"\n").unwrap();
|
||||
self.keymap.write(b" xkb_keycodes \"ufkbd\" {\n").unwrap();
|
||||
self.keymap.write(b" minimum = 8;\n").unwrap();
|
||||
self.keymap.write(b" maximum = 255;\n").unwrap();
|
||||
|
||||
for i in 8..keycode {
|
||||
write!(self.keymap, " <I{:03}> = {};\n", i, i).unwrap();
|
||||
}
|
||||
|
||||
self.keymap.write(b" indicator 1 = \"Caps Lock\";\n").unwrap();
|
||||
self.keymap.write(b" };\n").unwrap();
|
||||
self.keymap.write(b"\n").unwrap();
|
||||
self.keymap.write(b" xkb_types \"ufkbd\" {\n").unwrap();
|
||||
self.keymap.write(b" type \"TWO_LEVEL\" {\n").unwrap();
|
||||
self.keymap.write(b" modifiers = Shift;\n").unwrap();
|
||||
self.keymap.write(b" map[Shift] = Level2;\n").unwrap();
|
||||
self.keymap.write(b" level_name[Level1] = \"Base\";\n").unwrap();
|
||||
self.keymap.write(b" level_name[Level2] = \"Shift\";\n").unwrap();
|
||||
self.keymap.write(b" };\n").unwrap();
|
||||
self.keymap.write(b" };\n").unwrap();
|
||||
self.keymap.write(b"\n").unwrap();
|
||||
self.keymap.write(b" xkb_compatibility \"ufkbd\" {\n").unwrap();
|
||||
self.keymap.write(b" };\n").unwrap();
|
||||
self.keymap.write(b"};\n").unwrap();
|
||||
|
||||
let len = self.keymap.stream_position().unwrap() as u32;
|
||||
self.vk.keymap(KeymapFormat::XkbV1 as u32, self.keymap.as_fd(), len);
|
||||
}
|
||||
}
|
||||
30
src/wayland/mod.rs
Normal file
30
src/wayland/mod.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||
*/
|
||||
|
||||
pub extern crate wayland_client;
|
||||
pub extern crate wayland_protocols;
|
||||
pub extern crate wayland_protocols_wlr;
|
||||
pub extern crate wayland_scanner;
|
||||
|
||||
mod buffer;
|
||||
mod dispatcher;
|
||||
mod keyboard;
|
||||
mod protocols;
|
||||
mod seat;
|
||||
mod surface;
|
||||
|
||||
pub use self::buffer::Buffer;
|
||||
pub use self::dispatcher::Dispatcher;
|
||||
pub use self::keyboard::VirtualKeyboard;
|
||||
pub use self::seat::Seat;
|
||||
pub use self::surface::Surface;
|
||||
|
||||
pub use self::wayland_protocols_wlr::layer_shell::v1::client as wlr_layer_shell_unstable_v1;
|
||||
pub use self::wayland_protocols::wp::fractional_scale::v1::client as fractional_scale_v1;
|
||||
pub use self::wayland_protocols::wp::text_input::zv3::client as text_input_unstable_v3;
|
||||
pub use self::wayland_protocols::wp::viewporter::client as viewporter;
|
||||
|
||||
pub use self::protocols::input_method_unstable_v2;
|
||||
pub use self::protocols::virtual_keyboard_unstable_v1;
|
||||
35
src/wayland/protocols.rs
Normal file
35
src/wayland/protocols.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||
*/
|
||||
|
||||
pub mod input_method_unstable_v2 {
|
||||
use wayland::wayland_client;
|
||||
use wayland::wayland_client::protocol::*;
|
||||
use wayland::text_input_unstable_v3::*;
|
||||
|
||||
pub mod __interfaces {
|
||||
use wayland::wayland_client::protocol::__interfaces::*;
|
||||
|
||||
wayland_scanner::generate_interfaces!("wayland-protocols/input-method-unstable-v2.xml");
|
||||
}
|
||||
|
||||
use self::__interfaces::*;
|
||||
|
||||
wayland_scanner::generate_client_code!("wayland-protocols/input-method-unstable-v2.xml");
|
||||
}
|
||||
|
||||
pub mod virtual_keyboard_unstable_v1 {
|
||||
use wayland::wayland_client;
|
||||
use wayland::wayland_client::protocol::*;
|
||||
|
||||
pub mod __interfaces {
|
||||
use wayland::wayland_client::protocol::__interfaces::*;
|
||||
|
||||
wayland_scanner::generate_interfaces!("wayland-protocols/virtual-keyboard-unstable-v1.xml");
|
||||
}
|
||||
|
||||
use self::__interfaces::*;
|
||||
|
||||
wayland_scanner::generate_client_code!("wayland-protocols/virtual-keyboard-unstable-v1.xml");
|
||||
}
|
||||
186
src/wayland/seat.rs
Normal file
186
src/wayland/seat.rs
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||
*/
|
||||
|
||||
use core::Button;
|
||||
use core::ModState;
|
||||
use core::Display;
|
||||
use core::Graphics;
|
||||
use core::Keyboard;
|
||||
use core::Layout;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use wayland::wayland_client::protocol::wl_pointer;
|
||||
use wayland::wayland_client::protocol::wl_seat;
|
||||
use wayland::wayland_client::protocol::wl_touch::WlTouch;
|
||||
use wayland::wayland_client::Dispatch;
|
||||
use wayland::wayland_client::QueueHandle;
|
||||
|
||||
enum PressAction {
|
||||
Pos(f64, f64),
|
||||
Press(f64, f64),
|
||||
Release,
|
||||
}
|
||||
|
||||
struct TouchAction {
|
||||
id: usize,
|
||||
act: PressAction,
|
||||
}
|
||||
|
||||
pub struct Seat<D: Display, K: Keyboard, T> {
|
||||
seat: wl_seat::WlSeat,
|
||||
queue: QueueHandle<T>,
|
||||
|
||||
ptr: Option<wl_pointer::WlPointer>,
|
||||
touch: Option<WlTouch>,
|
||||
|
||||
button: Button<D, K>,
|
||||
|
||||
x_scale: f64,
|
||||
y_scale: f64,
|
||||
|
||||
mouse_x: f64,
|
||||
mouse_y: f64,
|
||||
actions: Vec<TouchAction>,
|
||||
}
|
||||
|
||||
impl<D: Display, K: Keyboard,
|
||||
T: Dispatch<wl_pointer::WlPointer, ()>
|
||||
+ Dispatch<WlTouch, ()>
|
||||
+ 'static> Seat<D, K, T> {
|
||||
pub fn new(layout: Layout, kbd: K, gfx: Arc<Mutex<Graphics<D>>>,
|
||||
queue: QueueHandle<T>, seat: wl_seat::WlSeat) -> Seat<D, K, T>
|
||||
{
|
||||
let actions = Vec::new();
|
||||
let button = Button::new(layout, kbd, gfx);
|
||||
|
||||
Seat {
|
||||
seat,
|
||||
queue,
|
||||
|
||||
ptr: None,
|
||||
touch: None,
|
||||
|
||||
button,
|
||||
|
||||
x_scale: 0.0,
|
||||
y_scale: 0.0,
|
||||
|
||||
mouse_x: 0.0,
|
||||
mouse_y: 0.0,
|
||||
actions,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn button(&self) -> &Button<D, K>
|
||||
{
|
||||
&self.button
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn button_mut(&mut self) -> &mut Button<D, K>
|
||||
{
|
||||
&mut self.button
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn layout(&self) -> &Layout
|
||||
{
|
||||
self.button.layout()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mod_state(&self) -> &[ModState]
|
||||
{
|
||||
self.button.mod_state()
|
||||
}
|
||||
|
||||
pub fn set_capabilities(&mut self, caps: wl_seat::Capability)
|
||||
{
|
||||
if caps.contains(wl_seat::Capability::Pointer) {
|
||||
self.ptr = Some(self.seat.get_pointer(&self.queue, ()));
|
||||
}
|
||||
|
||||
if caps.contains(wl_seat::Capability::Touch) {
|
||||
self.touch = Some(self.seat.get_touch(&self.queue, ()));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_scale(&mut self, x_scale: f64, y_scale: f64)
|
||||
{
|
||||
self.x_scale = x_scale;
|
||||
self.y_scale = y_scale;
|
||||
}
|
||||
|
||||
pub fn ptr_motion(&mut self, x: f64, y: f64)
|
||||
{
|
||||
let (x, y) = (x * self.x_scale, y * self.y_scale);
|
||||
|
||||
self.mouse_x = x;
|
||||
self.mouse_y = y;
|
||||
|
||||
let act = TouchAction { id: 0, act: PressAction::Pos(x, y), };
|
||||
self.actions.push(act);
|
||||
}
|
||||
|
||||
pub fn ptr_button(&mut self, state: wl_pointer::ButtonState)
|
||||
{
|
||||
match state {
|
||||
wl_pointer::ButtonState::Pressed => {
|
||||
let (x, y) = (self.mouse_x, self.mouse_y);
|
||||
let act = TouchAction { id: 0, act: PressAction::Press(x, y), };
|
||||
self.actions.push(act);
|
||||
},
|
||||
wl_pointer::ButtonState::Released => {
|
||||
let act = TouchAction { id: 0, act: PressAction::Release, };
|
||||
self.actions.push(act);
|
||||
},
|
||||
_ => eprintln!("warn: ignoring unknown pointer event"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn touch_press(&mut self, id: u32, x: f64, y: f64)
|
||||
{
|
||||
let id = id as usize + 1;
|
||||
let (x, y) = (x * self.x_scale, y * self.y_scale);
|
||||
let act = TouchAction { id, act: PressAction::Press(x, y), };
|
||||
self.actions.push(act);
|
||||
}
|
||||
|
||||
pub fn touch_pos(&mut self, id: u32, x: f64, y: f64)
|
||||
{
|
||||
let id = id as usize + 1;
|
||||
let (x, y) = (x * self.x_scale, y * self.y_scale);
|
||||
let act = TouchAction { id, act: PressAction::Pos(x, y), };
|
||||
self.actions.push(act);
|
||||
}
|
||||
|
||||
pub fn touch_release(&mut self, id: u32)
|
||||
{
|
||||
let id = id as usize + 1;
|
||||
let act = TouchAction { id, act: PressAction::Release, };
|
||||
self.actions.push(act);
|
||||
}
|
||||
|
||||
pub fn commit(&mut self)
|
||||
{
|
||||
for action in &self.actions {
|
||||
match action.act {
|
||||
PressAction::Press(x, y) => {
|
||||
self.button.press(action.id, x, y);
|
||||
},
|
||||
PressAction::Pos(x, y) => {
|
||||
self.button.pos(action.id, x, y);
|
||||
},
|
||||
PressAction::Release => {
|
||||
self.button.release(action.id);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the action for the next frame.
|
||||
self.actions.clear();
|
||||
}
|
||||
}
|
||||
179
src/wayland/surface.rs
Normal file
179
src/wayland/surface.rs
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||
*/
|
||||
|
||||
use core::Display;
|
||||
use core::imgref::ImgRefMut;
|
||||
use core::rgb::alt::BGRA;
|
||||
use std::io::Error;
|
||||
use wayland::Buffer;
|
||||
use wayland::wayland_client::protocol::wl_buffer::WlBuffer;
|
||||
use wayland::wayland_client::protocol::wl_compositor::WlCompositor;
|
||||
use wayland::wayland_client::protocol::wl_shm_pool::WlShmPool;
|
||||
use wayland::wayland_client::protocol::wl_shm::WlShm;
|
||||
use wayland::wayland_client::protocol::wl_surface::WlSurface;
|
||||
use wayland::wayland_client::Dispatch;
|
||||
use wayland::wayland_client::QueueHandle;
|
||||
use wayland::wlr_layer_shell_unstable_v1::zwlr_layer_shell_v1;
|
||||
use wayland::wlr_layer_shell_unstable_v1::zwlr_layer_surface_v1;
|
||||
use wayland::fractional_scale_v1::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1;
|
||||
use wayland::fractional_scale_v1::wp_fractional_scale_v1::WpFractionalScaleV1;
|
||||
use wayland::viewporter::wp_viewporter::WpViewporter;
|
||||
use wayland::viewporter::wp_viewport::WpViewport;
|
||||
|
||||
pub struct Surface<T> {
|
||||
bufs: [Buffer<T>; 2],
|
||||
surface: WlSurface,
|
||||
layer_surf: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||
vp: Option<WpViewport>,
|
||||
|
||||
used_buf: usize,
|
||||
configured: bool,
|
||||
scale: u32,
|
||||
}
|
||||
|
||||
const LAYER_ANCHOR: zwlr_layer_surface_v1::Anchor
|
||||
= zwlr_layer_surface_v1::Anchor::from_bits_truncate(0)
|
||||
.union(zwlr_layer_surface_v1::Anchor::Bottom)
|
||||
.union(zwlr_layer_surface_v1::Anchor::Left)
|
||||
.union(zwlr_layer_surface_v1::Anchor::Right);
|
||||
|
||||
impl<T: Dispatch<WlBuffer, u32>
|
||||
+ Dispatch<WlShmPool, u32>
|
||||
+ Dispatch<WlSurface, ()>
|
||||
+ Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()>
|
||||
+ Dispatch<WpFractionalScaleV1, ()>
|
||||
+ Dispatch<WpViewport, ()>
|
||||
+ 'static> Surface<T> {
|
||||
pub fn new(queue: QueueHandle<T>, shm: &WlShm, comp: &WlCompositor,
|
||||
layer_shell: &zwlr_layer_shell_v1::ZwlrLayerShellV1,
|
||||
frac_scale_man: Option<WpFractionalScaleManagerV1>,
|
||||
vper: Option<WpViewporter>,
|
||||
size: i32)
|
||||
-> Result<Surface<T>, Error>
|
||||
{
|
||||
let buf1 = Buffer::new(queue.clone(), shm, 0)?;
|
||||
let buf2 = Buffer::new(queue.clone(), shm, 1)?;
|
||||
|
||||
let surface = comp.create_surface(&queue, ());
|
||||
|
||||
let layer_surf = layer_shell.get_layer_surface(&surface, None,
|
||||
zwlr_layer_shell_v1::Layer::Top,
|
||||
String::from("osk-ufkbd"),
|
||||
&queue, ());
|
||||
|
||||
frac_scale_man.map(|fsm| fsm.get_fractional_scale(&surface, &queue, ()));
|
||||
|
||||
let vp = vper.map(|vper| vper.get_viewport(&surface, &queue, ()));
|
||||
|
||||
layer_surf.set_size(0, size as u32);
|
||||
layer_surf.set_exclusive_zone(size);
|
||||
layer_surf.set_anchor(LAYER_ANCHOR);
|
||||
|
||||
surface.commit();
|
||||
|
||||
Ok(Surface {
|
||||
bufs: [buf1, buf2],
|
||||
surface,
|
||||
layer_surf,
|
||||
vp,
|
||||
used_buf: 1,
|
||||
configured: false,
|
||||
scale: 120,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn configured(&self) -> bool
|
||||
{
|
||||
self.configured
|
||||
}
|
||||
|
||||
pub fn ack_configure(&mut self, serial: u32)
|
||||
{
|
||||
self.configured = true;
|
||||
self.layer_surf.ack_configure(serial);
|
||||
}
|
||||
|
||||
pub fn scale(&self) -> u32
|
||||
{
|
||||
self.scale
|
||||
}
|
||||
|
||||
pub fn update_scale(&mut self, scale: u32)
|
||||
{
|
||||
self.scale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Dispatch<WlBuffer, u32>
|
||||
+ Dispatch<WlShmPool, u32>
|
||||
+ Dispatch<WlSurface, ()>
|
||||
+ Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()>
|
||||
+ Dispatch<WpFractionalScaleV1, ()>
|
||||
+ Dispatch<WpViewport, ()>
|
||||
+ 'static> Display for Surface<T> {
|
||||
#[inline(always)]
|
||||
fn size(&self) -> (u32, u32)
|
||||
{
|
||||
let (width, height) = self.bufs[self.used_buf].size();
|
||||
(width as u32, height as u32)
|
||||
}
|
||||
|
||||
fn begin(&mut self) -> ImgRefMut<BGRA<u8>>
|
||||
{
|
||||
for (id, buf) in self.bufs.iter_mut().enumerate() {
|
||||
if let Some(img) = buf.consume(&self.surface) {
|
||||
self.used_buf = id;
|
||||
return img;
|
||||
}
|
||||
}
|
||||
|
||||
panic!("No buffers available")
|
||||
}
|
||||
|
||||
fn resize(&mut self, width: u32, height: u32)
|
||||
{
|
||||
let width_unscaled = (width * 120 / self.scale) as i32;
|
||||
let height_unscaled = (height * 120 / self.scale) as i32;
|
||||
|
||||
for buf in &mut self.bufs {
|
||||
buf.resize(width as i32, height as i32).unwrap();
|
||||
}
|
||||
|
||||
if let Some(vp) = &self.vp {
|
||||
vp.set_source(0.0, 0.0, width as f64, height as f64);
|
||||
vp.set_destination(width_unscaled, height_unscaled);
|
||||
}
|
||||
}
|
||||
|
||||
fn end(&mut self, x: u32, y: u32, width: u32, height: u32)
|
||||
{
|
||||
self.surface.damage_buffer(x as i32, y as i32, width as i32, height as i32);
|
||||
self.surface.commit();
|
||||
|
||||
for (id, buf) in self.bufs.iter_mut().enumerate() {
|
||||
if id != self.used_buf {
|
||||
buf.release();
|
||||
}
|
||||
}
|
||||
|
||||
let (src, dest) = match self.used_buf {
|
||||
0 => {
|
||||
let [src, ref mut dest] = &mut self.bufs;
|
||||
(src, dest)
|
||||
},
|
||||
1 => {
|
||||
let [ref mut dest, src] = &mut self.bufs;
|
||||
(src, dest)
|
||||
},
|
||||
2.. => panic!("Surface must only use two buffers"),
|
||||
};
|
||||
|
||||
let img = src.image().sub_image(x as usize,
|
||||
y as usize,
|
||||
width as usize,
|
||||
height as usize);
|
||||
dest.writeback(&img, x as usize, y as usize);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue