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.
391 lines
13 KiB
Rust
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");
|
|
}
|
|
}
|