autocommit 2022-03-13 22:20:31 CET
This commit is contained in:
parent
156bd5b042
commit
a15a02a95c
38 changed files with 63 additions and 66 deletions
8
jay-config/Cargo.toml
Normal file
8
jay-config/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "jay-config"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bincode = "2.0.0-beta.3"
|
||||
log = "0.4.14"
|
||||
39
jay-config/src/_private.rs
Normal file
39
jay-config/src/_private.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
pub mod client;
|
||||
pub mod ipc;
|
||||
mod logging;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub const VERSION: u32 = 1;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ConfigEntry {
|
||||
pub version: u32,
|
||||
pub init: unsafe extern "C" fn(
|
||||
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,
|
||||
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 struct ConfigEntryGen<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Config> ConfigEntryGen<T> {}
|
||||
|
||||
pub fn bincode_ops() -> impl bincode::config::Config {
|
||||
bincode::config::standard()
|
||||
.with_fixed_int_encoding()
|
||||
.with_little_endian()
|
||||
.with_no_limit()
|
||||
.skip_fixed_array_length()
|
||||
}
|
||||
|
||||
pub trait Config {
|
||||
extern "C" fn configure();
|
||||
}
|
||||
410
jay-config/src/_private/client.rs
Normal file
410
jay-config/src/_private/client.rs
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage};
|
||||
use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION};
|
||||
use crate::keyboard::keymap::Keymap;
|
||||
use crate::theme::Color;
|
||||
use crate::{Axis, Command, Direction, InputDevice, LogLevel, ModifiedKeySym, Seat};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::{ptr, slice};
|
||||
|
||||
pub(crate) struct Client {
|
||||
configure: extern "C" fn(),
|
||||
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),
|
||||
key_handlers: RefCell<HashMap<(Seat, ModifiedKeySym), Rc<dyn Fn()>>>,
|
||||
response: RefCell<Vec<Response>>,
|
||||
on_new_seat: RefCell<Option<Rc<dyn Fn(Seat)>>>,
|
||||
on_new_input_device: RefCell<Option<Rc<dyn Fn(InputDevice)>>>,
|
||||
bufs: RefCell<Vec<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl Drop for Client {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
(self.srv_unref)(self.srv_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
pub(crate) static CLIENT: std::cell::Cell<*const Client> = const { std::cell::Cell::new(ptr::null()) };
|
||||
}
|
||||
|
||||
unsafe fn with_client<T, F: FnOnce(&Client) -> T>(data: *const u8, f: F) -> T {
|
||||
struct Reset<'a> {
|
||||
cell: &'a Cell<*const Client>,
|
||||
val: *const Client,
|
||||
}
|
||||
impl Drop for Reset<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.cell.set(self.val);
|
||||
}
|
||||
}
|
||||
CLIENT.with(|cell| unsafe {
|
||||
let client = data as *const Client;
|
||||
Rc::increment_strong_count(client);
|
||||
let client = Rc::from_raw(client);
|
||||
let old = cell.replace(client.deref());
|
||||
let _reset = Reset { cell, val: old };
|
||||
f(&client)
|
||||
})
|
||||
}
|
||||
|
||||
impl<T: Config> ConfigEntryGen<T> {
|
||||
pub const ENTRY: ConfigEntry = ConfigEntry {
|
||||
version: VERSION,
|
||||
init: Self::init,
|
||||
unref,
|
||||
handle_msg,
|
||||
};
|
||||
|
||||
pub unsafe extern "C" fn 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),
|
||||
init_data: *const u8,
|
||||
size: usize,
|
||||
) -> *const u8 {
|
||||
logging::init();
|
||||
init(
|
||||
srv_data,
|
||||
srv_unref,
|
||||
srv_handler,
|
||||
init_data,
|
||||
size,
|
||||
T::configure,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn 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),
|
||||
init: *const u8,
|
||||
size: usize,
|
||||
f: extern "C" fn(),
|
||||
) -> *const u8 {
|
||||
let client = Rc::new(Client {
|
||||
configure: f,
|
||||
srv_data,
|
||||
srv_unref,
|
||||
srv_handler,
|
||||
key_handlers: Default::default(),
|
||||
response: Default::default(),
|
||||
on_new_seat: Default::default(),
|
||||
on_new_input_device: Default::default(),
|
||||
bufs: Default::default(),
|
||||
});
|
||||
let init = slice::from_raw_parts(init, size);
|
||||
client.handle_init_msg(init);
|
||||
Rc::into_raw(client) as *const u8
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn unref(data: *const u8) {
|
||||
let client = data as *const Client;
|
||||
drop(Rc::from_raw(client));
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
|
||||
with_client(data, |client| {
|
||||
let msg = slice::from_raw_parts(msg, size);
|
||||
client.handle_msg(msg);
|
||||
});
|
||||
}
|
||||
|
||||
impl Client {
|
||||
fn send(&self, msg: &ClientMessage) {
|
||||
let mut buf = self.bufs.borrow_mut().pop().unwrap_or_default();
|
||||
buf.clear();
|
||||
bincode::encode_into_std_write(msg, &mut buf, bincode_ops()).unwrap();
|
||||
unsafe {
|
||||
(self.srv_handler)(self.srv_data, buf.as_ptr(), buf.len());
|
||||
}
|
||||
self.bufs.borrow_mut().push(buf);
|
||||
}
|
||||
|
||||
pub fn spawn(&self, command: &Command) {
|
||||
let env = command
|
||||
.env
|
||||
.iter()
|
||||
.map(|(a, b)| (a.to_string(), b.to_string()))
|
||||
.collect();
|
||||
self.send(&ClientMessage::Run {
|
||||
prog: &command.prog,
|
||||
args: command.args.clone(),
|
||||
env,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn grab(&self, kb: InputDevice, grab: bool) {
|
||||
self.send(&ClientMessage::GrabKb { kb, grab });
|
||||
}
|
||||
|
||||
pub fn focus(&self, seat: Seat, direction: Direction) {
|
||||
self.send(&ClientMessage::Focus { seat, direction });
|
||||
}
|
||||
|
||||
pub fn move_(&self, seat: Seat, direction: Direction) {
|
||||
self.send(&ClientMessage::Move { seat, direction });
|
||||
}
|
||||
|
||||
pub fn unbind<T: Into<ModifiedKeySym>>(&self, seat: Seat, mod_sym: T) {
|
||||
let mod_sym = mod_sym.into();
|
||||
let deregister = self
|
||||
.key_handlers
|
||||
.borrow_mut()
|
||||
.remove(&(seat, mod_sym))
|
||||
.is_some();
|
||||
if deregister {
|
||||
self.send(&ClientMessage::RemoveShortcut {
|
||||
seat,
|
||||
mods: mod_sym.mods,
|
||||
sym: mod_sym.sym,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn with_response<F: FnOnce()>(&self, f: F) -> Response {
|
||||
f();
|
||||
self.response.borrow_mut().pop().unwrap_or(Response::None)
|
||||
}
|
||||
|
||||
pub fn seats(&self) -> Vec<Seat> {
|
||||
let response = self.with_response(|| self.send(&ClientMessage::GetSeats));
|
||||
match response {
|
||||
Response::GetSeats { seats } => seats,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a get_seats request");
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split(&self, seat: Seat) -> Axis {
|
||||
let res = self.with_response(|| self.send(&ClientMessage::GetSplit { seat }));
|
||||
match res {
|
||||
Response::GetSplit { axis } => axis,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a get_split request");
|
||||
Axis::Horizontal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_floating(&self, seat: Seat) {
|
||||
self.send(&ClientMessage::ToggleFloating { seat });
|
||||
}
|
||||
|
||||
pub fn set_title_color(&self, color: Color) {
|
||||
self.send(&ClientMessage::SetTitleColor { color });
|
||||
}
|
||||
|
||||
pub fn set_border_color(&self, color: Color) {
|
||||
self.send(&ClientMessage::SetBorderColor { color });
|
||||
}
|
||||
|
||||
pub fn set_title_underline_color(&self, color: Color) {
|
||||
self.send(&ClientMessage::SetTitleUnderlineColor { color });
|
||||
}
|
||||
|
||||
pub fn set_background_color(&self, color: Color) {
|
||||
self.send(&ClientMessage::SetBackgroundColor { color });
|
||||
}
|
||||
|
||||
pub fn get_title_height(&self) -> i32 {
|
||||
let resp = self.with_response(|| self.send(&ClientMessage::GetTitleHeight));
|
||||
match resp {
|
||||
Response::GetTitleHeight { height } => height,
|
||||
_ => {
|
||||
log::warn!("Server did not reply to a get_title_height request");
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_border_width(&self) -> i32 {
|
||||
let resp = self.with_response(|| self.send(&ClientMessage::GetBorderWidth));
|
||||
match resp {
|
||||
Response::GetBorderWidth { width } => width,
|
||||
_ => {
|
||||
log::warn!("Server did not reply to a get_border_width request");
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_title_height(&self, height: i32) {
|
||||
self.send(&ClientMessage::SetTitleHeight { height })
|
||||
}
|
||||
|
||||
pub fn set_border_width(&self, width: i32) {
|
||||
self.send(&ClientMessage::SetBorderWidth { width })
|
||||
}
|
||||
|
||||
pub fn set_split(&self, seat: Seat, axis: Axis) {
|
||||
self.send(&ClientMessage::SetSplit { seat, axis });
|
||||
}
|
||||
|
||||
pub fn create_split(&self, seat: Seat, axis: Axis) {
|
||||
self.send(&ClientMessage::CreateSplit { seat, axis });
|
||||
}
|
||||
|
||||
pub fn focus_parent(&self, seat: Seat) {
|
||||
self.send(&ClientMessage::FocusParent { seat });
|
||||
}
|
||||
|
||||
pub fn create_seat(&self, name: &str) -> Seat {
|
||||
let response = self.with_response(|| self.send(&ClientMessage::CreateSeat { name }));
|
||||
match response {
|
||||
Response::CreateSeat { seat } => seat,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a create_seat request");
|
||||
Seat(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_input_devices(&self, seat: Option<Seat>) -> Vec<InputDevice> {
|
||||
let res = self.with_response(|| self.send(&ClientMessage::GetInputDevices { seat }));
|
||||
match res {
|
||||
Response::GetInputDevices { devices } => devices,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a get_input_devices request");
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_new_seat<F: Fn(Seat) + 'static>(&self, f: F) {
|
||||
*self.on_new_seat.borrow_mut() = Some(Rc::new(f));
|
||||
}
|
||||
|
||||
pub fn quit(&self) {
|
||||
self.send(&ClientMessage::Quit)
|
||||
}
|
||||
|
||||
pub fn on_new_input_device<F: Fn(InputDevice) + 'static>(&self, f: F) {
|
||||
*self.on_new_input_device.borrow_mut() = Some(Rc::new(f));
|
||||
}
|
||||
|
||||
pub fn set_seat(&self, device: InputDevice, seat: Seat) {
|
||||
self.send(&ClientMessage::SetSeat { device, seat })
|
||||
}
|
||||
|
||||
pub fn seat_set_keymap(&self, seat: Seat, keymap: Keymap) {
|
||||
self.send(&ClientMessage::SeatSetKeymap { seat, keymap })
|
||||
}
|
||||
|
||||
pub fn seat_set_repeat_rate(&self, seat: Seat, rate: i32, delay: i32) {
|
||||
self.send(&ClientMessage::SeatSetRepeatRate { seat, rate, delay })
|
||||
}
|
||||
|
||||
pub fn seat_get_repeat_rate(&self, seat: Seat) -> (i32, i32) {
|
||||
let res = self.with_response(|| self.send(&ClientMessage::SeatGetRepeatRate { seat }));
|
||||
match res {
|
||||
Response::GetRepeatRate { rate, delay } => (rate, delay),
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a get_repeat_rate request");
|
||||
(25, 250)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_keymap(&self, keymap: &str) -> Keymap {
|
||||
let res = self.with_response(|| self.send(&ClientMessage::ParseKeymap { keymap }));
|
||||
match res {
|
||||
Response::ParseKeymap { keymap } => keymap,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a parse_keymap request");
|
||||
Keymap(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind<T: Into<ModifiedKeySym>, F: Fn() + 'static>(&self, seat: Seat, mod_sym: T, f: F) {
|
||||
let mod_sym = mod_sym.into();
|
||||
let register = {
|
||||
let mut kh = self.key_handlers.borrow_mut();
|
||||
let f = Rc::new(f);
|
||||
match kh.entry((seat, mod_sym)) {
|
||||
Entry::Occupied(mut o) => {
|
||||
*o.get_mut() = f;
|
||||
false
|
||||
}
|
||||
Entry::Vacant(v) => {
|
||||
v.insert(f);
|
||||
true
|
||||
}
|
||||
}
|
||||
};
|
||||
if register {
|
||||
self.send(&ClientMessage::AddShortcut {
|
||||
seat,
|
||||
mods: mod_sym.mods,
|
||||
sym: mod_sym.sym,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log(&self, level: LogLevel, msg: &str, file: Option<&str>, line: Option<u32>) {
|
||||
self.send(&ClientMessage::Log {
|
||||
level,
|
||||
msg,
|
||||
file,
|
||||
line,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_msg(&self, msg: &[u8]) {
|
||||
let res = bincode::decode_from_slice::<ServerMessage, _>(msg, bincode_ops());
|
||||
let (msg, _) = match res {
|
||||
Ok(msg) => msg,
|
||||
Err(e) => {
|
||||
let msg = format!("could not deserialize message: {}", e);
|
||||
self.log(LogLevel::Error, &msg, None, None);
|
||||
return;
|
||||
}
|
||||
};
|
||||
match msg {
|
||||
ServerMessage::Configure => {
|
||||
(self.configure)();
|
||||
}
|
||||
ServerMessage::Response { response } => {
|
||||
self.response.borrow_mut().push(response);
|
||||
}
|
||||
ServerMessage::InvokeShortcut { seat, mods, sym } => {
|
||||
let ms = ModifiedKeySym { mods, sym };
|
||||
let handler = self.key_handlers.borrow_mut().get(&(seat, ms)).cloned();
|
||||
if let Some(handler) = handler {
|
||||
handler();
|
||||
}
|
||||
}
|
||||
ServerMessage::NewInputDevice { device } => {
|
||||
let handler = self.on_new_input_device.borrow_mut().clone();
|
||||
if let Some(handler) = handler {
|
||||
handler(device);
|
||||
}
|
||||
}
|
||||
ServerMessage::DelInputDevice { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_init_msg(&self, msg: &[u8]) {
|
||||
let (init, _) = match bincode::decode_from_slice::<InitMessage, _>(msg, bincode_ops()) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
let msg = format!("could not deserialize message: {}", e);
|
||||
self.log(LogLevel::Error, &msg, None, None);
|
||||
return;
|
||||
}
|
||||
};
|
||||
match init {
|
||||
InitMessage::V1(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
150
jay-config/src/_private/ipc.rs
Normal file
150
jay-config/src/_private/ipc.rs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
use crate::keyboard::keymap::Keymap;
|
||||
use crate::keyboard::mods::Modifiers;
|
||||
use crate::keyboard::syms::KeySym;
|
||||
use crate::theme::Color;
|
||||
use crate::{Axis, Direction, InputDevice, LogLevel, Seat};
|
||||
use bincode::{BorrowDecode, Decode, Encode};
|
||||
|
||||
#[derive(Encode, BorrowDecode, Debug)]
|
||||
pub enum ServerMessage {
|
||||
Configure,
|
||||
Response {
|
||||
response: Response,
|
||||
},
|
||||
NewInputDevice {
|
||||
device: InputDevice,
|
||||
},
|
||||
DelInputDevice {
|
||||
device: InputDevice,
|
||||
},
|
||||
InvokeShortcut {
|
||||
seat: Seat,
|
||||
mods: Modifiers,
|
||||
sym: KeySym,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Encode, BorrowDecode, Debug)]
|
||||
pub enum ClientMessage<'a> {
|
||||
Log {
|
||||
level: LogLevel,
|
||||
msg: &'a str,
|
||||
file: Option<&'a str>,
|
||||
line: Option<u32>,
|
||||
},
|
||||
CreateSeat {
|
||||
name: &'a str,
|
||||
},
|
||||
Quit,
|
||||
SetSeat {
|
||||
device: InputDevice,
|
||||
seat: Seat,
|
||||
},
|
||||
ParseKeymap {
|
||||
keymap: &'a str,
|
||||
},
|
||||
SeatSetKeymap {
|
||||
seat: Seat,
|
||||
keymap: Keymap,
|
||||
},
|
||||
SeatGetRepeatRate {
|
||||
seat: Seat,
|
||||
},
|
||||
SeatSetRepeatRate {
|
||||
seat: Seat,
|
||||
rate: i32,
|
||||
delay: i32,
|
||||
},
|
||||
GetSplit {
|
||||
seat: Seat,
|
||||
},
|
||||
SetSplit {
|
||||
seat: Seat,
|
||||
axis: Axis,
|
||||
},
|
||||
RemoveSeat {
|
||||
seat: Seat,
|
||||
},
|
||||
GetSeats,
|
||||
GetInputDevices {
|
||||
seat: Option<Seat>,
|
||||
},
|
||||
AddShortcut {
|
||||
seat: Seat,
|
||||
mods: Modifiers,
|
||||
sym: KeySym,
|
||||
},
|
||||
RemoveShortcut {
|
||||
seat: Seat,
|
||||
mods: Modifiers,
|
||||
sym: KeySym,
|
||||
},
|
||||
Run {
|
||||
prog: &'a str,
|
||||
args: Vec<String>,
|
||||
env: Vec<(String, String)>,
|
||||
},
|
||||
Focus {
|
||||
seat: Seat,
|
||||
direction: Direction,
|
||||
},
|
||||
Move {
|
||||
seat: Seat,
|
||||
direction: Direction,
|
||||
},
|
||||
GrabKb {
|
||||
kb: InputDevice,
|
||||
grab: bool,
|
||||
},
|
||||
GetTitleHeight,
|
||||
GetBorderWidth,
|
||||
SetTitleHeight {
|
||||
height: i32,
|
||||
},
|
||||
SetBorderWidth {
|
||||
width: i32,
|
||||
},
|
||||
SetTitleColor {
|
||||
color: Color,
|
||||
},
|
||||
SetTitleUnderlineColor {
|
||||
color: Color,
|
||||
},
|
||||
SetBorderColor {
|
||||
color: Color,
|
||||
},
|
||||
SetBackgroundColor {
|
||||
color: Color,
|
||||
},
|
||||
CreateSplit {
|
||||
seat: Seat,
|
||||
axis: Axis,
|
||||
},
|
||||
FocusParent {
|
||||
seat: Seat,
|
||||
},
|
||||
ToggleFloating {
|
||||
seat: Seat,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub enum Response {
|
||||
None,
|
||||
GetSeats { seats: Vec<Seat> },
|
||||
GetSplit { axis: Axis },
|
||||
GetRepeatRate { rate: i32, delay: i32 },
|
||||
ParseKeymap { keymap: Keymap },
|
||||
CreateSeat { seat: Seat },
|
||||
GetInputDevices { devices: Vec<InputDevice> },
|
||||
GetTitleHeight { height: i32 },
|
||||
GetBorderWidth { width: i32 },
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub enum InitMessage {
|
||||
V1(V1InitMessage),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub struct V1InitMessage {}
|
||||
39
jay-config/src/_private/logging.rs
Normal file
39
jay-config/src/_private/logging.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
use crate::LogLevel;
|
||||
use log::{Level, LevelFilter, Log, Metadata, Record};
|
||||
|
||||
pub fn init() {
|
||||
log::set_logger(&Logger).unwrap();
|
||||
log::set_max_level(LevelFilter::Trace);
|
||||
}
|
||||
|
||||
struct Logger;
|
||||
|
||||
impl Log for Logger {
|
||||
fn enabled(&self, _metadata: &Metadata) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
let client = get!();
|
||||
let level = match record.level() {
|
||||
Level::Error => LogLevel::Error,
|
||||
Level::Warn => LogLevel::Warn,
|
||||
Level::Info => LogLevel::Info,
|
||||
Level::Debug => LogLevel::Debug,
|
||||
Level::Trace => LogLevel::Trace,
|
||||
};
|
||||
let formatted;
|
||||
let msg = match record.args().as_str() {
|
||||
Some(s) => s,
|
||||
_ => {
|
||||
formatted = record.args().to_string();
|
||||
&formatted
|
||||
}
|
||||
};
|
||||
client.log(level, msg, record.file(), record.line());
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
5
jay-config/src/embedded.rs
Normal file
5
jay-config/src/embedded.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
use crate::InputDevice;
|
||||
|
||||
pub fn grab_input_device(kb: InputDevice, grab: bool) {
|
||||
get!().grab(kb, grab);
|
||||
}
|
||||
18
jay-config/src/keyboard/keymap.rs
Normal file
18
jay-config/src/keyboard/keymap.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use bincode::{Decode, Encode};
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Keymap(pub u64);
|
||||
|
||||
impl Keymap {
|
||||
pub const INVALID: Self = Self(0);
|
||||
|
||||
pub fn is_invalid(self) -> bool {
|
||||
self == Self::INVALID
|
||||
}
|
||||
|
||||
pub fn parse(self, keymap: &str) -> Self {
|
||||
let mut res = Self::INVALID;
|
||||
(|| res = get!().parse_keymap(keymap))();
|
||||
res
|
||||
}
|
||||
}
|
||||
40
jay-config/src/keyboard/mod.rs
Normal file
40
jay-config/src/keyboard/mod.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use crate::keyboard::mods::Modifiers;
|
||||
use crate::keyboard::syms::KeySym;
|
||||
use bincode::{Decode, Encode};
|
||||
use std::ops::{BitOr, BitOrAssign};
|
||||
|
||||
pub mod keymap;
|
||||
pub mod mods;
|
||||
pub mod syms;
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ModifiedKeySym {
|
||||
pub mods: Modifiers,
|
||||
pub sym: KeySym,
|
||||
}
|
||||
|
||||
impl From<KeySym> for ModifiedKeySym {
|
||||
fn from(sym: KeySym) -> Self {
|
||||
Self {
|
||||
mods: Modifiers(0),
|
||||
sym,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr<Modifiers> for ModifiedKeySym {
|
||||
type Output = ModifiedKeySym;
|
||||
|
||||
fn bitor(self, rhs: Modifiers) -> Self::Output {
|
||||
ModifiedKeySym {
|
||||
mods: self.mods | rhs,
|
||||
sym: self.sym,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign<Modifiers> for ModifiedKeySym {
|
||||
fn bitor_assign(&mut self, rhs: Modifiers) {
|
||||
self.mods |= rhs;
|
||||
}
|
||||
}
|
||||
60
jay-config/src/keyboard/mods.rs
Normal file
60
jay-config/src/keyboard/mods.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
use crate::keyboard::syms::KeySym;
|
||||
use crate::ModifiedKeySym;
|
||||
use bincode::{Decode, Encode};
|
||||
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Default, Hash, Debug)]
|
||||
pub struct Modifiers(pub u32);
|
||||
|
||||
pub const SHIFT: Modifiers = Modifiers(1 << 0);
|
||||
pub const LOCK: Modifiers = Modifiers(1 << 1);
|
||||
pub const CTRL: Modifiers = Modifiers(1 << 2);
|
||||
pub const MOD1: Modifiers = Modifiers(1 << 3);
|
||||
pub const MOD2: Modifiers = Modifiers(1 << 4);
|
||||
pub const MOD3: Modifiers = Modifiers(1 << 5);
|
||||
pub const MOD4: Modifiers = Modifiers(1 << 6);
|
||||
pub const MOD5: Modifiers = Modifiers(1 << 7);
|
||||
|
||||
pub const CAPS: Modifiers = LOCK;
|
||||
pub const ALT: Modifiers = MOD1;
|
||||
pub const NUM: Modifiers = MOD2;
|
||||
pub const LOGO: Modifiers = MOD4;
|
||||
|
||||
impl BitOr for Modifiers {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr<KeySym> for Modifiers {
|
||||
type Output = ModifiedKeySym;
|
||||
|
||||
fn bitor(self, rhs: KeySym) -> Self::Output {
|
||||
ModifiedKeySym {
|
||||
mods: self,
|
||||
sym: rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAnd for Modifiers {
|
||||
type Output = Self;
|
||||
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 & rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign for Modifiers {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAndAssign for Modifiers {
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
self.0 &= rhs.0
|
||||
}
|
||||
}
|
||||
2556
jay-config/src/keyboard/syms.rs
Normal file
2556
jay-config/src/keyboard/syms.rs
Normal file
File diff suppressed because it is too large
Load diff
196
jay-config/src/lib.rs
Normal file
196
jay-config/src/lib.rs
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
use crate::keyboard::keymap::Keymap;
|
||||
use crate::keyboard::ModifiedKeySym;
|
||||
use bincode::{Decode, Encode};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
#[doc(hidden)]
|
||||
pub mod _private;
|
||||
pub mod embedded;
|
||||
pub mod keyboard;
|
||||
pub mod theme;
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug)]
|
||||
pub enum LogLevel {
|
||||
Error,
|
||||
Warn,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Direction {
|
||||
Left,
|
||||
Down,
|
||||
Up,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct Seat(pub u64);
|
||||
|
||||
impl Seat {
|
||||
pub const INVALID: Self = Self(0);
|
||||
|
||||
pub fn is_invalid(self) -> bool {
|
||||
self == Self::INVALID
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct InputDevice(pub u64);
|
||||
|
||||
impl InputDevice {
|
||||
pub fn set_seat(self, seat: Seat) {
|
||||
get!().set_seat(self, seat)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum Axis {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
pub fn other(self) -> Self {
|
||||
match self {
|
||||
Self::Horizontal => Self::Vertical,
|
||||
Self::Vertical => Self::Horizontal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Seat {
|
||||
#[doc(hidden)]
|
||||
pub fn raw(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn from_raw(raw: u64) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
pub fn bind<T: Into<ModifiedKeySym>, F: Fn() + 'static>(self, mod_sym: T, f: F) {
|
||||
get!().bind(self, mod_sym, f)
|
||||
}
|
||||
|
||||
pub fn unbind<T: Into<ModifiedKeySym>>(self, mod_sym: T) {
|
||||
get!().unbind(self, mod_sym)
|
||||
}
|
||||
|
||||
pub fn focus(self, direction: Direction) {
|
||||
get!().focus(self, direction)
|
||||
}
|
||||
|
||||
pub fn move_(self, direction: Direction) {
|
||||
get!().move_(self, direction)
|
||||
}
|
||||
|
||||
pub fn set_keymap(self, keymap: Keymap) {
|
||||
get!().seat_set_keymap(self, keymap)
|
||||
}
|
||||
|
||||
pub fn repeat_rate(self) -> (i32, i32) {
|
||||
let mut res = (25, 250);
|
||||
(|| res = get!().seat_get_repeat_rate(self))();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn set_repeat_rate(self, rate: i32, delay: i32) {
|
||||
get!().seat_set_repeat_rate(self, rate, delay)
|
||||
}
|
||||
|
||||
pub fn split(self) -> Axis {
|
||||
let mut res = Axis::Horizontal;
|
||||
(|| res = get!().split(self))();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn set_split(self, axis: Axis) {
|
||||
get!().set_split(self, axis)
|
||||
}
|
||||
|
||||
pub fn input_devices(self) -> Vec<InputDevice> {
|
||||
let mut res = vec![];
|
||||
(|| res = get!().get_input_devices(Some(self)))();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn create_split(self, axis: Axis) {
|
||||
get!().create_split(self, axis);
|
||||
}
|
||||
|
||||
pub fn focus_parent(self) {
|
||||
get!().focus_parent(self);
|
||||
}
|
||||
|
||||
pub fn toggle_floating(self) {
|
||||
get!().toggle_floating(self);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_seats() -> Vec<Seat> {
|
||||
let mut res = vec![];
|
||||
(|| res = get!().seats())();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn input_devices() -> Vec<InputDevice> {
|
||||
let mut res = vec![];
|
||||
(|| res = get!().get_input_devices(None))();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn remove_all_seats() {}
|
||||
|
||||
pub fn create_seat(name: &str) -> Seat {
|
||||
let mut res = Seat(0);
|
||||
(|| res = get!().create_seat(name))();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn on_new_seat<F: Fn(Seat) + 'static>(f: F) {
|
||||
get!().on_new_seat(f)
|
||||
}
|
||||
|
||||
pub fn on_new_input_device<F: Fn(InputDevice) + 'static>(f: F) {
|
||||
get!().on_new_input_device(f)
|
||||
}
|
||||
|
||||
pub fn quit() {
|
||||
get!().quit()
|
||||
}
|
||||
|
||||
pub struct Command {
|
||||
prog: String,
|
||||
args: Vec<String>,
|
||||
env: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn new(prog: &str) -> Self {
|
||||
Self {
|
||||
prog: prog.to_string(),
|
||||
args: vec![],
|
||||
env: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arg(&mut self, arg: &str) -> &mut Self {
|
||||
self.args.push(arg.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn env(&mut self, key: &str, val: &str) -> &mut Self {
|
||||
self.env.insert(key.to_string(), val.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn spawn(&self) {
|
||||
get!().spawn(self);
|
||||
}
|
||||
}
|
||||
68
jay-config/src/macros.rs
Normal file
68
jay-config/src/macros.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#[macro_export]
|
||||
macro_rules! config {
|
||||
($f:path) => {
|
||||
#[no_mangle]
|
||||
#[used]
|
||||
pub static mut I4_CONFIG_ENTRY: $crate::_private::ConfigEntry = {
|
||||
struct X;
|
||||
impl $crate::_private::Config for X {
|
||||
extern "C" fn configure() {
|
||||
$f();
|
||||
}
|
||||
}
|
||||
$crate::_private::ConfigEntryGen::<X>::ENTRY
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get {
|
||||
() => {{
|
||||
#[allow(unused_unsafe)]
|
||||
let client = unsafe {
|
||||
let client = crate::_private::client::CLIENT.with(|client| client.get());
|
||||
if client.is_null() {
|
||||
return;
|
||||
}
|
||||
&*client
|
||||
};
|
||||
client
|
||||
}};
|
||||
}
|
||||
|
||||
// #[macro_export]
|
||||
// macro_rules! log {
|
||||
// ($lvl:expr, $($arg:tt)+) => ({
|
||||
// $crate::log(
|
||||
// $lvl,
|
||||
// &format!($($args)*),
|
||||
// );
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// #[macro_export]
|
||||
// macro_rules! trace {
|
||||
// ($($arg:tt)+) => {
|
||||
// $crate::log!($crate::LogLevel::Trace, $($arg)+)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[macro_export]
|
||||
// macro_rules! debug {
|
||||
// ($($arg:tt)+) => {
|
||||
// $crate::log!($crate::LogLevel::Debug, $($arg)+)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[macro_export]
|
||||
// macro_rules! info {
|
||||
// ($($arg:tt)+) => {
|
||||
// $crate::log!($crate::LogLevel::Info, $($arg)+)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[macro_export]
|
||||
// macro_rules! info {
|
||||
// ($($arg:tt)+) => {
|
||||
// $crate::log!($crate::LogLevel::Info, $($arg)+)
|
||||
// }
|
||||
// }
|
||||
45
jay-config/src/theme.rs
Normal file
45
jay-config/src/theme.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use bincode::{BorrowDecode, Encode};
|
||||
|
||||
#[derive(Encode, BorrowDecode, Debug)]
|
||||
pub struct Color {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
pub a: u8,
|
||||
}
|
||||
|
||||
pub fn set_title_color(color: Color) {
|
||||
get!().set_title_color(color)
|
||||
}
|
||||
|
||||
pub fn set_title_underline_color(color: Color) {
|
||||
get!().set_title_underline_color(color)
|
||||
}
|
||||
|
||||
pub fn set_border_color(color: Color) {
|
||||
get!().set_border_color(color)
|
||||
}
|
||||
|
||||
pub fn set_background_color(color: Color) {
|
||||
get!().set_background_color(color)
|
||||
}
|
||||
|
||||
pub fn get_title_height() -> i32 {
|
||||
let mut res = 0;
|
||||
(|| res = get!().get_title_height())();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn get_border_width() -> i32 {
|
||||
let mut res = 0;
|
||||
(|| res = get!().get_border_width())();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn set_title_height(height: i32) {
|
||||
get!().set_title_height(height)
|
||||
}
|
||||
|
||||
pub fn set_border_width(width: i32) {
|
||||
get!().set_border_width(width)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue