fix(wayland): new API

This commit is contained in:
Nova
2023-08-27 17:13:20 -04:00
parent ba3faf2c76
commit a4d3ec537f
5 changed files with 178 additions and 152 deletions

View File

@@ -7,7 +7,7 @@ use crate::{
core::task,
nodes::items::panel::{Backend, Geometry, PanelItem},
};
use color_eyre::eyre::Result;
use color_eyre::eyre::{bail, eyre, Result};
use mint::Vector2;
use nanoid::nanoid;
use once_cell::sync::OnceCell;
@@ -15,7 +15,7 @@ use parking_lot::Mutex;
use rand::{seq::IteratorRandom, thread_rng};
use rustc_hash::{FxHashMap, FxHashSet};
use smithay::{
input::keyboard::ModifiersState,
input::keyboard::{KeymapFile, ModifiersState},
reexports::wayland_server::{
backend::{ClientId, GlobalId, ObjectId},
protocol::{
@@ -36,7 +36,7 @@ use std::{
};
use tokio::sync::watch;
use tracing::{debug, warn};
use xkbcommon::xkb::{self, Context, Keymap};
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
pub fn handle_cursor<B: Backend>(
panel_item: &Arc<PanelItem<B>>,
@@ -53,14 +53,18 @@ pub fn handle_cursor<B: Backend>(
}
pub struct KeyboardInfo {
keymap_string: String,
keymap: KeymapFile,
state: xkb::State,
mods: ModifiersState,
keys: FxHashSet<u32>,
}
impl KeyboardInfo {
pub fn new(keymap: &Keymap) -> Self {
pub fn new(keymap_string: String, keymap: &Keymap) -> Self {
KeyboardInfo {
keymap_string,
state: xkb::State::new(keymap),
keymap: KeymapFile::new(keymap),
mods: ModifiersState::default(),
keys: FxHashSet::default(),
}
@@ -116,6 +120,7 @@ pub enum PointerEvent {
}
#[derive(Debug, Clone)]
pub enum KeyboardEvent {
Keymap,
Key { key: u32, state: u32 },
}
@@ -126,7 +131,7 @@ struct SurfaceInfo {
pointer_queue: VecDeque<PointerEvent>,
pointer_latest_event: Instant,
keyboard_queue: VecDeque<KeyboardEvent>,
keyboard_info: KeyboardInfo,
keyboard_info: Option<KeyboardInfo>,
}
impl SurfaceInfo {
fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender<Option<CursorInfo>>) -> Self {
@@ -136,9 +141,7 @@ impl SurfaceInfo {
pointer_queue: VecDeque::new(),
pointer_latest_event: Instant::now(),
keyboard_queue: VecDeque::new(),
keyboard_info: KeyboardInfo::new(
&Keymap::new_from_names(&Context::new(0), "", "", "", "", None, 0).unwrap(),
),
keyboard_info: None,
}
}
fn flush(&self) {
@@ -233,20 +236,25 @@ impl SurfaceInfo {
locked
}
fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, locked: bool) -> bool {
fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, mut locked: bool) -> bool {
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
let Some(info) = self.keyboard_info.as_mut() else { return true; };
if !locked {
keyboard.enter(0, &focus, vec![]);
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE {
keyboard.repeat_info(0, 0);
}
locked = info.keymap.send(keyboard).is_ok();
}
while let Some(event) = self.keyboard_queue.pop_front() {
debug!(locked, ?event, "Process keyboard event");
match (locked, event) {
(true, KeyboardEvent::Keymap) => {
let _ = info.keymap.send(keyboard);
}
(true, KeyboardEvent::Key { key, state }) => {
if let Ok(key_count) = self.keyboard_info.process(key, state, keyboard) {
if let Ok(key_count) = info.process(key, state, keyboard) {
if key_count == 0 {
keyboard.leave(SERIAL_COUNTER.inc(), &focus);
return false;
@@ -290,6 +298,31 @@ impl SeatData {
seat_data
}
pub fn set_keymap(&self, keymap_str: String, surfaces: Vec<WlSurface>) -> Result<()> {
let context = xkb::Context::new(0);
let keymap =
Keymap::new_from_string(&context, keymap_str.clone(), XKB_KEYMAP_FORMAT_TEXT_V1, 0)
.ok_or_else(|| eyre!("Keymap is not valid"))?;
let mut panels = self.surfaces.lock();
let Some((_, focus)) = self.keyboard.get() else {bail!("Could not get keyboard")};
for surface in surfaces {
let Some(surface_info) = panels.get_mut(&surface.id()) else {continue};
if let Some(keyboard_info) = &mut surface_info.keyboard_info {
if &keyboard_info.keymap_string == &keymap_str {
continue;
}
}
surface_info
.keyboard_info
.replace(KeyboardInfo::new(keymap_str.clone(), &keymap));
if *focus.lock() == surface.id() {
surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap);
}
}
Ok(())
}
pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) {
let mut surfaces = self.surfaces.lock();
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
@@ -345,6 +378,7 @@ impl SeatData {
if keyboard_focus.is_null() {
*keyboard_focus = surfaces
.iter()
.filter(|(_k, v)| v.keyboard_info.is_some())
.filter(|(_k, v)| !v.keyboard_queue.is_empty())
.map(|(k, _v)| k)
.choose(&mut thread_rng())

View File

@@ -6,11 +6,11 @@ use super::{
};
use crate::{
nodes::{
data::KEYMAPS,
drawable::model::ModelPart,
items::panel::{
Backend, ChildInfo, Geometry, PanelItem, PanelItemInitData, SurfaceID, ToplevelInfo,
},
Node,
},
wayland::seat::handle_cursor,
};
@@ -378,11 +378,10 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
xdg_surface_data.lock().surface_id = SurfaceID::Toplevel;
let Some(backend) = XDGBackend::create(toplevel.clone(), seat_data.clone()) else {return};
let (node, panel_item) = PanelItem::create(
let panel_item = PanelItem::create(
Box::new(backend),
client_credentials.map(|c| c.pid),
);
toplevel_data.lock().panel_item_node.replace(node);
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
handle_cursor(&panel_item, panel_item.backend.cursor.clone());
}
@@ -509,7 +508,6 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
#[derive(Debug, Clone)]
pub struct ToplevelData {
panel_item_node: Option<Arc<Node>>,
xdg_surface: WlWeak<XdgSurface>,
parent: Option<WlWeak<XdgToplevel>>,
title: Option<String>,
@@ -520,7 +518,6 @@ pub struct ToplevelData {
impl ToplevelData {
fn new(xdg_surface: &XdgSurface) -> Self {
ToplevelData {
panel_item_node: None,
xdg_surface: xdg_surface.downgrade(),
parent: None,
title: None,
@@ -543,6 +540,12 @@ impl ToplevelData {
xdg_surface_data.panel_item()
}
}
impl Drop for ToplevelData {
fn drop(&mut self) {
let Some(panel_item) = self.panel_item() else {return};
panel_item.drop_toplevel();
}
}
impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
fn request(
_state: &mut WaylandState,
@@ -578,15 +581,6 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
let Some(panel_item) = data.lock().panel_item() else {return};
panel_item.toplevel_app_id_changed(&app_id);
}
xdg_toplevel::Request::ShowWindowMenu {
seat: _,
serial: _,
x,
y,
} => {
let Some(panel_item) = data.lock().panel_item() else {return};
panel_item.toplevel_window_menu([x, y].into());
}
xdg_toplevel::Request::Move { seat, serial } => {
debug!(?xdg_toplevel, ?seat, serial, "XDG Toplevel move request");
let Some(panel_item) = data.lock().panel_item() else {return};
@@ -629,8 +623,6 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
data.lock().min_size = (width > 1 || height > 1)
.then_some(Vector2::from([width as u32, height as u32]));
}
xdg_toplevel::Request::SetMaximized => {}
xdg_toplevel::Request::UnsetMaximized => {}
xdg_toplevel::Request::SetFullscreen { output: _ } => {
let Some(panel_item) = data.lock().panel_item() else {return};
panel_item.backend.toplevel_state.lock().fullscreen = true;
@@ -641,13 +633,12 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
panel_item.backend.toplevel_state.lock().fullscreen = false;
panel_item.backend.configure(None);
}
xdg_toplevel::Request::SetMinimized => {}
xdg_toplevel::Request::Destroy => {
debug!(?xdg_toplevel, "Destroy XDG Toplevel");
let Some(panel_item) = data.lock().panel_item() else {return};
panel_item.drop_toplevel();
}
_ => unreachable!(),
_ => {}
}
}
}
@@ -863,16 +854,18 @@ impl XDGBackend {
popup: &XdgPopup,
data: &PopupData,
) {
let uid = data.uid.clone();
self.popups.lock().insert(uid.clone(), popup.downgrade());
self.popups
.lock()
.insert(data.uid.clone(), popup.downgrade());
let Some(positioner_data) = data.positioner_data() else {return};
panel_item.new_child(ChildInfo {
uid,
parent: data.parent_id.clone(),
geometry: positioner_data.into(),
})
panel_item.new_child(
&data.uid,
ChildInfo {
parent: data.parent_id.clone(),
geometry: positioner_data.into(),
},
)
}
pub fn reposition_popup(&self, panel_item: &PanelItem<XDGBackend>, popup_state: &PopupData) {
let Some(positioner_data) = popup_state.positioner_data() else {return};
@@ -890,21 +883,19 @@ impl XDGBackend {
self.seat.drop_surface(&wl_surface);
}
fn child_data(&self) -> Vec<ChildInfo> {
self.popups
.lock()
.values()
.filter_map(|v| {
let popup = v.upgrade().ok()?;
let data = PopupData::get(&popup)?;
let data_lock = data.lock();
Some(ChildInfo {
uid: data_lock.uid.clone(),
fn child_data(&self) -> FxHashMap<String, ChildInfo> {
FxHashMap::from_iter(self.popups.lock().values().filter_map(|v| {
let popup = v.upgrade().ok()?;
let data = PopupData::get(&popup)?;
let data_lock = data.lock();
Some((
data_lock.uid.clone(),
ChildInfo {
parent: data_lock.parent_id.clone(),
geometry: data_lock.positioner_data()?.into(),
})
})
.collect::<Vec<_>>()
},
))
}))
}
fn flush_client(&self) {
@@ -952,7 +943,10 @@ impl Backend for XDGBackend {
.lock()
.geometry
.clone()
.unwrap(),
.unwrap_or_else(|| Geometry {
origin: [0, 0].into(),
size,
}),
};
Ok(PanelItemInitData {
@@ -1017,18 +1011,21 @@ impl Backend for XDGBackend {
)
}
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
let Some(surface) = self.wl_surface_from_id(surface) else {return};
self.seat.keyboard_event(
&surface,
KeyboardEvent::Key {
key,
state: if state { 1 } else { 0 },
},
)
}
fn keyboard_keymap(&self, _surface: &SurfaceID, _keymap_id: &str) {
todo!()
let keymaps = KEYMAPS.lock();
let Some(keymap) = keymaps.get(keymap_id).cloned() else {return};
if self.seat.set_keymap(keymap, vec![surface.clone()]).is_err() {
return;
}
for key in keys {
self.seat.keyboard_event(
&surface,
KeyboardEvent::Key {
key: key.abs() as u32,
state: if key < 0 { 1 } else { 0 },
},
);
}
}
}

View File

@@ -4,6 +4,7 @@ use super::{
};
use crate::{
nodes::{
data::KEYMAPS,
drawable::model::ModelPart,
items::panel::{Backend, Geometry, PanelItem, PanelItemInitData, SurfaceID, ToplevelInfo},
},
@@ -13,6 +14,7 @@ use color_eyre::eyre::Result;
use mint::Vector2;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use smithay::{
reexports::{
calloop::{EventLoop, LoopSignal},
@@ -42,7 +44,7 @@ impl XWaylandState {
let (tx, rx) = oneshot::channel();
tokio::task::spawn_blocking(move || {
std::thread::spawn(move || {
let mut event_loop: EventLoop<XWaylandHandler> = EventLoop::try_new()?;
let (xwayland, connection) = XWayland::new(&dh);
let handle = event_loop.handle();
@@ -144,7 +146,7 @@ impl XwmHandler for XWaylandHandler {
let Some(wl_surface) = window.wl_surface() else {return};
let seat = seat.clone();
window.user_data().insert_if_missing_threadsafe(|| {
let (_node, panel_item) = PanelItem::create(
let panel_item = PanelItem::create(
Box::new(X11Backend {
toplevel_parent: None,
toplevel: window.clone(),
@@ -357,7 +359,7 @@ impl Backend for X11Backend {
.into(),
},
},
children: vec![],
children: FxHashMap::default(),
pointer_grab: self._pointer_grab.lock().clone(),
keyboard_grab: self._keyboard_grab.lock().clone(),
})
@@ -415,17 +417,21 @@ impl Backend for X11Backend {
)
}
fn keyboard_keymap(&self, surface: &SurfaceID, keymap_id: &str) {
todo!()
}
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
let Some(surface) = self.wl_surface_from_id(surface) else {return};
self.seat.keyboard_event(
&surface,
KeyboardEvent::Key {
key,
state: if state { 1 } else { 0 },
},
)
let keymaps = KEYMAPS.lock();
let Some(keymap) = keymaps.get(keymap_id).cloned() else {return};
if self.seat.set_keymap(keymap, vec![surface.clone()]).is_err() {
return;
}
for key in keys {
self.seat.keyboard_event(
&surface,
KeyboardEvent::Key {
key: key.abs() as u32,
state: if key < 0 { 1 } else { 0 },
},
);
}
}
}