From da783fcf7fd70e3531d248cbb5f320a94564fc29 Mon Sep 17 00:00:00 2001 From: Seaotatop Date: Thu, 15 Jun 2023 16:43:33 -0500 Subject: [PATCH] Working MVP for setting keybinds through the api --- pinnacle/Cargo.toml | 2 +- pinnacle/src/input.rs | 29 +++++++- pinnacle/src/main.rs | 2 +- pinnacle/src/state.rs | 43 ++++++++++- pinnacle_api/Cargo.toml | 1 + pinnacle_api/src/lib.rs | 145 ++++++++++++++++++++++++++++++++++++ pinnacle_api/src/message.rs | 23 +++++- 7 files changed, 236 insertions(+), 9 deletions(-) diff --git a/pinnacle/Cargo.toml b/pinnacle/Cargo.toml index 16a1801..19fc880 100644 --- a/pinnacle/Cargo.toml +++ b/pinnacle/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" pinnacle_api = { path = "../pinnacle_api" } tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } -smithay = { git = "https://github.com/Smithay/smithay" } +smithay = { git = "https://github.com/Smithay/smithay", rev = "9b3d173" } smithay-drm-extras = { git = "https://github.com/Smithay/smithay", optional = true } thiserror = "1.0.40" xcursor = {version = "0.3.4", optional = true } diff --git a/pinnacle/src/input.rs b/pinnacle/src/input.rs index 7a7cc4a..c650109 100644 --- a/pinnacle/src/input.rs +++ b/pinnacle/src/input.rs @@ -1,3 +1,6 @@ +use std::collections::HashMap; + +use pinnacle_api::message::{ModifierMask, Modifiers}; use smithay::{ backend::input::{ AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent, @@ -18,6 +21,10 @@ use crate::{ state::State, }; +pub struct InputState { + pub keybinds: HashMap<(ModifierMask, u32), u32>, +} + impl State { pub fn surface_under

