unfettered-keyboard/src/wayland/dispatcher.rs
Richard Acayan b5d09e655b wayland: surface: add show/hide functionality
While the keyboard is running, it may want to automatically show or hide
itself depending on whether a text input is active. Add functions to
show and hide the surface by destroying and re-creating it.

Phosh's compositor, phoc, does not emit configure events in reaction to
a surface being committed with no buffer attached. The complicated
surface creation/destruction process is for compatibility with phoc.
2024-07-24 22:31:59 -04:00

391 lines
13 KiB
Rust

// 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");
}
}