1
0
Fork 0
forked from wry/wry

autocommit 2022-02-14 21:13:42 CET

This commit is contained in:
Julian Orth 2022-02-14 21:13:42 +01:00
parent 9b8e1ac29f
commit da6b29f138
44 changed files with 5903 additions and 364 deletions

View file

@ -3,7 +3,8 @@ use std::fmt::Debug;
use std::rc::Rc;
linear_ids!(OutputIds, OutputId);
linear_ids!(SeatIds, SeatId);
linear_ids!(KeyboardIds, KeyboardId);
linear_ids!(MouseIds, MouseId);
pub trait Output {
fn id(&self) -> OutputId;
@ -13,16 +14,24 @@ pub trait Output {
fn on_change(&self, cb: Rc<dyn Fn()>);
}
pub trait Seat {
fn id(&self) -> SeatId;
pub trait Keyboard {
fn id(&self) -> KeyboardId;
fn removed(&self) -> bool;
fn event(&self) -> Option<SeatEvent>;
fn event(&self) -> Option<KeyboardEvent>;
fn on_change(&self, cb: Rc<dyn Fn()>);
}
pub trait Mouse {
fn id(&self) -> MouseId;
fn removed(&self) -> bool;
fn event(&self) -> Option<MouseEvent>;
fn on_change(&self, cb: Rc<dyn Fn()>);
}
pub enum BackendEvent {
NewOutput(Rc<dyn Output>),
NewSeat(Rc<dyn Seat>),
NewKeyboard(Rc<dyn Keyboard>),
NewMouse(Rc<dyn Mouse>),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
@ -38,11 +47,15 @@ pub enum ScrollAxis {
}
#[derive(Debug)]
pub enum SeatEvent {
pub enum KeyboardEvent {
Key(u32, KeyState),
}
#[derive(Debug)]
pub enum MouseEvent {
OutputPosition(OutputId, Fixed, Fixed),
#[allow(dead_code)]
Motion(Fixed, Fixed),
Button(u32, KeyState),
Scroll(i32, ScrollAxis),
Key(u32, KeyState),
}

View file

@ -1,6 +1,4 @@
use crate::backend::{
BackendEvent, KeyState, Output, OutputId, ScrollAxis, Seat, SeatEvent, SeatId,
};
use crate::backend::{BackendEvent, Keyboard, KeyboardEvent, KeyboardId, KeyState, Mouse, MouseEvent, MouseId, Output, OutputId, ScrollAxis};
use crate::drm::drm::{Drm, DrmError};
use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
@ -519,14 +517,15 @@ impl XorgBackend {
}
fn handle_input_device(self: &Rc<Self>, info: &ffi::xcb_input_xi_device_info_t) {
if info.type_ != ffi::XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD as _ {
if info.type_ != ffi::XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD as u16 {
return;
}
let con = &self.con;
self.mouse_seats.remove(&info.attachment);
if let Some(kb) = self.seats.remove(&info.deviceid) {
kb.removed.set(true);
kb.changed();
kb.kb_changed();
kb.mouse_changed();
}
unsafe {
let mut err = ptr::null_mut();
@ -550,13 +549,16 @@ impl XorgBackend {
);
}
let seat = Rc::new(XorgSeat {
id: self.state.seat_ids.next(),
kb_id: self.state.kb_ids.next(),
mouse_id: self.state.mouse_ids.next(),
backend: self.clone(),
_kb: info.deviceid,
mouse: info.attachment,
removed: Cell::new(false),
cb: CloneCell::new(None),
events: RefCell::new(Default::default()),
kb_cb: Default::default(),
mouse_cb: Default::default(),
kb_events: RefCell::new(Default::default()),
mouse_events: RefCell::new(Default::default()),
button_map: Default::default(),
});
seat.update_button_map();
@ -564,7 +566,10 @@ impl XorgBackend {
self.mouse_seats.set(info.attachment, seat.clone());
self.state
.backend_events
.push(BackendEvent::NewSeat(seat.clone()));
.push(BackendEvent::NewMouse(seat.clone()));
self.state
.backend_events
.push(BackendEvent::NewKeyboard(seat.clone()));
}
}
@ -756,7 +761,7 @@ impl XorgBackend {
7 => (ScrollAxis::Horizontal, 15),
_ => unreachable!(),
};
seat.event(SeatEvent::Scroll(val, axis));
seat.mouse_event(MouseEvent::Scroll(val, axis));
}
} else {
const BTN_LEFT: u32 = 0x110;
@ -770,7 +775,7 @@ impl XorgBackend {
3 => BTN_RIGHT,
n => BTN_SIDE + n - 8,
};
seat.event(SeatEvent::Button(button, state));
seat.mouse_event(MouseEvent::Button(button, state));
}
}
Ok(())
@ -790,7 +795,7 @@ impl XorgBackend {
let event =
unsafe { (event as *const _ as *const ffi::xcb_input_key_press_event_t).deref() };
if let Some(seat) = self.seats.get(&event.deviceid) {
seat.event(SeatEvent::Key(event.detail - 8, state));
seat.kb_event(KeyboardEvent::Key(event.detail - 8, state));
}
Ok(())
}
@ -816,7 +821,8 @@ impl XorgBackend {
self.mouse_seats.remove(&info.attachment);
if let Some(seat) = self.seats.remove(&info.deviceid) {
seat.removed.set(true);
seat.changed();
seat.kb_changed();
seat.mouse_changed();
}
}
}
@ -832,7 +838,7 @@ impl XorgBackend {
self.outputs.get(&event.event),
self.mouse_seats.get(&event.deviceid),
) {
seat.event(SeatEvent::OutputPosition(
seat.mouse_event(MouseEvent::OutputPosition(
win.id,
Fixed::from_1616(event.event_x),
Fixed::from_1616(event.event_y),
@ -853,7 +859,7 @@ impl XorgBackend {
(Some(a), Some(b)) => (a, b),
_ => return Ok(()),
};
seat.event(SeatEvent::OutputPosition(
seat.mouse_event(MouseEvent::OutputPosition(
win.id,
Fixed::from_1616(event.event_x),
Fixed::from_1616(event.event_y),
@ -986,26 +992,40 @@ impl Output for XorgOutput {
}
struct XorgSeat {
id: SeatId,
kb_id: KeyboardId,
mouse_id: MouseId,
backend: Rc<XorgBackend>,
_kb: ffi::xcb_input_device_id_t,
mouse: ffi::xcb_input_device_id_t,
removed: Cell<bool>,
cb: CloneCell<Option<Rc<dyn Fn()>>>,
events: RefCell<VecDeque<SeatEvent>>,
kb_cb: CloneCell<Option<Rc<dyn Fn()>>>,
mouse_cb: CloneCell<Option<Rc<dyn Fn()>>>,
kb_events: RefCell<VecDeque<KeyboardEvent>>,
mouse_events: RefCell<VecDeque<MouseEvent>>,
button_map: CopyHashMap<u32, u32>,
}
impl XorgSeat {
fn changed(&self) {
if let Some(cb) = self.cb.get() {
fn kb_changed(&self) {
if let Some(cb) = self.kb_cb.get() {
cb();
}
}
fn event(&self, event: SeatEvent) {
self.events.borrow_mut().push_back(event);
self.changed();
fn mouse_changed(&self) {
if let Some(cb) = self.mouse_cb.get() {
cb();
}
}
fn mouse_event(&self, event: MouseEvent) {
self.mouse_events.borrow_mut().push_back(event);
self.mouse_changed();
}
fn kb_event(&self, event: KeyboardEvent) {
self.kb_events.borrow_mut().push_back(event);
self.kb_changed();
}
fn update_button_map(&self) {
@ -1041,20 +1061,38 @@ impl XorgSeat {
}
}
impl Seat for XorgSeat {
fn id(&self) -> SeatId {
self.id
impl Keyboard for XorgSeat {
fn id(&self) -> KeyboardId {
self.kb_id
}
fn removed(&self) -> bool {
self.removed.get()
}
fn event(&self) -> Option<SeatEvent> {
self.events.borrow_mut().pop_front()
fn event(&self) -> Option<KeyboardEvent> {
self.kb_events.borrow_mut().pop_front()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.cb.set(Some(cb));
self.kb_cb.set(Some(cb));
}
}
impl Mouse for XorgSeat {
fn id(&self) -> MouseId {
self.mouse_id
}
fn removed(&self) -> bool {
self.removed.get()
}
fn event(&self) -> Option<MouseEvent> {
self.mouse_events.borrow_mut().pop_front()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.mouse_cb.set(Some(cb));
}
}

154
src/config.rs Normal file
View file

@ -0,0 +1,154 @@
mod handler;
use crate::backend::{KeyboardId, MouseId};
use crate::utils::ptr_ext::PtrExt;
use crate::{NumCell, State};
use i4config::_private::ipc::{InitMessage, Request, V1InitMessage};
use i4config::_private::{bincode_ops, ConfigEntry, VERSION};
use i4config::keyboard::ModifiedKeySym;
use libloading::Library;
use std::cell::Cell;
use std::ptr;
use std::rc::Rc;
use thiserror::Error;
use i4config::{InputDevice, Keyboard, Mouse, Seat};
use crate::config::handler::ConfigProxyHandler;
use crate::ifs::wl_seat::{SeatId};
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("Could not load the config library")]
CouldNotLoadLibrary(#[source] libloading::Error),
#[error("Config library does not contain the entry symbol")]
LibraryDoesNotContainEntry(#[source] libloading::Error),
}
pub struct ConfigProxy {
handler: Rc<ConfigProxyHandler>,
}
impl ConfigProxy {
pub fn invoke_shortcut(&self, seat: SeatId, modsym: &ModifiedKeySym) {
self.handler.send(&Request::InvokeShortcut {
seat: Seat(seat.raw() as _),
mods: modsym.mods,
sym: modsym.sym,
});
}
pub fn new_keyboard(&self, kb: KeyboardId) {
self.handler.send(&Request::NewInputDevice {
device: InputDevice::Keyboard(Keyboard(kb.raw() as _)),
});
}
pub fn new_mouse(&self, mouse: MouseId) {
self.handler.send(&Request::NewInputDevice {
device: InputDevice::Mouse(Mouse(mouse.raw() as _)),
});
}
pub fn del_keyboard(&self, kb: KeyboardId) {
self.handler.send(&Request::DelInputDevice {
device: InputDevice::Keyboard(Keyboard(kb.raw() as _)),
});
}
pub fn del_mouse(&self, mouse: MouseId) {
self.handler.send(&Request::DelInputDevice {
device: InputDevice::Mouse(Mouse(mouse.raw() as _)),
});
}
}
impl Drop for ConfigProxy {
fn drop(&mut self) {
unsafe {
self.handler.dropped.set(true);
(self.handler.unref)(self.handler.client_data.get());
}
}
}
unsafe extern "C" fn default_client_init(
srv_data: *const u8,
srv_unref: unsafe extern "C" fn(data: *const u8),
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
msg: *const u8,
size: usize,
) -> *const u8 {
extern "C" fn configure() {
default_config::configure();
}
i4config::_private::client::init(srv_data, srv_unref, srv_handler, msg, size, configure)
}
impl ConfigProxy {
fn new(lib: Option<Library>, entry: &ConfigEntry, state: &Rc<State>) -> Self {
let version = entry.version.min(VERSION);
let data = Rc::new(ConfigProxyHandler {
client_data: Cell::new(ptr::null()),
dropped: Cell::new(false),
_lib: lib,
_version: version,
unref: entry.unref,
handle_msg: entry.handle_msg,
state: state.clone(),
next_id: NumCell::new(1),
keymaps: Default::default(),
bufs: Default::default(),
});
let init_msg =
bincode::encode_to_vec(&InitMessage::V1(V1InitMessage {}), bincode_ops()).unwrap();
unsafe {
let client_data = (entry.init)(
Rc::into_raw(data.clone()) as _,
unref,
handle_msg,
init_msg.as_ptr(),
init_msg.len(),
);
data.client_data.set(client_data);
}
data.send(&Request::Configure);
Self { handler: data }
}
pub fn default(state: &Rc<State>) -> Self {
let entry = ConfigEntry {
version: VERSION,
init: default_client_init,
unref: i4config::_private::client::unref,
handle_msg: i4config::_private::client::handle_msg,
};
Self::new(None, &entry, state)
}
#[allow(dead_code)]
pub unsafe fn from_file(path: &str, state: &Rc<State>) -> Result<Self, ConfigError> {
let lib = match Library::new(path) {
Ok(l) => l,
Err(e) => return Err(ConfigError::CouldNotLoadLibrary(e)),
};
let entry = lib.get::<&'static ConfigEntry>(b"I4_CONFIG_ENTRY\0");
let entry = match entry {
Ok(e) => *e,
Err(e) => return Err(ConfigError::LibraryDoesNotContainEntry(e)),
};
Ok(Self::new(Some(lib), entry, state))
}
}
unsafe extern "C" fn unref(data: *const u8) {
let server = data as *const ConfigProxyHandler;
drop(Rc::from_raw(server));
}
unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
let server = (data as *const ConfigProxyHandler).deref();
if server.dropped.get() {
return;
}
let msg = std::slice::from_raw_parts(msg, size);
server.handle_request(msg);
}

370
src/config/handler.rs Normal file
View file

@ -0,0 +1,370 @@
use std::cell::{Cell};
use std::rc::Rc;
use bincode::error::DecodeError;
use libloading::Library;
use log::Level;
use thiserror::Error;
use i4config::_private::bincode_ops;
use i4config::_private::ipc::{Request, Response};
use i4config::keyboard::keymap::Keymap;
use i4config::{Direction, InputDevice, Keyboard, LogLevel, Mouse, Seat};
use i4config::keyboard::mods::Modifiers;
use i4config::keyboard::syms::KeySym;
use crate::{ErrorFmt, NumCell, State};
use crate::backend::{KeyboardId, MouseId};
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::state::DeviceHandlerData;
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::debug_fn::debug_fn;
use crate::utils::stack::Stack;
use crate::xkbcommon::XkbKeymap;
pub(super) struct ConfigProxyHandler {
pub client_data: Cell<*const u8>,
pub dropped: Cell<bool>,
pub _lib: Option<Library>,
pub _version: u32,
pub unref: unsafe extern "C" fn(data: *const u8),
pub handle_msg: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
pub state: Rc<State>,
pub next_id: NumCell<u64>,
pub keymaps: CopyHashMap<Keymap, Rc<XkbKeymap>>,
pub bufs: Stack<Vec<u8>>,
}
impl ConfigProxyHandler {
pub fn send(&self, msg: &Request) {
let mut buf = self.bufs.pop().unwrap_or_default();
buf.clear();
bincode::encode_into_std_write(msg, &mut buf, bincode_ops()).unwrap();
unsafe {
(self.handle_msg)(self.client_data.get(), buf.as_ptr(), buf.len());
}
self.bufs.push(buf);
}
fn id(&self) -> u64 {
self.next_id.fetch_add(1)
}
fn handle_log_request(&self, level: LogLevel, msg: &str, file: Option<&str>, line: Option<u32>) -> Result<(), LogError> {
let level = match level {
LogLevel::Error => Level::Error,
LogLevel::Warn => Level::Warn,
LogLevel::Info => Level::Info,
LogLevel::Debug => Level::Debug,
LogLevel::Trace => Level::Trace,
};
let debug = debug_fn(|fmt| {
if let Some(file) = file {
write!(fmt, "{}", file)?;
if let Some(line) = line {
write!(fmt, ":{}", line)?;
}
write!(fmt, ": ")?;
}
write!(fmt, "{}", msg)?;
Ok(())
});
log::log!(level, "{:?}", debug);
Ok(())
}
fn handle_create_seat(&self, name: &str) -> Result<(), CreateSeatError> {
let global_name = self.state.globals.name();
let seat = WlSeatGlobal::new(global_name, name, &self.state);
self.state.globals.add_global(&self.state, &seat);
self.send(&Request::Response {
response: Response::CreateSeat {
seat: Seat(seat.id().raw() as _),
}
});
Ok(())
}
fn handle_parse_keymap(&self, keymap: &str) -> Result<(), ParseKeymapError> {
let (keymap, res) = match self.state.xkb_ctx.keymap_from_str(keymap) {
Ok(keymap) => {
let id = Keymap(self.id());
self.keymaps.set(id, keymap);
(id, Ok(()))
}
_ => {
(Keymap::INVALID, Err(ParseKeymapError::ParsingFailed))
}
};
self.send(&Request::Response { response: Response::ParseKeymap { keymap } });
res
}
fn handle_set_keymap(&self, seat: Seat, keymap: Keymap) -> Result<(), SeatSetKeymapError> {
let seat = self.get_seat(seat)?;
let keymap = if keymap.is_invalid() {
self.state.default_keymap.clone()
} else {
self.get_keymap(keymap)?
};
seat.set_keymap(&keymap);
Ok(())
}
fn handle_focus(&self, seat: Seat, direction: Direction) -> Result<(), FocusError> {
let seat = self.get_seat(seat)?;
seat.move_focus(direction);
Ok(())
}
fn handle_get_repeat_rate(&self, seat: Seat) -> Result<(), SeatGetRepeatRateError> {
let seat = self.get_seat(seat)?;
let (rate, delay) = seat.get_rate();
self.send(&Request::Response {
response: Response::GetRepeatRate {
rate,
delay,
},
});
Ok(())
}
fn handle_set_repeat_rate(&self, seat: Seat, rate: i32, delay: i32) -> Result<(), SeatSetRepeatRateError> {
let seat = self.get_seat(seat)?;
if rate < 0 {
return Err(SeatSetRepeatRateError::NegativeRate);
}
if delay < 0 {
return Err(SeatSetRepeatRateError::NegativeDelay);
}
seat.set_rate(rate, delay);
Ok(())
}
fn get_device_handler_data(&self, device: InputDevice) -> Result<Rc<DeviceHandlerData>, CphError> {
let data = match device {
InputDevice::Keyboard(kb) => {
self.state.kb_handlers.borrow_mut().get(&KeyboardId::from_raw(kb.0 as _)).map(|d| d.data.clone())
},
InputDevice::Mouse(mouse) => {
self.state.mouse_handlers.borrow_mut().get(&MouseId::from_raw(mouse.0 as _)).map(|d| d.data.clone())
}
};
match data {
Some(d) => Ok(d),
_ => Err(CphError::DeviceDoesNotExist(device)),
}
}
fn get_seat(&self, seat: Seat) -> Result<Rc<WlSeatGlobal>, CphError> {
let seats = self.state.globals.seats.lock();
for seat_global in seats.values() {
if seat_global.id().raw() == seat.0 as _ {
return Ok(seat_global.clone());
}
}
Err(CphError::SeatDoesNotExist(seat))
}
fn get_keymap(&self, keymap: Keymap) -> Result<Rc<XkbKeymap>, CphError> {
match self.keymaps.get(&keymap) {
Some(k) => Ok(k),
None => Err(CphError::KeymapDoesNotExist(keymap)),
}
}
fn handle_set_seat(&self, device: InputDevice, seat: Seat) -> Result<(), SetSeatError> {
let seat = if seat.is_invalid() {
None
} else {
Some(self.get_seat(seat)?)
};
let dev = self.get_device_handler_data(device)?;
dev.seat.set(seat);
Ok(())
}
fn handle_add_shortcut(&self, seat: Seat, mods: Modifiers, sym: KeySym) -> Result<(), AddShortcutError> {
let seat = self.get_seat(seat)?;
seat.add_shortcut(mods, sym);
Ok(())
}
fn handle_get_input_devices(&self) -> Result<(), GetInputDevicesError> {
let mut res = vec!();
{
let devs = self.state.kb_handlers.borrow_mut();
for dev in devs.values() {
res.push(InputDevice::Keyboard(Keyboard(dev.id.raw() as _)));
}
}
{
let devs = self.state.mouse_handlers.borrow_mut();
for dev in devs.values() {
res.push(InputDevice::Mouse(Mouse(dev.id.raw() as _)));
}
}
self.send(&Request::Response {
response: Response::GetInputDevices { devices: res },
});
Ok(())
}
fn handle_get_seats(&self) -> Result<(), GetSeatsError> {
let seats = {
let seats = self.state.globals.seats.lock();
seats
.values()
.map(|seat| Seat::from_raw(seat.id().raw() as _))
.collect()
};
self.send(&Request::Response {
response: Response::GetSeats { seats },
});
Ok(())
}
pub fn handle_request(&self, msg: &[u8]) {
if let Err(e) = self.handle_request_(msg) {
log::error!("Could not handle client request: {}", ErrorFmt(e));
}
}
fn handle_request_(&self, msg: &[u8]) -> Result<(), CphError> {
let (request, _) = match bincode::decode_from_slice::<Request, _>(msg, bincode_ops()) {
Ok(msg) => msg,
Err(e) => return Err(CphError::ParsingFailed(e)),
};
match request {
Request::Log {
level,
msg,
file,
line,
} => self.handle_log_request(level, msg, file, line)?,
Request::CreateSeat { name } => self.handle_create_seat(name)?,
Request::ParseKeymap { keymap } => self.handle_parse_keymap(keymap)?,
Request::SeatSetKeymap { seat, keymap } => self.handle_set_keymap(seat, keymap)?,
Request::SeatGetRepeatRate { seat } => self.handle_get_repeat_rate(seat)?,
Request::SeatSetRepeatRate { seat, rate, delay } => self.handle_set_repeat_rate(seat, rate, delay)?,
Request::SetSeat { device, seat } => self.handle_set_seat(device, seat)?,
Request::AddShortcut {
seat,
mods,
sym,
} => self.handle_add_shortcut(seat, mods, sym)?,
Request::RemoveShortcut { .. } => {}
Request::Focus { seat, direction } => self.handle_focus(seat, direction)?,
Request::Move { seat, direction } => {}
Request::GetInputDevices => self.handle_get_input_devices()?,
Request::GetSeats => self.handle_get_seats()?,
m => return Err(CphError::UnexpectedMessage(format!("{:?}", m))),
}
Ok(())
}
}
#[derive(Debug, Error)]
enum CphError {
#[error("Could not process a `log` request")]
LogError(#[from] LogError),
#[error("Could not process a `create_seat` request")]
CreateSeatError(#[from] CreateSeatError),
#[error("Could not process a `parse_keymap` request")]
ParseKeymapError(#[from] ParseKeymapError),
#[error("Could not process a `set_seat` request")]
SetSeatError(#[from] SetSeatError),
#[error("Could not process a `add_shortcut` request")]
AddShortcutError(#[from] AddShortcutError),
#[error("Could not process a `get_input_devices` request")]
GetInputDevicesError(#[from] GetInputDevicesError),
#[error("Could not process a `get_seats` request")]
GetSeatsError(#[from] GetSeatsError),
#[error("Could not process a `set_keymap` request")]
SeatSetKeymapError(#[from] SeatSetKeymapError),
#[error("Could not process a `get_repeat_rate` request")]
SeatGetRepeatRateError(#[from] SeatGetRepeatRateError),
#[error("Could not process a `set_repeat_rate` request")]
SeatSetRepeatRateError(#[from] SeatSetRepeatRateError),
#[error("Could not process a `focus` request")]
FocusError(#[from] FocusError),
#[error("Device {0:?} does not exist")]
DeviceDoesNotExist(InputDevice),
#[error("Device {0:?} does not exist")]
KeymapDoesNotExist(Keymap),
#[error("Seat {0:?} does not exist")]
SeatDoesNotExist(Seat),
#[error("Seat {0:?} does not exist")]
UnexpectedMessage(String),
#[error("Could not parse the message")]
ParsingFailed(#[source] DecodeError),
}
#[derive(Debug, Error)]
enum LogError {
}
#[derive(Debug, Error)]
enum CreateSeatError {
}
#[derive(Debug, Error)]
enum ParseKeymapError {
#[error("Parsing failed")]
ParsingFailed,
}
#[derive(Debug, Error)]
enum SetSeatError {
#[error(transparent)]
CphError(#[from] Box<CphError>),
}
efrom!(SetSeatError, CphError);
#[derive(Debug, Error)]
enum AddShortcutError {
#[error(transparent)]
CphError(#[from] Box<CphError>),
}
efrom!(AddShortcutError, CphError);
#[derive(Debug, Error)]
enum GetInputDevicesError {
}
#[derive(Debug, Error)]
enum GetSeatsError {
}
#[derive(Debug, Error)]
enum SeatSetKeymapError {
#[error(transparent)]
CphError(#[from] Box<CphError>),
}
efrom!(SeatSetKeymapError, CphError);
#[derive(Debug, Error)]
enum SeatSetRepeatRateError {
#[error(transparent)]
CphError(#[from] Box<CphError>),
#[error("Rate is negative")]
NegativeRate,
#[error("Delay is negative")]
NegativeDelay,
}
efrom!(SeatSetRepeatRateError, CphError);
#[derive(Debug, Error)]
enum SeatGetRepeatRateError {
#[error(transparent)]
CphError(#[from] Box<CphError>),
}
efrom!(SeatGetRepeatRateError, CphError);
#[derive(Debug, Error)]
enum FocusError {
#[error(transparent)]
CphError(#[from] Box<CphError>),
}
efrom!(FocusError, CphError);

View file

@ -4,7 +4,6 @@ pub mod wl_keyboard;
pub mod wl_pointer;
pub mod wl_touch;
use crate::backend::{Seat, SeatId};
use crate::client::{Client, ClientError, ClientId};
use crate::cursor::{Cursor, KnownCursor};
use crate::fixed::Fixed;
@ -29,24 +28,25 @@ use crate::utils::buffd::MsgParser;
use crate::utils::buffd::MsgParserError;
use crate::utils::clonecell::CloneCell;
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::linkedlist::LinkedList;
use crate::utils::linkedlist::{LinkedList, LinkedNode};
use crate::wire::wl_seat::*;
use crate::wire::{
WlDataDeviceId, WlKeyboardId, WlPointerId, WlSeatId, ZwpPrimarySelectionDeviceV1Id,
};
use crate::xkbcommon::{XkbContext, XkbState};
use crate::{NumCell, State};
use crate::xkbcommon::{XkbKeymap, XkbState};
use crate::{ErrorFmt, NumCell, State};
use ahash::{AHashMap, AHashSet};
use bstr::ByteSlice;
pub use event_handling::NodeSeatState;
use i4config::keyboard::mods::Modifiers;
use std::cell::{Cell, RefCell};
use std::collections::hash_map::Entry;
use std::io::Write;
use std::mem;
use std::ops::DerefMut;
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, OwnedFd};
use uapi::{c, Errno, OwnedFd};
use i4config::Direction;
use crate::async_engine::SpawnedFuture;
const POINTER: u32 = 1;
const KEYBOARD: u32 = 2;
@ -79,11 +79,13 @@ impl Drop for DroppedDnd {
}
}
linear_ids!(SeatIds, SeatId);
pub struct WlSeatGlobal {
id: SeatId,
name: GlobalName,
state: Rc<State>,
seat: Rc<dyn Seat>,
seat_name: Rc<String>,
seat_name: String,
move_: Cell<bool>,
move_start_pos: Cell<(Fixed, Fixed)>,
extents_start_pos: Cell<(i32, i32)>,
@ -101,9 +103,9 @@ pub struct WlSeatGlobal {
AHashMap<ZwpPrimarySelectionDeviceV1Id, Rc<ZwpPrimarySelectionDeviceV1>>,
>,
>,
repeat_rate: Cell<(i32, i32)>,
kb_map: CloneCell<Rc<XkbKeymap>>,
kb_state: RefCell<XkbState>,
layout: Rc<OwnedFd>,
layout_size: u32,
cursor: CloneCell<Option<Rc<dyn Cursor>>>,
serial: NumCell<u32>,
tree_changed: Rc<AsyncEvent>,
@ -111,37 +113,22 @@ pub struct WlSeatGlobal {
primary_selection: CloneCell<Option<Rc<ZwpPrimarySelectionSourceV1>>>,
pointer_owner: PointerOwnerHolder,
dropped_dnd: RefCell<Option<DroppedDnd>>,
shortcuts: CopyHashMap<(u32, u32), Modifiers>,
queue_link: Cell<Option<LinkedNode<Rc<Self>>>>,
tree_changed_handler: Cell<Option<SpawnedFuture<()>>>,
}
impl WlSeatGlobal {
pub fn new(
name: GlobalName,
seat_name: &str,
state: &Rc<State>,
seat: &Rc<dyn Seat>,
tree_changed: &Rc<AsyncEvent>,
) -> Self {
let (kb_state, layout, layout_size) = {
let ctx = XkbContext::new().unwrap();
let keymap = ctx.default_keymap().unwrap();
let state = keymap.state().unwrap();
let string = keymap.as_str().unwrap();
let mut memfd =
uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
memfd.write_all(string.as_bytes()).unwrap();
memfd.write_all(&[0]).unwrap();
uapi::lseek(memfd.raw(), 0, c::SEEK_SET).unwrap();
uapi::fcntl_add_seals(
memfd.raw(),
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
)
.unwrap();
(state, Rc::new(memfd), (string.len() + 1) as _)
};
Self {
) -> Rc<Self> {
let slf = Rc::new(Self {
id: state.seat_ids.next(),
name,
state: state.clone(),
seat: seat.clone(),
seat_name: Rc::new(format!("seat-{}", seat.id())),
seat_name: seat_name.to_string(),
move_: Cell::new(false),
move_start_pos: Cell::new((Fixed(0), Fixed(0))),
extents_start_pos: Cell::new((0, 0)),
@ -154,19 +141,79 @@ impl WlSeatGlobal {
bindings: Default::default(),
data_devices: RefCell::new(Default::default()),
primary_selection_devices: RefCell::new(Default::default()),
kb_state: RefCell::new(kb_state),
layout,
layout_size,
repeat_rate: Cell::new((25, 250)),
kb_map: CloneCell::new(state.default_keymap.clone()),
kb_state: RefCell::new(state.default_keymap.state().unwrap()),
cursor: Default::default(),
serial: Default::default(),
tree_changed: tree_changed.clone(),
tree_changed: Default::default(),
selection: Default::default(),
primary_selection: Default::default(),
pointer_owner: Default::default(),
dropped_dnd: RefCell::new(None),
shortcuts: Default::default(),
queue_link: Cell::new(None),
tree_changed_handler: Cell::new(None),
});
let seat = slf.clone();
state.eng.spawn(async move {
loop {
seat.tree_changed.triggered().await;
seat.state.tree_changed_sent.set(false);
seat.tree_changed();
}
});
slf
}
pub fn mark_last_active(self: &Rc<Self>) {
self.queue_link.set(Some(self.state.seat_queue.add_last(self.clone())));
}
pub fn set_keymap(&self, keymap: &Rc<XkbKeymap>) {
self.kb_map.set(keymap.clone());
let bindings = self.bindings.borrow_mut();
for (id, client) in bindings.iter() {
for seat in client.values() {
let kbs = seat.keyboards.lock();
for kb in kbs.values() {
let fd = match seat.keymap_fd(&keymap) {
Ok(fd) => fd,
Err(e) => {
log::error!("Could not creat a file descriptor to transfer the keymap to client {}: {}", id, ErrorFmt(e));
continue;
}
};
kb.send_keymap(wl_keyboard::XKB_V1, fd, keymap.map_len as _);
}
}
}
}
pub fn get_rate(&self) -> (i32, i32) {
self.repeat_rate.get()
}
pub fn set_rate(&self, rate: i32, delay: i32) {
self.repeat_rate.set((rate, delay));
let bindings = self.bindings.borrow_mut();
for client in bindings.values() {
for seat in client.values() {
if seat.version >= REPEAT_INFO_SINCE {
let kbs = seat.keyboards.lock();
for kb in kbs.values() {
kb.send_repeat_info(rate, delay);
}
}
}
}
}
pub fn move_focus(self: &Rc<Self>, direction: Direction) {
let kb_node = self.keyboard_node.get();
kb_node.move_focus(self, direction);
}
fn set_selection_<T: ipc::Vtable>(
self: &Rc<Self>,
field: &CloneCell<Option<Rc<T::Source>>>,
@ -275,7 +322,7 @@ impl WlSeatGlobal {
}
pub fn id(&self) -> SeatId {
self.seat.id()
self.id
}
fn bind_(
@ -321,6 +368,8 @@ impl Global for WlSeatGlobal {
fn break_loops(&self) {
self.bindings.borrow_mut().clear();
self.queue_link.take();
self.tree_changed_handler.take();
}
}
@ -336,6 +385,8 @@ pub struct WlSeat {
tracker: Tracker<Self>,
}
const READ_ONLY_KEYMAP_SINCE: u32 = 7;
impl WlSeat {
fn send_capabilities(self: &Rc<Self>) {
self.client.event(Capabilities {
@ -404,13 +455,41 @@ impl WlSeat {
track!(self.client, p);
self.client.add_client_obj(&p)?;
self.keyboards.set(req.id, p.clone());
p.send_keymap(wl_keyboard::XKB_V1, p.keymap_fd()?, self.global.layout_size);
let keymap = self.global.kb_map.get();
p.send_keymap(wl_keyboard::XKB_V1, self.keymap_fd(&keymap)?, keymap.map_len as _);
if self.version >= REPEAT_INFO_SINCE {
p.send_repeat_info(25, 250);
let (rate, delay) = self.global.repeat_rate.get();
p.send_repeat_info(rate, delay);
}
Ok(())
}
pub fn keymap_fd(&self, keymap: &XkbKeymap) -> Result<Rc<OwnedFd>, WlKeyboardError> {
if self.version >= READ_ONLY_KEYMAP_SINCE {
return Ok(keymap.map.clone());
}
let fd = match uapi::memfd_create("shared-keymap", c::MFD_CLOEXEC) {
Ok(fd) => fd,
Err(e) => return Err(WlKeyboardError::KeymapMemfd(e.into())),
};
let target = keymap.map_len as c::off_t;
let mut pos = 0;
while pos < target {
let rem = target - pos;
let res = uapi::sendfile(
fd.raw(),
keymap.map.raw(),
Some(&mut pos),
rem as usize,
);
match res {
Ok(_) | Err(Errno(c::EINTR)) => {}
Err(e) => return Err(WlKeyboardError::KeymapCopy(e.into())),
}
}
Ok(Rc::new(fd))
}
fn get_touch(self: &Rc<Self>, parser: MsgParser<'_, '_>) -> Result<(), GetTouchError> {
let req: GetTouch = self.client.parse(&**self, parser)?;
let p = Rc::new(WlTouch::new(req.id, self));

View file

@ -1,4 +1,4 @@
use crate::backend::{KeyState, OutputId, ScrollAxis, SeatEvent, SeatId};
use crate::backend::{KeyboardEvent, KeyState, MouseEvent, OutputId, ScrollAxis};
use crate::client::{Client, ClientId};
use crate::fixed::Fixed;
use crate::ifs::ipc;
@ -6,7 +6,7 @@ use crate::ifs::ipc::wl_data_device::WlDataDevice;
use crate::ifs::ipc::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1;
use crate::ifs::wl_seat::wl_keyboard::WlKeyboard;
use crate::ifs::wl_seat::wl_pointer::{WlPointer, POINTER_FRAME_SINCE_VERSION};
use crate::ifs::wl_seat::{wl_keyboard, wl_pointer, Dnd, WlSeat, WlSeatGlobal};
use crate::ifs::wl_seat::{wl_keyboard, wl_pointer, Dnd, WlSeat, WlSeatGlobal, SeatId};
use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup;
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
@ -17,6 +17,10 @@ use crate::utils::clonecell::CloneCell;
use crate::utils::smallmap::SmallMap;
use crate::wire::WlDataOfferId;
use crate::xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP};
use i4config::keyboard::mods::Modifiers;
use i4config::keyboard::syms::KeySym;
use i4config::keyboard::ModifiedKeySym;
use smallvec::SmallVec;
use std::ops::Deref;
use std::rc::Rc;
@ -30,37 +34,37 @@ pub struct NodeSeatState {
impl NodeSeatState {
pub(super) fn enter(&self, seat: &Rc<WlSeatGlobal>) {
self.pointer_foci.insert(seat.seat.id(), seat.clone());
self.pointer_foci.insert(seat.id, seat.clone());
}
pub(super) fn leave(&self, seat: &WlSeatGlobal) {
self.pointer_foci.remove(&seat.seat.id());
self.pointer_foci.remove(&seat.id);
}
pub(super) fn focus(&self, seat: &Rc<WlSeatGlobal>) -> bool {
self.kb_foci.insert(seat.seat.id(), seat.clone());
self.kb_foci.insert(seat.id, seat.clone());
self.kb_foci.len() == 1
}
pub(super) fn unfocus(&self, seat: &WlSeatGlobal) -> bool {
self.kb_foci.remove(&seat.seat.id());
self.kb_foci.remove(&seat.id);
self.kb_foci.len() == 0
}
pub(super) fn add_pointer_grab(&self, seat: &Rc<WlSeatGlobal>) {
self.grabs.insert(seat.id(), seat.clone());
self.grabs.insert(seat.id, seat.clone());
}
pub(super) fn remove_pointer_grab(&self, seat: &WlSeatGlobal) {
self.grabs.remove(&seat.id());
self.grabs.remove(&seat.id);
}
pub(super) fn add_dnd_target(&self, seat: &Rc<WlSeatGlobal>) {
self.dnd_targets.insert(seat.id(), seat.clone());
self.dnd_targets.insert(seat.id, seat.clone());
}
pub(super) fn remove_dnd_target(&self, seat: &WlSeatGlobal) {
self.dnd_targets.remove(&seat.id());
self.dnd_targets.remove(&seat.id);
}
// pub fn remove_pointer_grabs(&self) {
@ -100,13 +104,18 @@ impl NodeSeatState {
}
impl WlSeatGlobal {
pub fn event(self: &Rc<Self>, event: SeatEvent) {
pub fn kb_event(self: &Rc<Self>, event: KeyboardEvent) {
match event {
SeatEvent::OutputPosition(o, x, y) => self.output_position_event(o, x, y),
SeatEvent::Motion(dx, dy) => self.motion_event(dx, dy),
SeatEvent::Button(b, s) => self.pointer_owner.button(self, b, s),
SeatEvent::Scroll(d, a) => self.pointer_owner.scroll(self, d, a),
SeatEvent::Key(k, s) => self.key_event(k, s),
KeyboardEvent::Key(k, s) => self.key_event(k, s),
}
}
pub fn mouse_event(self: &Rc<Self>, event: MouseEvent) {
match event {
MouseEvent::OutputPosition(o, x, y) => self.output_position_event(o, x, y),
MouseEvent::Motion(dx, dy) => self.motion_event(dx, dy),
MouseEvent::Button(b, s) => self.pointer_owner.button(self, b, s),
MouseEvent::Scroll(d, a) => self.pointer_owner.scroll(self, d, a),
}
}
@ -143,9 +152,35 @@ impl WlSeatGlobal {
}
}
};
let mods = self.kb_state.borrow_mut().update(key, xkb_dir);
let mut shortcuts = SmallVec::<[_; 1]>::new();
let new_mods;
{
let mut kb_state = self.kb_state.borrow_mut();
if state == wl_keyboard::PRESSED {
let old_mods = kb_state.mods();
let keysyms = kb_state.unmodified_keysyms(key);
for &sym in keysyms {
if let Some(mods) = self.shortcuts.get(&(old_mods.mods_effective, sym)) {
shortcuts.push(ModifiedKeySym {
mods,
sym: KeySym(sym),
});
}
}
}
new_mods = kb_state.update(key, xkb_dir);
}
let node = self.keyboard_node.get();
node.key(self, key, state, mods);
if shortcuts.is_empty() {
node.key(self, key, state);
} else if let Some(config) = self.state.config.get() {
for shortcut in shortcuts {
config.invoke_shortcut(self.id(), &shortcut);
}
}
if let Some(mods) = new_mods {
node.mods(self, mods);
}
}
}
@ -206,6 +241,7 @@ impl WlSeatGlobal {
mods_latched,
mods_locked,
group,
..
} = self.kb_state.borrow().mods();
let serial = self.serial.fetch_add(1);
self.surface_kb_event(0, &surface, |k| {
@ -331,7 +367,15 @@ impl WlSeatGlobal {
self.handle_new_position(true);
}
pub fn tree_changed(self: &Rc<Self>) {
pub fn add_shortcut(&self, mods: Modifiers, keysym: KeySym) {
self.shortcuts.set((mods.0, keysym.0), mods);
}
pub fn trigger_tree_changed(&self) {
self.tree_changed.trigger();
}
pub(super) fn tree_changed(self: &Rc<Self>) {
self.handle_new_position(false);
}
@ -417,27 +461,25 @@ impl WlSeatGlobal {
// Key callbacks
impl WlSeatGlobal {
pub fn key_surface(
&self,
surface: &WlSurface,
key: u32,
state: u32,
mods: Option<ModifierState>,
) {
pub fn key_surface(&self, surface: &WlSurface, key: u32, state: u32) {
let serial = self.serial.fetch_add(1);
self.surface_kb_event(0, surface, |k| k.send_key(serial, 0, key, state));
}
}
// Modifiers callbacks
impl WlSeatGlobal {
pub fn mods_surface(&self, surface: &WlSurface, mods: ModifierState) {
let serial = self.serial.fetch_add(1);
if let Some(mods) = mods {
self.surface_kb_event(0, surface, |k| {
k.send_modifiers(
serial,
mods.mods_depressed,
mods.mods_latched,
mods.mods_locked,
mods.group,
)
});
}
self.surface_kb_event(0, surface, |k| {
k.send_modifiers(
serial,
mods.mods_depressed,
mods.mods_latched,
mods.mods_locked,
mods.group,
)
});
}
}

View file

@ -8,7 +8,7 @@ use crate::wire::wl_keyboard::*;
use crate::wire::{WlKeyboardId, WlSurfaceId};
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, Errno, OwnedFd};
use uapi::{OwnedFd};
pub const REPEAT_INFO_SINCE: u32 = 4;
@ -34,36 +34,6 @@ impl WlKeyboard {
}
}
pub fn needs_dedicated_keymap_fd(&self) -> bool {
self.seat.version < 7
}
pub fn keymap_fd(&self) -> Result<Rc<OwnedFd>, WlKeyboardError> {
if !self.needs_dedicated_keymap_fd() {
return Ok(self.seat.global.layout.clone());
}
let fd = match uapi::memfd_create("shared-keymap", c::MFD_CLOEXEC) {
Ok(fd) => fd,
Err(e) => return Err(WlKeyboardError::KeymapMemfd(e.into())),
};
let target = self.seat.global.layout_size as c::off_t;
let mut pos = 0;
while pos < target {
let rem = target - pos;
let res = uapi::sendfile(
fd.raw(),
self.seat.global.layout.raw(),
Some(&mut pos),
rem as usize,
);
match res {
Ok(_) | Err(Errno(c::EINTR)) => {}
Err(e) => return Err(WlKeyboardError::KeymapCopy(e.into())),
}
}
Ok(Rc::new(fd))
}
pub fn send_keymap(self: &Rc<Self>, format: u32, fd: Rc<OwnedFd>, size: u32) {
self.seat.client.event(Keymap {
self_id: self.id,

View file

@ -2,12 +2,11 @@ pub mod cursor;
pub mod wl_subsurface;
pub mod xdg_surface;
use crate::backend::{KeyState, ScrollAxis, SeatId};
use crate::client::{Client, ClientError, RequestParser};
use crate::fixed::Fixed;
use crate::ifs::wl_buffer::WlBuffer;
use crate::ifs::wl_callback::WlCallback;
use crate::ifs::wl_seat::{Dnd, NodeSeatState, WlSeatGlobal};
use crate::ifs::wl_seat::{Dnd, NodeSeatState, SeatId, WlSeatGlobal};
use crate::ifs::wl_surface::cursor::CursorSurface;
use crate::ifs::wl_surface::wl_subsurface::WlSubsurface;
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceRole};
@ -32,6 +31,8 @@ use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use thiserror::Error;
use i4config::Direction;
use crate::backend::{KeyState, ScrollAxis};
#[allow(dead_code)]
const INVALID_SCALE: u32 = 0;
@ -609,6 +610,14 @@ impl Node for WlSurface {
self.seat_state.destroy_node(self);
}
fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let xdg = match self.xdg.get() {
Some(x) => x,
_ => return,
};
xdg.move_focus(seat, direction);
}
fn absolute_position(&self) -> Rect {
self.buffer_abs_pos.get()
}
@ -619,8 +628,12 @@ impl Node for WlSurface {
}
}
fn key(&self, seat: &WlSeatGlobal, key: u32, state: u32, mods: Option<ModifierState>) {
seat.key_surface(self, key, state, mods);
fn key(&self, seat: &WlSeatGlobal, key: u32, state: u32) {
seat.key_surface(self, key, state);
}
fn mods(&self, seat: &WlSeatGlobal, mods: ModifierState) {
seat.mods_surface(self, mods);
}
fn button(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, button: u32, state: KeyState) {
@ -665,10 +678,6 @@ impl Node for WlSurface {
Some(self)
}
fn dnd_enter(&self, dnd: &Dnd, x: Fixed, y: Fixed) {
dnd.seat.dnd_surface_enter(self, dnd, x, y);
}
fn dnd_drop(&self, dnd: &Dnd) {
dnd.seat.dnd_surface_drop(self, dnd);
}
@ -677,6 +686,10 @@ impl Node for WlSurface {
dnd.seat.dnd_surface_leave(self, dnd);
}
fn dnd_enter(&self, dnd: &Dnd, x: Fixed, y: Fixed) {
dnd.seat.dnd_surface_enter(self, dnd, x, y);
}
fn dnd_motion(&self, dnd: &Dnd, x: Fixed, y: Fixed) {
dnd.seat.dnd_surface_motion(self, dnd, x, y);
}

View file

@ -1,9 +1,8 @@
pub mod xdg_popup;
pub mod xdg_toplevel;
use crate::backend::SeatId;
use crate::client::ClientError;
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal};
use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopup, XdgPopupError};
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
use crate::ifs::wl_surface::{
@ -26,6 +25,7 @@ use std::cell::Cell;
use std::fmt::Debug;
use std::rc::Rc;
use thiserror::Error;
use i4config::Direction;
#[allow(dead_code)]
const NOT_CONSTRUCTED: u32 = 1;
@ -75,6 +75,11 @@ struct PendingXdgSurfaceData {
}
pub trait XdgSurfaceExt: Debug {
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let _ = seat;
let _ = direction;
}
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
Ok(())
}
@ -137,6 +142,14 @@ impl XdgSurface {
}
}
pub fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let ext = match self.ext.get() {
None => return,
Some(e) => e,
};
ext.move_focus(seat, direction);
}
pub fn role(&self) -> XdgSurfaceRole {
self.role.get()
}

View file

@ -1,9 +1,8 @@
use crate::backend::SeatId;
use crate::bugs::Bugs;
use crate::client::{Client, ClientError};
use crate::cursor::KnownCursor;
use crate::fixed::Fixed;
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal};
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt};
use crate::leaks::Tracker;
use crate::object::Object;
@ -27,6 +26,7 @@ use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use thiserror::Error;
use i4config::Direction;
#[derive(Copy, Clone, Debug, FromPrimitive)]
pub enum ResizeEdge {
@ -438,6 +438,10 @@ impl Node for XdgToplevel {
self.xdg.seat_state.destroy_node(self)
}
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) {
seat.focus_toplevel(&self);
}
fn absolute_position(&self) -> Rect {
self.xdg.absolute_desired_extents.get()
}
@ -480,6 +484,14 @@ impl Node for XdgToplevel {
}
impl XdgSurfaceExt for XdgToplevel {
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let pn = match self.parent_node.get() {
Some(pn) => pn,
_ => return,
};
pn.move_focus_from_child(seat, &*self, direction);
}
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
self.send_configure(0, 0);
Ok(())

485
src/keycodes.xkb Normal file
View file

@ -0,0 +1,485 @@
<1> = 9; # ESC
<2> = 10; # 1
<3> = 11; # 2
<4> = 12; # 3
<5> = 13; # 4
<6> = 14; # 5
<7> = 15; # 6
<8> = 16; # 7
<9> = 17; # 8
<10> = 18; # 9
<11> = 19; # 0
<12> = 20; # MINUS
<13> = 21; # EQUAL
<14> = 22; # BACKSPACE
<15> = 23; # TAB
<16> = 24; # Q
<17> = 25; # W
<18> = 26; # E
<19> = 27; # R
<20> = 28; # T
<21> = 29; # Y
<22> = 30; # U
<23> = 31; # I
<24> = 32; # O
<25> = 33; # P
<26> = 34; # LEFTBRACE
<27> = 35; # RIGHTBRACE
<28> = 36; # ENTER
<29> = 37; # LEFTCTRL
<30> = 38; # A
<31> = 39; # S
<32> = 40; # D
<33> = 41; # F
<34> = 42; # G
<35> = 43; # H
<36> = 44; # J
<37> = 45; # K
<38> = 46; # L
<39> = 47; # SEMICOLON
<40> = 48; # APOSTROPHE
<41> = 49; # GRAVE
<42> = 50; # LEFTSHIFT
<43> = 51; # BACKSLASH
<44> = 52; # Z
<45> = 53; # X
<46> = 54; # C
<47> = 55; # V
<48> = 56; # B
<49> = 57; # N
<50> = 58; # M
<51> = 59; # COMMA
<52> = 60; # DOT
<53> = 61; # SLASH
<54> = 62; # RIGHTSHIFT
<55> = 63; # KPASTERISK
<56> = 64; # LEFTALT
<57> = 65; # SPACE
<58> = 66; # CAPSLOCK
<59> = 67; # F1
<60> = 68; # F2
<61> = 69; # F3
<62> = 70; # F4
<63> = 71; # F5
<64> = 72; # F6
<65> = 73; # F7
<66> = 74; # F8
<67> = 75; # F9
<68> = 76; # F10
<69> = 77; # NUMLOCK
<70> = 78; # SCROLLLOCK
<71> = 79; # KP7
<72> = 80; # KP8
<73> = 81; # KP9
<74> = 82; # KPMINUS
<75> = 83; # KP4
<76> = 84; # KP5
<77> = 85; # KP6
<78> = 86; # KPPLUS
<79> = 87; # KP1
<80> = 88; # KP2
<81> = 89; # KP3
<82> = 90; # KP0
<83> = 91; # KPDOT
<85> = 93; # ZENKAKUHANKAKU
<86> = 94; # 102ND
<87> = 95; # F11
<88> = 96; # F12
<89> = 97; # RO
<90> = 98; # KATAKANA
<91> = 99; # HIRAGANA
<92> = 100; # HENKAN
<93> = 101; # KATAKANAHIRAGANA
<94> = 102; # MUHENKAN
<95> = 103; # KPJPCOMMA
<96> = 104; # KPENTER
<97> = 105; # RIGHTCTRL
<98> = 106; # KPSLASH
<99> = 107; # SYSRQ
<100> = 108; # RIGHTALT
<101> = 109; # LINEFEED
<102> = 110; # HOME
<103> = 111; # UP
<104> = 112; # PAGEUP
<105> = 113; # LEFT
<106> = 114; # RIGHT
<107> = 115; # END
<108> = 116; # DOWN
<109> = 117; # PAGEDOWN
<110> = 118; # INSERT
111> = 119; # DELETE
<112> = 120; # MACRO
<113> = 121; # MUTE
<114> = 122; # VOLUMEDOWN
<115> = 123; # VOLUMEUP
<116> = 124; # POWER
<117> = 125; # KPEQUAL
<118> = 126; # KPPLUSMINUS
<119> = 127; # PAUSE
<120> = 128; # SCALE
<121> = 129; # KPCOMMA
<122> = 130; # HANGEUL
<123> = 131; # HANJA
<124> = 132; # YEN
<125> = 133; # LEFTMETA
<126> = 134; # RIGHTMETA
<127> = 135; # COMPOSE
<128> = 136; # STOP
<129> = 137; # AGAIN
<130> = 138; # PROPS
<131> = 139; # UNDO
<132> = 140; # FRONT
<133> = 141; # COPY
<134> = 142; # OPEN
<135> = 143; # PASTE
<136> = 144; # FIND
<137> = 145; # CUT
<138> = 146; # HELP
<139> = 147; # MENU
<140> = 148; # CALC
<141> = 149; # SETUP
<142> = 150; # SLEEP
<143> = 151; # WAKEUP
<144> = 152; # FILE
<145> = 153; # SENDFILE
<146> = 154; # DELETEFILE
<147> = 155; # XFER
<148> = 156; # PROG1
<149> = 157; # PROG2
<150> = 158; # WWW
<151> = 159; # MSDOS
<152> = 160; # COFFEE
<153> = 161; # ROTATE_DISPLAY
<154> = 162; # CYCLEWINDOWS
<155> = 163; # MAIL
<156> = 164; # BOOKMARKS
<157> = 165; # COMPUTER
<158> = 166; # BACK
<159> = 167; # FORWARD
<160> = 168; # CLOSECD
<161> = 169; # EJECTCD
<162> = 170; # EJECTCLOSECD
<163> = 171; # NEXTSONG
<164> = 172; # PLAYPAUSE
<165> = 173; # PREVIOUSSONG
<166> = 174; # STOPCD
<167> = 175; # RECORD
<168> = 176; # REWIND
<169> = 177; # PHONE
<170> = 178; # ISO
<171> = 179; # CONFIG
<172> = 180; # HOMEPAGE
<173> = 181; # REFRESH
<174> = 182; # EXIT
<175> = 183; # MOVE
<176> = 184; # EDIT
<177> = 185; # SCROLLUP
<178> = 186; # SCROLLDOWN
<179> = 187; # KPLEFTPAREN
<180> = 188; # KPRIGHTPAREN
<181> = 189; # NEW
<182> = 190; # REDO
<183> = 191; # F13
<184> = 192; # F14
<185> = 193; # F15
<186> = 194; # F16
<187> = 195; # F17
<188> = 196; # F18
<189> = 197; # F19
<190> = 198; # F20
<191> = 199; # F21
<192> = 200; # F22
<193> = 201; # F23
<194> = 202; # F24
<200> = 208; # PLAYCD
<201> = 209; # PAUSECD
<202> = 210; # PROG3
<203> = 211; # PROG4
<204> = 212; # DASHBOARD
<205> = 213; # SUSPEND
<206> = 214; # CLOSE
<207> = 215; # PLAY
<208> = 216; # FASTFORWARD
<209> = 217; # BASSBOOST
<210> = 218; # PRINT
<211> = 219; # HP
<212> = 220; # CAMERA
<213> = 221; # SOUND
<214> = 222; # QUESTION
<215> = 223; # EMAIL
<216> = 224; # CHAT
<217> = 225; # SEARCH
<218> = 226; # CONNECT
<219> = 227; # FINANCE
<220> = 228; # SPORT
<221> = 229; # SHOP
<222> = 230; # ALTERASE
<223> = 231; # CANCEL
<224> = 232; # BRIGHTNESSDOWN
<225> = 233; # BRIGHTNESSUP
<226> = 234; # MEDIA
<227> = 235; # SWITCHVIDEOMODE
<228> = 236; # KBDILLUMTOGGLE
<229> = 237; # KBDILLUMDOWN
<230> = 238; # KBDILLUMUP
<231> = 239; # SEND
<232> = 240; # REPLY
<233> = 241; # FORWARDMAIL
<234> = 242; # SAVE
<235> = 243; # DOCUMENTS
<236> = 244; # BATTERY
<237> = 245; # BLUETOOTH
<238> = 246; # WLAN
<239> = 247; # UWB
<240> = 248; # UNKNOWN
<241> = 249; # VIDEO_NEXT
<242> = 250; # VIDEO_PREV
<243> = 251; # BRIGHTNESS_CYCLE
<244> = 252; # BRIGHTNESS_AUTO
<245> = 253; # DISPLAY_OFF
<246> = 254; # WWAN
<247> = 255; # RFKILL
<248> = 256; # MICMUTE
<352> = 360; # OK
<353> = 361; # SELECT
<354> = 362; # GOTO
<355> = 363; # CLEAR
<356> = 364; # POWER2
<357> = 365; # OPTION
<358> = 366; # INFO
<359> = 367; # TIME
<360> = 368; # VENDOR
<361> = 369; # ARCHIVE
<362> = 370; # PROGRAM
<363> = 371; # CHANNEL
<364> = 372; # FAVORITES
<365> = 373; # EPG
<366> = 374; # PVR
<367> = 375; # MHP
<368> = 376; # LANGUAGE
<369> = 377; # TITLE
<370> = 378; # SUBTITLE
<371> = 379; # ANGLE
<372> = 380; # FULL_SCREEN
<373> = 381; # MODE
<374> = 382; # KEYBOARD
<375> = 383; # ASPECT_RATIO
<376> = 384; # PC
<377> = 385; # TV
<378> = 386; # TV2
<379> = 387; # VCR
<380> = 388; # VCR2
<381> = 389; # SAT
<382> = 390; # SAT2
<383> = 391; # CD
<384> = 392; # TAPE
<385> = 393; # RADIO
<386> = 394; # TUNER
<387> = 395; # PLAYER
<388> = 396; # TEXT
<389> = 397; # DVD
<390> = 398; # AUX
<391> = 399; # MP3
<392> = 400; # AUDIO
<393> = 401; # VIDEO
<394> = 402; # DIRECTORY
<395> = 403; # LIST
<396> = 404; # MEMO
<397> = 405; # CALENDAR
<398> = 406; # RED
<399> = 407; # GREEN
<400> = 408; # YELLOW
<401> = 409; # BLUE
<402> = 410; # CHANNELUP
<403> = 411; # CHANNELDOWN
<404> = 412; # FIRST
<405> = 413; # LAST
<406> = 414; # AB
<407> = 415; # NEXT
<408> = 416; # RESTART
<409> = 417; # SLOW
<410> = 418; # SHUFFLE
<411> = 419; # BREAK
<412> = 420; # PREVIOUS
<413> = 421; # DIGITS
<414> = 422; # TEEN
<415> = 423; # TWEN
<416> = 424; # VIDEOPHONE
<417> = 425; # GAMES
<418> = 426; # ZOOMIN
<419> = 427; # ZOOMOUT
<420> = 428; # ZOOMRESET
<421> = 429; # WORDPROCESSOR
<422> = 430; # EDITOR
<423> = 431; # SPREADSHEET
<424> = 432; # GRAPHICSEDITOR
<425> = 433; # PRESENTATION
<426> = 434; # DATABASE
<427> = 435; # NEWS
<428> = 436; # VOICEMAIL
<429> = 437; # ADDRESSBOOK
<430> = 438; # MESSENGER
<431> = 439; # DISPLAYTOGGLE
<432> = 440; # SPELLCHECK
<433> = 441; # LOGOFF
<434> = 442; # DOLLAR
<435> = 443; # EURO
<436> = 444; # FRAMEBACK
<437> = 445; # FRAMEFORWARD
<438> = 446; # CONTEXT_MENU
<439> = 447; # MEDIA_REPEAT
<440> = 448; # 10CHANNELSUP
<441> = 449; # 10CHANNELSDOWN
<442> = 450; # IMAGES
<444> = 452; # NOTIFICATION_CENTER
<445> = 453; # PICKUP_PHONE
<446> = 454; # HANGUP_PHONE
<448> = 456; # DEL_EOL
<449> = 457; # DEL_EOS
<450> = 458; # INS_LINE
<451> = 459; # DEL_LINE
<464> = 472; # FN
<465> = 473; # FN_ESC
<466> = 474; # FN_F1
<467> = 475; # FN_F2
<468> = 476; # FN_F3
<469> = 477; # FN_F4
<470> = 478; # FN_F5
<471> = 479; # FN_F6
<472> = 480; # FN_F7
<473> = 481; # FN_F8
<474> = 482; # FN_F9
<475> = 483; # FN_F10
<476> = 484; # FN_F11
<477> = 485; # FN_F12
<478> = 486; # FN_1
<479> = 487; # FN_2
<480> = 488; # FN_D
<481> = 489; # FN_E
<482> = 490; # FN_F
<483> = 491; # FN_S
<484> = 492; # FN_B
<485> = 493; # FN_RIGHT_SHIFT
<497> = 505; # BRL_DOT1
<498> = 506; # BRL_DOT2
<499> = 507; # BRL_DOT3
<500> = 508; # BRL_DOT4
<501> = 509; # BRL_DOT5
<502> = 510; # BRL_DOT6
<503> = 511; # BRL_DOT7
<504> = 512; # BRL_DOT8
<505> = 513; # BRL_DOT9
<506> = 514; # BRL_DOT10
<512> = 520; # NUMERIC_0
<513> = 521; # NUMERIC_1
<514> = 522; # NUMERIC_2
<515> = 523; # NUMERIC_3
<516> = 524; # NUMERIC_4
<517> = 525; # NUMERIC_5
<518> = 526; # NUMERIC_6
<519> = 527; # NUMERIC_7
<520> = 528; # NUMERIC_8
<521> = 529; # NUMERIC_9
<522> = 530; # NUMERIC_STAR
<523> = 531; # NUMERIC_POUND
<524> = 532; # NUMERIC_A
<525> = 533; # NUMERIC_B
<526> = 534; # NUMERIC_C
<527> = 535; # NUMERIC_D
<528> = 536; # CAMERA_FOCUS
<529> = 537; # WPS_BUTTON
<530> = 538; # TOUCHPAD_TOGGLE
<531> = 539; # TOUCHPAD_ON
<532> = 540; # TOUCHPAD_OFF
<533> = 541; # CAMERA_ZOOMIN
<534> = 542; # CAMERA_ZOOMOUT
<535> = 543; # CAMERA_UP
<536> = 544; # CAMERA_DOWN
<537> = 545; # CAMERA_LEFT
<538> = 546; # CAMERA_RIGHT
<539> = 547; # ATTENDANT_ON
<540> = 548; # ATTENDANT_OFF
<541> = 549; # ATTENDANT_TOGGLE
<542> = 550; # LIGHTS_TOGGLE
<560> = 568; # ALS_TOGGLE
<561> = 569; # ROTATE_LOCK_TOGGLE
<576> = 584; # BUTTONCONFIG
<577> = 585; # TASKMANAGER
<578> = 586; # JOURNAL
<579> = 587; # CONTROLPANEL
<580> = 588; # APPSELECT
<581> = 589; # SCREENSAVER
<582> = 590; # VOICECOMMAND
<583> = 591; # ASSISTANT
<584> = 592; # KBD_LAYOUT_NEXT
<585> = 593; # EMOJI_PICKER
<592> = 600; # BRIGHTNESS_MIN
<593> = 601; # BRIGHTNESS_MAX
<608> = 616; # KBDINPUTASSIST_PREV
<609> = 617; # KBDINPUTASSIST_NEXT
<610> = 618; # KBDINPUTASSIST_PREVGROUP
<611> = 619; # KBDINPUTASSIST_NEXTGROUP
<612> = 620; # KBDINPUTASSIST_ACCEPT
<613> = 621; # KBDINPUTASSIST_CANCEL
<614> = 622; # RIGHT_UP
<615> = 623; # RIGHT_DOWN
<616> = 624; # LEFT_UP
<617> = 625; # LEFT_DOWN
<618> = 626; # ROOT_MENU
<619> = 627; # MEDIA_TOP_MENU
<620> = 628; # NUMERIC_11
<621> = 629; # NUMERIC_12
<622> = 630; # AUDIO_DESC
<623> = 631; # 3D_MODE
<624> = 632; # NEXT_FAVORITE
<625> = 633; # STOP_RECORD
<626> = 634; # PAUSE_RECORD
<627> = 635; # VOD
<628> = 636; # UNMUTE
<629> = 637; # FASTREVERSE
<630> = 638; # SLOWREVERSE
<631> = 639; # DATA
<632> = 640; # ONSCREEN_KEYBOARD
<633> = 641; # PRIVACY_SCREEN_TOGGLE
<634> = 642; # SELECTIVE_SCREENSHOT
<656> = 664; # MACRO1
<657> = 665; # MACRO2
<658> = 666; # MACRO3
<659> = 667; # MACRO4
<660> = 668; # MACRO5
<661> = 669; # MACRO6
<662> = 670; # MACRO7
<663> = 671; # MACRO8
<664> = 672; # MACRO9
<665> = 673; # MACRO10
<666> = 674; # MACRO11
<667> = 675; # MACRO12
<668> = 676; # MACRO13
<669> = 677; # MACRO14
<670> = 678; # MACRO15
<671> = 679; # MACRO16
<672> = 680; # MACRO17
<673> = 681; # MACRO18
<674> = 682; # MACRO19
<675> = 683; # MACRO20
<676> = 684; # MACRO21
<677> = 685; # MACRO22
<678> = 686; # MACRO23
<679> = 687; # MACRO24
<680> = 688; # MACRO25
<681> = 689; # MACRO26
<682> = 690; # MACRO27
<683> = 691; # MACRO28
<684> = 692; # MACRO29
<685> = 693; # MACRO30
<688> = 696; # MACRO_RECORD_START
<689> = 697; # MACRO_RECORD_STOP
<690> = 698; # MACRO_PRESET_CYCLE
<691> = 699; # MACRO_PRESET1
<692> = 700; # MACRO_PRESET2
<693> = 701; # MACRO_PRESET3
<696> = 704; # KBD_LCD_MENU1
<697> = 705; # KBD_LCD_MENU2
<698> = 706; # KBD_LCD_MENU3
<699> = 707; # KBD_LCD_MENU4
<700> = 708; # KBD_LCD_MENU5

285
src/keymap.xkb Normal file
View file

@ -0,0 +1,285 @@
xkb_keymap {
xkb_keycodes {
<1> = 9; # ESC
<2> = 10; # 1
<3> = 11; # 2
<4> = 12; # 3
<5> = 13; # 4
<6> = 14; # 5
<7> = 15; # 6
<8> = 16; # 7
<9> = 17; # 8
<10> = 18; # 9
<11> = 19; # 0
<12> = 20; # MINUS
<13> = 21; # EQUAL
<14> = 22; # BACKSPACE
<15> = 23; # TAB
<16> = 24; # Q
<17> = 25; # W
<18> = 26; # E
<19> = 27; # R
<20> = 28; # T
<21> = 29; # Y
<22> = 30; # U
<23> = 31; # I
<24> = 32; # O
<25> = 33; # P
<26> = 34; # LEFTBRACE
<27> = 35; # RIGHTBRACE
<28> = 36; # ENTER
<29> = 37; # LEFTCTRL
<30> = 38; # A
<31> = 39; # S
<32> = 40; # D
<33> = 41; # F
<34> = 42; # G
<35> = 43; # H
<36> = 44; # J
<37> = 45; # K
<38> = 46; # L
<39> = 47; # SEMICOLON
<40> = 48; # APOSTROPHE
<41> = 49; # GRAVE
<42> = 50; # LEFTSHIFT
<43> = 51; # BACKSLASH
<44> = 52; # Z
<45> = 53; # X
<46> = 54; # C
<47> = 55; # V
<48> = 56; # B
<49> = 57; # N
<50> = 58; # M
<51> = 59; # COMMA
<52> = 60; # DOT
<53> = 61; # SLASH
<54> = 62; # RIGHTSHIFT
<55> = 63; # KPASTERISK
<56> = 64; # LEFTALT
<57> = 65; # SPACE
<58> = 66; # CAPSLOCK
<59> = 67; # F1
<60> = 68; # F2
<61> = 69; # F3
<62> = 70; # F4
<63> = 71; # F5
<64> = 72; # F6
<65> = 73; # F7
<66> = 74; # F8
<67> = 75; # F9
<68> = 76; # F10
<69> = 77; # NUMLOCK
<70> = 78; # SCROLLLOCK
<71> = 79; # KP7
<72> = 80; # KP8
<73> = 81; # KP9
<74> = 82; # KPMINUS
<75> = 83; # KP4
<76> = 84; # KP5
<77> = 85; # KP6
<78> = 86; # KPPLUS
<79> = 87; # KP1
<80> = 88; # KP2
<81> = 89; # KP3
<82> = 90; # KP0
<83> = 91; # KPDOT
<87> = 95; # F11
<88> = 96; # F12
<96> = 104; # KPENTER
<97> = 105; # RIGHTCTRL
<98> = 106; # KPSLASH
<100> = 108; # RIGHTALT
<102> = 110; # HOME
<103> = 111; # UP
<104> = 112; # PAGEUP
<105> = 113; # LEFT
<106> = 114; # RIGHT
<107> = 115; # END
<108> = 116; # DOWN
<109> = 117; # PAGEDOWN
<110> = 118; # INSERT
<111> = 119; # DELETE
<117> = 125; # KPEQUAL
<119> = 127; # PAUSE
<125> = 133; # LEFTMETA
<126> = 134; # RIGHTMETA
<139> = 147; # MENU
<210> = 218; # PRINT
# We must include at least one indicator here. Otherwise Xwayland segfaults.
indicator 1 = "DUMMY";
};
xkb_types {
# We must include at least one virtual modifier.
# Otherwise Xwayland rejects our keymap.
virtual_modifiers Dummy;
type "ONE_LEVEL" {
modifiers = none;
};
type "TWO_LEVEL" {
modifiers = Shift;
map[Shift] = Level2;
};
type "ALPHABETIC" {
modifiers = Shift+Lock;
map[Shift] = Level2;
map[Lock] = Level2;
};
type "KEYPAD" {
modifiers = Shift+Mod2;
map[Mod2] = Level2;
};
};
xkb_compatibility {
interpret.repeat = False;
interpret.locking = False;
interpret Shift_L {
action = SetMods(modifiers=Shift);
};
interpret Shift_R {
action = SetMods(modifiers=Shift);
};
interpret Caps_Lock {
action = LockMods(modifiers=Lock);
};
interpret Control_L {
action = SetMods(modifiers=Control);
};
interpret Control_R {
action = SetMods(modifiers=Control);
};
interpret Alt_L {
action = SetMods(modifiers=Mod1);
};
interpret Alt_R {
action = SetMods(modifiers=Mod1);
};
interpret Num_Lock {
action = LockMods(modifiers=Mod2);
};
};
xkb_symbols {
key <1> { [ Escape ] };
key <59> { [ F1 ] };
key <60> { [ F2 ] };
key <61> { [ F3 ] };
key <62> { [ F4 ] };
key <63> { [ F5 ] };
key <64> { [ F6 ] };
key <65> { [ F7 ] };
key <66> { [ F8 ] };
key <67> { [ F9 ] };
key <68> { [ F10 ] };
key <87> { [ F11 ] };
key <88> { [ F12 ] };
key <210> { [ Print ] };
key <70> { [ Scroll_Lock ] };
key <119> { [ Pause ] };
key <69> { [ Num_Lock ] };
key <96> { [ KP_Enter ] };
key <98> { [ KP_Divide ] };
key <74> { [ KP_Subtract ] };
key <55> { [ KP_Multiply ] };
key <78> { [ KP_Add ] };
key <117> { [ KP_Equal ] };
key <83> { [ KP_Delete, KP_Decimal ] };
key <71> { [ KP_Home, KP_7 ] };
key <72> { [ KP_Up, KP_8 ] };
key <73> { [ KP_Prior, KP_9 ] };
key <75> { [ KP_Left, KP_4 ] };
key <76> { [ KP_Begin, KP_5 ] };
key <77> { [ KP_Right, KP_6 ] };
key <79> { [ KP_End, KP_1 ] };
key <80> { [ KP_Down, KP_2 ] };
key <81> { [ KP_Next, KP_3 ] };
key <82> { [ KP_Insert, KP_0 ] };
key <103> { [ Up ] };
key <105> { [ Left ] };
key <106> { [ Right ] };
key <108> { [ Down ] };
key <102> { [ Home ] };
key <104> { [ Prior ] };
key <107> { [ End ] };
key <109> { [ Next ] };
key <110> { [ Insert ] };
key <111> { [ Delete ] };
key <14> { [ BackSpace ] };
key <15> { [ Tab, ISO_Left_Tab ] };
key <58> { [ Caps_Lock ] };
key <28> { [ Return ] };
key <42> { [ Shift_L ] };
key <54> { [ Shift_R ] };
key <29> { [ Control_L ] };
key <125> { [ Super_L ] };
key <56> { [ Alt_L ] };
key <57> { [ space ] };
key <100> { [ Alt_R ] };
key <126> { [ Super_R ] };
key <139> { [ Menu ] };
key <97> { [ Control_R ] };
key <41> { [ grave, asciitilde ] };
key <12> { [ minus, underscore ] };
key <13> { [ equal, plus ] };
key <26> { [ bracketleft, braceleft ] };
key <27> { [ bracketright, braceright ] };
key <43> { [ backslash, bar ] };
key <39> { [ semicolon, colon ] };
key <40> { [ apostrophe, quotedbl ] };
key <51> { [ comma, less ] };
key <52> { [ period, greater ] };
key <53> { [ slash, question ] };
key <16> { [ q, Q ] };
key <17> { [ w, W ] };
key <18> { [ e, E ] };
key <19> { [ r, R ] };
key <20> { [ t, T ] };
key <21> { [ y, Y ] };
key <22> { [ u, U ] };
key <23> { [ i, I ] };
key <24> { [ o, O ] };
key <25> { [ p, P ] };
key <30> { [ a, A ] };
key <31> { [ s, S ] };
key <32> { [ d, D ] };
key <33> { [ f, F ] };
key <34> { [ g, G ] };
key <35> { [ h, H ] };
key <36> { [ j, J ] };
key <37> { [ k, K ] };
key <38> { [ l, L ] };
key <44> { [ z, Z ] };
key <45> { [ x, X ] };
key <46> { [ c, C ] };
key <47> { [ v, V ] };
key <48> { [ b, B ] };
key <49> { [ n, N ] };
key <50> { [ m, M ] };
key <2> { [ 1, exclam ] };
key <3> { [ 2, at ] };
key <4> { [ 3, numbersign ] };
key <5> { [ 4, dollar ] };
key <6> { [ 5, percent ] };
key <7> { [ 6, asciicircum ] };
key <8> { [ 7, ampersand ] };
key <9> { [ 8, asterisk ] };
key <10> { [ 9, parenleft ] };
key <11> { [ 0, parenright ] };
};
};

View file

@ -1,8 +1,14 @@
pub use leaks::*;
macro_rules! track {
($client:expr, $rc:expr) => {
$rc.tracker.register($client.id);
};
}
#[cfg(not(feature = "rc_tracking"))]
#[macro_use]
mod leaks {
use crate::client::ClientId;
use std::marker::PhantomData;
pub fn init() {
@ -17,6 +23,12 @@ mod leaks {
_phantom: PhantomData<T>,
}
impl<T> Tracker<T> {
pub fn register(&self, _client: ClientId) {
// nothing
}
}
impl<T> Default for Tracker<T> {
fn default() -> Self {
Self {
@ -24,16 +36,9 @@ mod leaks {
}
}
}
macro_rules! track {
($client:expr, $rc:expr) => {
let _ = $rc.tracker;
}
}
}
#[cfg(feature = "rc_tracking")]
#[macro_use]
mod leaks {
use crate::client::ClientId;
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
@ -59,7 +64,12 @@ mod leaks {
}
}
fn log_containers(prefix: &str, allocation: &mut Allocation, offset: usize, logged: &mut AHashSet<*mut u8>) {
fn log_containers(
prefix: &str,
allocation: &mut Allocation,
offset: usize,
logged: &mut AHashSet<*mut u8>,
) {
log::info!(
"{}Contained in allocation {:?} at offset {}. Backtrace:",
prefix,
@ -94,6 +104,9 @@ mod leaks {
for (id, obj) in MAP.deref_mut().drain() {
map.entry(obj.client).or_default().push((id, obj));
}
if map.is_empty() {
log::info!("No leaks");
}
for (_, mut objs) in map.drain() {
if objs.len() == 0 {
continue;
@ -102,13 +115,11 @@ mod leaks {
log::info!("Client {} leaked {} objects", objs[0].1.client, objs.len());
for (_, obj) in objs {
let time = chrono::NaiveDateTime::from_timestamp(obj.time.0, obj.time.1);
log::info!(
" [{}] {}",
time.format("%H:%M:%S%.3f"),
obj.ty,
);
log::info!(" [{}] {}", time.format("%H:%M:%S%.3f"), obj.ty,);
match find_allocation_containing(obj.addr) {
Some(mut alloc) => log_containers(" ", &mut alloc, 0, &mut AHashSet::new()),
Some(mut alloc) => {
log_containers(" ", &mut alloc, 0, &mut AHashSet::new())
}
_ => log::error!(" Not contained in any allocation??"),
}
}
@ -174,14 +185,6 @@ mod leaks {
}
}
macro_rules! track {
($client:expr, $rc:expr) => {
($rc)
.tracker
.register($client.id);
};
}
struct TracingAllocator;
#[global_allocator]
@ -225,7 +228,7 @@ mod leaks {
if INITIALIZED {
ALLOCATIONS.deref_mut().remove(&ptr);
}
c::memset(ptr as _, 0, layout.size());
// c::memset(ptr as _, 0, layout.size());
c::free(ptr as _);
}
}

View file

@ -168,6 +168,11 @@ macro_rules! linear_ids {
pub fn raw(&self) -> u32 {
self.0
}
#[allow(dead_code)]
pub fn from_raw(id: u32) -> Self {
Self(id)
}
}
impl std::fmt::Display for $id {

View file

@ -1,11 +1,4 @@
#![feature(
c_variadic,
thread_local,
label_break_value,
ptr_metadata,
linkage,
const_type_name
)]
#![feature(c_variadic, thread_local, label_break_value)]
#![allow(
clippy::len_zero,
clippy::needless_lifetimes,
@ -39,18 +32,18 @@ use crate::wheel::WheelError;
use acceptor::Acceptor;
use async_engine::AsyncEngine;
use event_loop::EventLoop;
use isnt::std_1::primitive::IsntMutPtrExt;
use log::LevelFilter;
use std::cell::Cell;
use std::ops::Deref;
use std::rc::Rc;
use thiserror::Error;
use wheel::Wheel;
use crate::xkbcommon::XkbContext;
#[macro_use]
mod macros;
#[macro_use]
pub mod leaks;
mod leaks;
mod acceptor;
mod async_engine;
mod backend;
@ -58,6 +51,7 @@ mod backends;
mod bugs;
mod client;
mod clientmem;
mod config;
mod cursor;
mod drm;
mod event_loop;
@ -81,15 +75,6 @@ mod wire;
mod xkbcommon;
fn main() {
unsafe {
extern "C" {
#[linkage = "extern_weak"]
static BYTEHOUND_REACHED_MAIN: *mut bool;
}
if BYTEHOUND_REACHED_MAIN.is_not_null() {
*BYTEHOUND_REACHED_MAIN = true;
}
}
env_logger::builder()
.filter_level(LevelFilter::Info)
.filter_level(LevelFilter::Debug)
@ -127,10 +112,14 @@ fn main_() -> Result<(), MainError> {
clientmem::init()?;
let el = EventLoop::new()?;
sighand::install(&el)?;
let xkb_ctx = XkbContext::new().unwrap();
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
let wheel = Wheel::install(&el)?;
let engine = AsyncEngine::install(&el, &wheel)?;
let node_ids = NodeIds::default();
let state = Rc::new(State {
xkb_ctx,
default_keymap: xkb_keymap,
eng: engine.clone(),
el: el.clone(),
render_ctx: Default::default(),
@ -144,14 +133,20 @@ fn main_() -> Result<(), MainError> {
node_ids,
backend_events: AsyncQueue::new(),
output_handlers: Default::default(),
mouse_handlers: Default::default(),
seat_ids: Default::default(),
seats: Default::default(),
kb_ids: Default::default(),
outputs: Default::default(),
seat_queue: Default::default(),
slow_clients: AsyncQueue::new(),
none_surface_ext: Rc::new(NoneSurfaceExt),
tree_changed_sent: Cell::new(false),
config: Default::default(),
mouse_ids: Default::default(),
kb_handlers: Default::default(),
});
let config = config::ConfigProxy::default(&state);
state.config.set(Some(Rc::new(config)));
let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone()));
let _slow_client_handler = engine.spawn(tasks::handle_slow_clients(state.clone()));
Acceptor::install(&state)?;

View file

@ -38,7 +38,7 @@ impl GlProgram {
let mut ok = 0;
glGetProgramiv(res.prog, GL_LINK_STATUS, &mut ok);
if ok == GL_FALSE as _ {
if ok == GL_FALSE as GLint {
return Err(RenderError::ProgramLink);
}

View file

@ -3,6 +3,7 @@ use crate::render::gl::sys::{
glCompileShader, glCreateShader, glDeleteShader, glGetShaderiv, glShaderSource, GLenum, GLuint,
GL_COMPILE_STATUS, GL_FALSE,
};
use crate::render::sys::GLint;
use crate::render::RenderError;
use std::rc::Rc;
@ -28,7 +29,7 @@ impl GlShader {
let mut ok = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &mut ok);
if ok == GL_FALSE as _ {
if ok == GL_FALSE as GLint {
return Err(RenderError::ShaderCompileFailed);
}
Ok(res)

View file

@ -1,26 +1,29 @@
use crate::async_engine::{AsyncEngine, SpawnedFuture};
use crate::backend::{BackendEvent, OutputId, OutputIds, SeatId, SeatIds};
use crate::backend::{BackendEvent, KeyboardId, KeyboardIds, MouseId, MouseIds, OutputId, OutputIds};
use crate::client::{Client, Clients};
use crate::config::ConfigProxy;
use crate::cursor::ServerCursors;
use crate::event_loop::EventLoop;
use crate::globals::{Globals, GlobalsError, WaylandGlobal};
use crate::ifs::wl_output::WlOutputGlobal;
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::ifs::wl_seat::{SeatIds, WlSeatGlobal};
use crate::ifs::wl_surface::NoneSurfaceExt;
use crate::render::RenderContext;
use crate::tree::{DisplayNode, NodeIds};
use crate::utils::asyncevent::AsyncEvent;
use crate::utils::clonecell::CloneCell;
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::linkedlist::LinkedList;
use crate::utils::numcell::NumCell;
use crate::utils::queue::AsyncQueue;
use crate::{ErrorFmt, Wheel};
use crate::{ErrorFmt, Wheel, XkbContext};
use ahash::AHashMap;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use crate::xkbcommon::XkbKeymap;
pub struct State {
pub xkb_ctx: XkbContext,
pub default_keymap: Rc<XkbKeymap>,
pub eng: Rc<AsyncEngine>,
pub el: Rc<EventLoop>,
pub render_ctx: CloneCell<Option<Rc<RenderContext>>>,
@ -31,21 +34,36 @@ pub struct State {
pub globals: Globals,
pub output_ids: OutputIds,
pub seat_ids: SeatIds,
pub kb_ids: KeyboardIds,
pub mouse_ids: MouseIds,
pub node_ids: NodeIds,
pub root: Rc<DisplayNode>,
pub backend_events: AsyncQueue<BackendEvent>,
pub output_handlers: RefCell<AHashMap<OutputId, SpawnedFuture<()>>>,
pub seats: RefCell<AHashMap<SeatId, SeatData>>,
pub mouse_handlers: RefCell<AHashMap<MouseId, MouseData>>,
pub kb_handlers: RefCell<AHashMap<KeyboardId, KeyboardData>>,
pub outputs: CopyHashMap<OutputId, Rc<WlOutputGlobal>>,
pub seat_queue: LinkedList<Rc<WlSeatGlobal>>,
pub slow_clients: AsyncQueue<Rc<Client>>,
pub none_surface_ext: Rc<NoneSurfaceExt>,
pub tree_changed_sent: Cell<bool>,
pub config: CloneCell<Option<Rc<ConfigProxy>>>,
}
pub struct SeatData {
pub struct MouseData {
pub handler: SpawnedFuture<()>,
pub tree_changed: Rc<AsyncEvent>,
pub id: MouseId,
pub data: Rc<DeviceHandlerData>
}
pub struct KeyboardData {
pub handler: SpawnedFuture<()>,
pub id: KeyboardId,
pub data: Rc<DeviceHandlerData>
}
pub struct DeviceHandlerData {
pub seat: CloneCell<Option<Rc<WlSeatGlobal>>>,
}
impl State {
@ -73,9 +91,9 @@ impl State {
if self.tree_changed_sent.replace(true) {
return;
}
let seats = self.seats.borrow();
let seats = self.globals.seats.lock();
for seat in seats.values() {
seat.tree_changed.trigger();
seat.trigger_tree_changed();
}
}
}

View file

@ -1,10 +1,8 @@
use crate::backend::{BackendEvent, Output, Seat};
use crate::state::SeatData;
use crate::backend::{BackendEvent, Output};
use crate::tasks::output::OutputHandler;
use crate::tasks::seat::SeatHandler;
use crate::utils::asyncevent::AsyncEvent;
use crate::State;
use std::rc::Rc;
use crate::tasks::device;
pub struct BackendEventHandler {
pub state: Rc<State>,
@ -21,7 +19,8 @@ impl BackendEventHandler {
fn handle_event(&mut self, event: BackendEvent) {
match event {
BackendEvent::NewOutput(output) => self.handle_new_output(output),
BackendEvent::NewSeat(seat) => self.handle_new_seat(seat),
BackendEvent::NewMouse(s) => device::handle(&self.state, s),
BackendEvent::NewKeyboard(s) => device::handle(&self.state, s),
}
}
@ -34,22 +33,4 @@ impl BackendEventHandler {
let future = self.state.eng.spawn(oh.handle());
self.state.output_handlers.borrow_mut().insert(id, future);
}
fn handle_new_seat(&mut self, seat: Rc<dyn Seat>) {
let id = seat.id();
let tree_changed = Rc::new(AsyncEvent::default());
let oh = SeatHandler {
state: self.state.clone(),
seat,
tree_changed: tree_changed.clone(),
};
let handler = self.state.eng.spawn(oh.handle());
self.state.seats.borrow_mut().insert(
id,
SeatData {
handler,
tree_changed,
},
);
}
}

157
src/tasks/device.rs Normal file
View file

@ -0,0 +1,157 @@
use crate::backend::{Keyboard, KeyboardEvent, Mouse, MouseEvent};
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::utils::asyncevent::AsyncEvent;
use crate::State;
use std::rc::Rc;
use crate::async_engine::SpawnedFuture;
use crate::config::ConfigProxy;
use crate::state::{DeviceHandlerData, KeyboardData, MouseData};
pub trait DeviceApi: 'static {
type Event;
fn on_change(&self, cb: Rc<dyn Fn()>);
fn announce(&self, config: &ConfigProxy);
fn announce_del(&self, config: &ConfigProxy);
fn removed(&self) -> bool;
fn add(&self, state: &State, handler: SpawnedFuture<()>, data: Rc<DeviceHandlerData>);
fn remove(&self, state: &State);
fn event(&self) -> Option<Self::Event>;
fn send(seat: &Rc<WlSeatGlobal>, event: Self::Event);
}
impl DeviceApi for dyn Keyboard {
type Event = KeyboardEvent;
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.on_change(cb);
}
fn announce(&self, config: &ConfigProxy) {
config.new_keyboard(self.id());
}
fn announce_del(&self, config: &ConfigProxy) {
config.del_keyboard(self.id());
}
fn removed(&self) -> bool {
self.removed()
}
fn add(&self, state: &State, handler: SpawnedFuture<()>, data: Rc<DeviceHandlerData>) {
state.kb_handlers.borrow_mut().insert(self.id(), KeyboardData {
handler,
id: self.id(),
data,
});
}
fn remove(&self, state: &State) {
state.kb_handlers.borrow_mut().remove(&self.id());
}
fn event(&self) -> Option<Self::Event> {
self.event()
}
fn send(seat: &Rc<WlSeatGlobal>, event: Self::Event) {
seat.kb_event(event);
}
}
impl DeviceApi for dyn Mouse {
type Event = MouseEvent;
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.on_change(cb);
}
fn announce(&self, config: &ConfigProxy) {
config.new_mouse(self.id());
}
fn announce_del(&self, config: &ConfigProxy) {
config.del_mouse(self.id());
}
fn removed(&self) -> bool {
self.removed()
}
fn add(&self, state: &State, handler: SpawnedFuture<()>, data: Rc<DeviceHandlerData>) {
state.mouse_handlers.borrow_mut().insert(self.id(), MouseData {
handler,
id: self.id(),
data,
});
}
fn remove(&self, state: &State) {
state.mouse_handlers.borrow_mut().remove(&self.id());
}
fn event(&self) -> Option<Self::Event> {
self.event()
}
fn send(seat: &Rc<WlSeatGlobal>, event: Self::Event) {
seat.mouse_event(event);
}
}
pub fn handle<T: DeviceApi + ?Sized>(state: &Rc<State>, dev: Rc<T>) {
let data = Rc::new(DeviceHandlerData {
seat: Default::default(),
});
let oh = DeviceHandler {
state: state.clone(),
dev: dev.clone(),
data: data.clone(),
};
let handler = state.eng.spawn(oh.handle());
dev.add(&state, handler, data);
}
pub struct DeviceHandler<T: DeviceApi + ?Sized> {
pub state: Rc<State>,
pub dev: Rc<T>,
pub data: Rc<DeviceHandlerData>,
}
impl<T: DeviceApi + ?Sized> DeviceHandler<T> {
pub async fn handle(self) {
let ae = Rc::new(AsyncEvent::default());
{
let ae = ae.clone();
self.dev.on_change(Rc::new(move || ae.trigger()));
}
if let Some(config) = self.state.config.get() {
self.dev.announce(&config);
}
loop {
if self.dev.removed() {
break;
}
if let Some(seat) = self.data.seat.get() {
let mut any_events = false;
while let Some(event) = self.dev.event() {
T::send(&seat, event);
any_events = true;
}
if any_events {
seat.mark_last_active();
}
} else {
while self.dev.event().is_some() {
// nothing
}
}
ae.triggered().await;
}
if let Some(config) = self.state.config.get() {
self.dev.announce_del(&config);
}
self.dev.remove(&self.state);
}
}

View file

@ -1,7 +1,7 @@
mod backend;
mod output;
mod seat;
mod slow_clients;
mod device;
use crate::tasks::backend::BackendEventHandler;
use crate::tasks::slow_clients::SlowClientHandler;

View file

@ -1,60 +0,0 @@
use crate::backend::Seat;
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::utils::asyncevent::AsyncEvent;
use crate::State;
use std::rc::Rc;
pub struct SeatHandler {
pub state: Rc<State>,
pub seat: Rc<dyn Seat>,
pub tree_changed: Rc<AsyncEvent>,
}
impl SeatHandler {
pub async fn handle(self) {
let ae = Rc::new(AsyncEvent::default());
{
let ae = ae.clone();
self.seat.on_change(Rc::new(move || ae.trigger()));
}
let name = self.state.globals.name();
let global = Rc::new(WlSeatGlobal::new(
name,
&self.state,
&self.seat,
&self.tree_changed,
));
let _tree_changed = self.state.eng.spawn(tree_changed(
self.state.clone(),
global.clone(),
self.tree_changed.clone(),
));
let mut _node = self.state.seat_queue.add_last(global.clone());
self.state.add_global(&global);
loop {
if self.seat.removed() {
break;
}
let mut any_events = false;
while let Some(event) = self.seat.event() {
global.event(event);
any_events = true;
}
if any_events {
_node = self.state.seat_queue.add_last(global.clone());
}
ae.triggered().await;
}
global.set_cursor(None);
let _ = self.state.remove_global(&*global);
self.state.seats.borrow_mut().remove(&self.seat.id());
}
}
async fn tree_changed(state: Rc<State>, global: Rc<WlSeatGlobal>, tree_changed: Rc<AsyncEvent>) {
loop {
tree_changed.triggered().await;
state.tree_changed_sent.set(false);
global.tree_changed();
}
}

View file

@ -1,7 +1,7 @@
use crate::backend::{KeyState, SeatId};
use crate::backend::{KeyState};
use crate::cursor::KnownCursor;
use crate::fixed::Fixed;
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal, BTN_LEFT};
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal, BTN_LEFT, SeatId};
use crate::rect::Rect;
use crate::render::Renderer;
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
@ -14,6 +14,7 @@ use std::fmt::{Debug, Formatter};
use std::mem;
use std::ops::DerefMut;
use std::rc::Rc;
use i4config::Direction;
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -421,6 +422,52 @@ impl Node for ContainerNode {
self.seat_state.destroy_node(self);
}
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let node = match direction {
Direction::Left => self.children.last(),
Direction::Down => self.children.first(),
Direction::Up => self.children.last(),
Direction::Right => self.children.first(),
};
if let Some(node) = node {
node.node.clone().do_focus(seat, direction);
}
}
fn move_focus_from_child(&self, seat: &Rc<WlSeatGlobal>, child: &dyn Node, direction: Direction) {
let children = self.child_nodes.borrow_mut();
let child = match children.get(&child.id()) {
Some(c) => c,
_ => return,
};
let in_line = match self.split.get() {
ContainerSplit::Horizontal => matches!(direction, Direction::Left | Direction::Right),
ContainerSplit::Vertical => matches!(direction, Direction::Up | Direction::Down),
};
if !in_line {
self.parent.get().move_focus_from_child(seat, self, direction);
return;
}
let prev = match direction {
Direction::Left => true,
Direction::Down => false,
Direction::Up => true,
Direction::Right => false,
};
let sibling = match prev {
true => child.prev(),
false => child.next()
};
let sibling = match sibling {
Some(s) => s,
None => {
self.parent.get().move_focus_from_child(seat, self, direction);
return;
}
};
sibling.node.clone().do_focus(seat, direction);
}
fn absolute_position(&self) -> Rect {
Rect::new_sized(
self.abs_x1.get(),

View file

@ -17,6 +17,7 @@ use std::cell::{Cell, RefCell};
use std::fmt::{Debug, Display, Formatter};
use std::ops::Deref;
use std::rc::Rc;
use i4config::Direction;
pub use workspace::*;
mod container;
@ -66,6 +67,22 @@ pub trait Node {
fn seat_state(&self) -> &NodeSeatState;
fn destroy_node(&self, detach: bool);
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let _ = seat;
let _ = direction;
}
fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let _ = seat;
let _ = direction;
}
fn move_focus_from_child(&self, seat: &Rc<WlSeatGlobal>, child: &dyn Node, direction: Direction) {
let _ = seat;
let _ = direction;
let _ = child;
}
fn absolute_position(&self) -> Rect {
Rect::new_empty(0, 0)
}
@ -78,10 +95,14 @@ pub trait Node {
let _ = active;
}
fn key(&self, seat: &WlSeatGlobal, key: u32, state: u32, mods: Option<ModifierState>) {
fn key(&self, seat: &WlSeatGlobal, key: u32, state: u32) {
let _ = seat;
let _ = key;
let _ = state;
}
fn mods(&self, seat: &WlSeatGlobal, mods: ModifierState) {
let _ = seat;
let _ = mods;
}

View file

@ -2,6 +2,7 @@ use crate::utils::ptr_ext::PtrExt;
use crate::NumCell;
use std::cell::Cell;
use std::fmt::{Debug, Formatter};
use std::mem;
use std::ops::Deref;
use std::ptr::NonNull;
@ -153,6 +154,7 @@ impl<T> Drop for RevLinkedListIter<T> {
}
}
#[repr(transparent)]
pub struct LinkedNode<T> {
data: NonNull<NodeData<T>>,
}
@ -164,13 +166,14 @@ impl<T: Debug> Debug for LinkedNode<T> {
}
impl<T> Deref for LinkedNode<T> {
type Target = T;
type Target = NodeRef<T>;
fn deref(&self) -> &Self::Target {
unsafe { self.data.as_ref().data.as_ref().unwrap_unchecked() }
unsafe { mem::transmute(self) }
}
}
#[repr(transparent)]
pub struct NodeRef<T> {
data: NonNull<NodeData<T>>,
}
@ -215,10 +218,12 @@ impl<T> NodeRef<T> {
unsafe { append(self.data, t) }
}
pub fn prev(&self) -> Option<NodeRef<T>> {
fn peer<F>(&self, peer: F) -> Option<NodeRef<T>>
where F: FnOnce(&NodeData<T>) -> &Cell<NonNull<NodeData<T>>>,
{
unsafe {
let data = self.data.as_ref();
let other = data.prev.get();
let other = peer(&data).get();
if other.as_ref().data.is_some() {
other.as_ref().rc.fetch_add(1);
Some(NodeRef { data: other })
@ -227,6 +232,14 @@ impl<T> NodeRef<T> {
}
}
}
pub fn prev(&self) -> Option<NodeRef<T>> {
self.peer(|d| &d.prev)
}
pub fn next(&self) -> Option<NodeRef<T>> {
self.peer(|d| &d.next)
}
}
struct NodeData<T> {

View file

@ -11,3 +11,4 @@ pub mod ptr_ext;
pub mod queue;
pub mod smallmap;
pub mod vec_ext;
pub mod stack;

28
src/utils/stack.rs Normal file
View file

@ -0,0 +1,28 @@
use std::cell::UnsafeCell;
use crate::utils::ptr_ext::MutPtrExt;
pub struct Stack<T> {
vec: UnsafeCell<Vec<T>>,
}
impl<T> Default for Stack<T> {
fn default() -> Self {
Self {
vec: Default::default(),
}
}
}
impl<T> Stack<T> {
pub fn push(&self, v: T) {
unsafe {
self.vec.get().deref_mut().push(v);
}
}
pub fn pop(&self) -> Option<T> {
unsafe {
self.vec.get().deref_mut().pop()
}
}
}

View file

@ -7,12 +7,14 @@ include!(concat!(env!("OUT_DIR"), "/xkbcommon_tys.rs"));
use bstr::{BStr, ByteSlice};
pub use consts::*;
use std::ffi::{CStr, VaList};
use std::io::Write;
use std::ops::Deref;
use std::ptr;
use std::rc::Rc;
use crate::utils::ptr_ext::PtrExt;
use thiserror::Error;
use uapi::c;
use uapi::{c, OwnedFd};
#[derive(Debug, Error)]
pub enum XkbCommonError {
@ -20,8 +22,8 @@ pub enum XkbCommonError {
CreateContext,
#[error("Could not create an xkbcommon state")]
CreateState,
#[error("Could not create keymap from names")]
KeymapFromNames,
#[error("Could not create keymap from buffer")]
KeymapFromBuffer,
#[error("Could not convert the keymap to a string")]
AsStr,
}
@ -30,6 +32,11 @@ struct xkb_context;
struct xkb_keymap;
struct xkb_state;
type xkb_keycode_t = u32;
type xkb_layout_index_t = u32;
type xkb_level_index_t = u32;
type xkb_keysym_t = u32;
#[repr(C)]
struct xkb_rule_names {
rules: *const c::c_char,
@ -55,6 +62,7 @@ impl Default for xkb_rule_names {
extern "C" {
fn xkb_context_new(flags: xkb_context_flags) -> *mut xkb_context;
fn xkb_context_unref(context: *mut xkb_context);
fn xkb_context_set_log_verbosity(context: *mut xkb_context, verbosity: c::c_int);
fn xkb_context_set_log_fn(
context: *mut xkb_context,
log_fn: unsafe extern "C" fn(
@ -64,9 +72,11 @@ extern "C" {
args: VaList,
),
);
fn xkb_keymap_new_from_names(
fn xkb_keymap_new_from_buffer(
context: *mut xkb_context,
name: *const xkb_rule_names,
buffer: *const u8,
length: usize,
format: xkb_keymap_format,
flags: xkb_keymap_compile_flags,
) -> *mut xkb_keymap;
fn xkb_keymap_get_as_string(
@ -74,6 +84,14 @@ extern "C" {
format: xkb_keymap_format,
) -> *mut c::c_char;
fn xkb_keymap_unref(keymap: *mut xkb_keymap);
// fn xkb_keymap_ref(keymap: *mut xkb_keymap) -> *mut xkb_keymap;
fn xkb_keymap_key_get_syms_by_level(
keymap: *mut xkb_keymap,
key: xkb_keycode_t,
layout: xkb_layout_index_t,
level: xkb_level_index_t,
syms_out: *mut *const xkb_keysym_t,
) -> c::c_int;
fn xkb_state_unref(state: *mut xkb_state);
fn xkb_state_new(keymap: *mut xkb_keymap) -> *mut xkb_state;
#[allow(dead_code)]
@ -99,19 +117,47 @@ impl XkbContext {
return Err(XkbCommonError::CreateContext);
}
unsafe {
xkb_context_set_log_verbosity(res, 10);
xkb_context_set_log_fn(res, xkbcommon_logger);
}
Ok(Self { context: res })
}
pub fn default_keymap(&self) -> Result<XkbKeymap, XkbCommonError> {
unsafe {
let names = Default::default();
let keymap = xkb_keymap_new_from_names(self.context, &names, 0);
if keymap.is_null() {
return Err(XkbCommonError::KeymapFromNames);
fn raw_to_map(raw: *mut xkb_keymap) -> Result<Rc<XkbKeymap>, XkbCommonError> {
let res =
unsafe { xkb_keymap_get_as_string(raw, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) };
if res.is_null() {
unsafe {
xkb_keymap_unref(raw);
}
Ok(XkbKeymap { keymap })
return Err(XkbCommonError::AsStr);
}
let str = XkbKeymapStr {
s: unsafe { CStr::from_ptr(res).to_bytes().as_bstr() },
};
let mut memfd =
uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
memfd.write_all(str.as_bytes()).unwrap();
memfd.write_all(&[0]).unwrap();
uapi::lseek(memfd.raw(), 0, c::SEEK_SET).unwrap();
uapi::fcntl_add_seals(
memfd.raw(),
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
).unwrap();
Ok(Rc::new(XkbKeymap {
keymap: raw,
map: Rc::new(memfd),
map_len: str.len() + 1,
}))
}
pub fn keymap_from_str(&self, s: &str) -> Result<Rc<XkbKeymap>, XkbCommonError> {
unsafe {
let keymap = xkb_keymap_new_from_buffer(self.context, s.as_bytes().as_ptr(), s.len(), XKB_KEYMAP_FORMAT_TEXT_V1.raw(), 0);
if keymap.is_null() {
return Err(XkbCommonError::KeymapFromBuffer);
}
Self::raw_to_map(keymap)
}
}
}
@ -126,31 +172,24 @@ impl Drop for XkbContext {
pub struct XkbKeymap {
keymap: *mut xkb_keymap,
pub map: Rc<OwnedFd>,
pub map_len: usize,
}
impl XkbKeymap {
pub fn as_str(&self) -> Result<XkbKeymapStr, XkbCommonError> {
let res =
unsafe { xkb_keymap_get_as_string(self.keymap, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) };
if res.is_null() {
return Err(XkbCommonError::AsStr);
}
Ok(XkbKeymapStr {
s: unsafe { CStr::from_ptr(res).to_bytes().as_bstr() },
})
}
pub fn state(&self) -> Result<XkbState, XkbCommonError> {
pub fn state(self: &Rc<Self>) -> Result<XkbState, XkbCommonError> {
let res = unsafe { xkb_state_new(self.keymap) };
if res.is_null() {
return Err(XkbCommonError::CreateState);
}
Ok(XkbState {
map: self.clone(),
state: res,
mods: ModifierState {
mods_depressed: 0,
mods_latched: 0,
mods_locked: 0,
mods_effective: 0,
group: 0,
},
})
@ -188,10 +227,12 @@ pub struct ModifierState {
pub mods_depressed: u32,
pub mods_latched: u32,
pub mods_locked: u32,
pub mods_effective: u32,
pub group: u32,
}
pub struct XkbState {
map: Rc<XkbKeymap>,
state: *mut xkb_state,
mods: ModifierState,
}
@ -212,6 +253,8 @@ impl XkbState {
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LATCHED.raw() as _);
self.mods.mods_locked =
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LOCKED.raw() as _);
self.mods.mods_effective =
self.mods.mods_depressed | self.mods.mods_latched | self.mods.mods_locked;
self.mods.group =
xkb_state_serialize_layout(self.state, XKB_STATE_LAYOUT_EFFECTIVE.raw() as _);
Some(self.mods)
@ -220,6 +263,24 @@ impl XkbState {
}
}
}
pub fn unmodified_keysyms(&self, key: u32) -> &[xkb_keysym_t] {
let mut res = ptr::null();
unsafe {
let num = xkb_keymap_key_get_syms_by_level(
self.map.keymap,
key + 8,
self.mods.group,
0,
&mut res,
);
if num > 0 {
std::slice::from_raw_parts(res, num as usize)
} else {
&[]
}
}
}
}
impl Drop for XkbState {
@ -242,10 +303,10 @@ unsafe extern "C" fn xkbcommon_logger(
let mut buf = ptr::null_mut();
let res = vasprintf(&mut buf, format, args);
if res < 0 {
log::warn!("Could not vasprintf");
log::error!("Could not vasprintf");
return;
}
let buf = std::slice::from_raw_parts(buf as *const u8, res as usize);
let buf = buf.as_bstr();
let level = match XkbLogLevel(level) {
XKB_LOG_LEVEL_CRITICAL | XKB_LOG_LEVEL_ERROR => log::Level::Error,
XKB_LOG_LEVEL_WARNING => log::Level::Warn,
@ -253,5 +314,5 @@ unsafe extern "C" fn xkbcommon_logger(
XKB_LOG_LEVEL_DEBUG => log::Level::Debug,
_ => log::Level::Error,
};
log::log!(level, "xkbcommon: {}", buf);
log::log!(level, "xkbcommon: {}", buf.trim_end().as_bstr());
}