(&self, point: P) -> Option<(Window, Point)> where @@ -189,8 +196,28 @@ impl State { press_state, serial, time, - |state, _modifiers, keysym| { + |state, modifiers, keysym| { if press_state == KeyState::Pressed { + let mut modifier_mask = Vec::::new(); + if modifiers.alt { + modifier_mask.push(Modifiers::Alt); + } + if modifiers.shift { + modifier_mask.push(Modifiers::Shift); + } + if modifiers.ctrl { + modifier_mask.push(Modifiers::Ctrl); + } + if modifiers.logo { + modifier_mask.push(Modifiers::Super); + } + if let Some(callback_id) = state + .input_state + .keybinds + .get(&(modifier_mask.into(), keysym.modified_sym())) + { + return FilterResult::Intercept(1); + } match keysym.modified_sym() { keysyms::KEY_L => return FilterResult::Intercept(1), keysyms::KEY_K => return FilterResult::Intercept(2), diff --git a/pinnacle/src/main.rs b/pinnacle/src/main.rs index ea6a4a7..e6fe6a2 100644 --- a/pinnacle/src/main.rs +++ b/pinnacle/src/main.rs @@ -13,7 +13,7 @@ mod xdg; use std::error::Error; fn main() -> Result<(), Box> { - pinnacle_api::run()?; + // pinnacle_api::run()?; match tracing_subscriber::EnvFilter::try_from_default_env() { Ok(env_filter) => { diff --git a/pinnacle/src/state.rs b/pinnacle/src/state.rs index 60b13dc..17ce3e1 100644 --- a/pinnacle/src/state.rs +++ b/pinnacle/src/state.rs @@ -1,5 +1,6 @@ -use std::{error::Error, os::fd::AsRawFd, sync::Arc}; +use std::{collections::HashMap, error::Error, os::fd::AsRawFd, sync::Arc}; +use pinnacle_api::{message::Msg, PinnacleSocketSource, PinnacleStreamSource}; use smithay::{ backend::renderer::element::RenderElementStates, desktop::{ @@ -34,7 +35,7 @@ use smithay::{ }, }; -use crate::backend::Backend; +use crate::{backend::Backend, input::InputState}; pub struct State { pub backend_data: B, @@ -57,6 +58,7 @@ pub struct State { pub xdg_shell_state: XdgShellState, pub viewporter_state: ViewporterState, pub fractional_scale_manager_state: FractionalScaleManagerState, + pub input_state: InputState, pub popup_manager: PopupManager, @@ -95,6 +97,29 @@ impl State { }, )?; + loop_handle.insert_source(PinnacleSocketSource::new()?, |stream, _, data| { + data.state + .loop_handle + .insert_source(PinnacleStreamSource::new(stream), |msg, _, data| { + // TODO: do stuff with msg + match msg { + Msg::SetKeybind { + key, + modifiers, + callback_id, + } => { + tracing::info!("set keybind: {:?}, {}", modifiers, key); + data.state + .input_state + .keybinds + .insert((modifiers.into(), key), callback_id); + } + Msg::SetMousebind { button } => todo!(), + }; + }) + .unwrap(); + })?; + let display_handle = display.handle(); let mut seat_state = SeatState::new(); let mut seat = seat_state.new_wl_seat(&display_handle, backend_data.seat_name()); @@ -119,6 +144,9 @@ impl State { fractional_scale_manager_state: FractionalScaleManagerState::new::( &display_handle, ), + input_state: InputState { + keybinds: HashMap::new(), + }, seat, @@ -136,6 +164,17 @@ impl State { .find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false)) .cloned() } + + pub fn handle_msg(msg: Msg) { + match msg { + Msg::SetKeybind { + key, + modifiers, + callback_id, + } => todo!(), + Msg::SetMousebind { button } => todo!(), + } + } } pub struct CalloopData { diff --git a/pinnacle_api/Cargo.toml b/pinnacle_api/Cargo.toml index 21bfc5c..9bf52bb 100644 --- a/pinnacle_api/Cargo.toml +++ b/pinnacle_api/Cargo.toml @@ -12,3 +12,4 @@ serde = { version = "1.0.164", features = ["derive"] } serde_json = { version = "1.0.96" } rmp-serde = { version = "1.1.1" } xkbcommon = { version = "0.5.0" } +smithay = { git = "https://github.com/Smithay/smithay", rev = "9b3d173" } diff --git a/pinnacle_api/src/lib.rs b/pinnacle_api/src/lib.rs index 462856a..38e8a25 100644 --- a/pinnacle_api/src/lib.rs +++ b/pinnacle_api/src/lib.rs @@ -1,9 +1,14 @@ use std::{ error::Error, + io, os::unix::net::{UnixListener, UnixStream}, path::Path, }; +use smithay::reexports::calloop::{ + self, generic::Generic, EventSource, Interest, Mode, PostAction, +}; + use crate::message::Msg; pub mod message; @@ -42,3 +47,143 @@ fn handle_client(stream: UnixStream) { println!("{:?}", msg); } } + +pub struct PinnacleSocketSource { + socket: Generic, +} + +impl PinnacleSocketSource { + pub fn new() -> Result { + let socket_path = Path::new(SOCKET_PATH); + + if socket_path.exists() { + std::fs::remove_file(socket_path)?; + } + + let listener = UnixListener::bind(SOCKET_PATH)?; + + let socket = Generic::new(listener, Interest::READ, Mode::Level); + + Ok(Self { socket }) + } +} + +impl EventSource for PinnacleSocketSource { + type Event = UnixStream; + + type Metadata = (); + + type Ret = (); + + type Error = io::Error; + + fn process_events( + &mut self, + readiness: calloop::Readiness, + token: calloop::Token, + mut callback: F, + ) -> Result + where + F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + self.socket + .process_events(readiness, token, |_readiness, listener| { + listener.set_nonblocking(true)?; + while let Ok((stream, _sock_addr)) = listener.accept() { + stream.set_nonblocking(true)?; + callback(stream, &mut ()); + } + + Ok(PostAction::Continue) + }) + } + + fn register( + &mut self, + poll: &mut calloop::Poll, + token_factory: &mut calloop::TokenFactory, + ) -> calloop::Result<()> { + self.socket.register(poll, token_factory) + } + + fn reregister( + &mut self, + poll: &mut calloop::Poll, + token_factory: &mut calloop::TokenFactory, + ) -> calloop::Result<()> { + self.socket.reregister(poll, token_factory) + } + + fn unregister(&mut self, poll: &mut calloop::Poll) -> calloop::Result<()> { + self.socket.unregister(poll) + } +} + +pub struct PinnacleStreamSource { + stream: Generic, +} + +impl PinnacleStreamSource { + pub fn new(stream: UnixStream) -> Self { + Self { + stream: Generic::new(stream, Interest::READ, Mode::Level), + } + } +} + +impl EventSource for PinnacleStreamSource { + type Event = Msg; + + type Metadata = (); + + type Ret = (); + + type Error = io::Error; + + fn process_events( + &mut self, + readiness: calloop::Readiness, + token: calloop::Token, + mut callback: F, + ) -> Result + where + F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + self.stream + .process_events(readiness, token, |_readiness, stream| { + match rmp_serde::from_read(stream as &UnixStream) { + Ok(msg) => callback(msg, &mut ()), + Err(rmp_serde::decode::Error::InvalidMarkerRead(err)) + if err.kind() == io::ErrorKind::UnexpectedEof => + { + stream.shutdown(std::net::Shutdown::Both)?; + println!("Stream closed: {:?}", err); + return Ok(PostAction::Remove); + } + Err(err) => println!("{:?}", err), + } + + Ok(PostAction::Continue) + }) + } + + fn register( + &mut self, + poll: &mut calloop::Poll, + token_factory: &mut calloop::TokenFactory, + ) -> calloop::Result<()> { + self.stream.register(poll, token_factory) + } + + fn reregister( + &mut self, + poll: &mut calloop::Poll, + token_factory: &mut calloop::TokenFactory, + ) -> calloop::Result<()> { + self.stream.reregister(poll, token_factory) + } + + fn unregister(&mut self, poll: &mut calloop::Poll) -> calloop::Result<()> { + self.stream.unregister(poll) + } +} diff --git a/pinnacle_api/src/message.rs b/pinnacle_api/src/message.rs index 80c9188..6dc252c 100644 --- a/pinnacle_api/src/message.rs +++ b/pinnacle_api/src/message.rs @@ -21,8 +21,23 @@ pub enum Action { #[derive(Debug, serde::Serialize, serde::Deserialize)] pub enum Modifiers { - Shift, - Ctrl, - Alt, - Super, + Shift = 0b0000_0001, + Ctrl = 0b0000_0010, + Alt = 0b0000_0100, + Super = 0b0000_1000, +} + +/// A bitmask of [Modifiers] for the purpose of hashing. +#[derive(PartialEq, Eq, Hash)] +pub struct ModifierMask(u8); + +impl> From for ModifierMask { + fn from(value: T) -> Self { + let value = value.into_iter(); + let mut mask: u8 = 0b0000_0000; + for modifier in value { + mask |= modifier as u8; + } + Self(mask) + } }