1
0
Fork 0
forked from wry/wry

autocommit 2022-03-13 22:20:31 CET

This commit is contained in:
Julian Orth 2022-03-13 22:20:31 +01:00
parent 156bd5b042
commit a15a02a95c
38 changed files with 63 additions and 66 deletions

8
jay-config/Cargo.toml Normal file
View 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"

View 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();
}

View 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(_) => {}
}
}
}

View 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 {}

View 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
}
}

View file

@ -0,0 +1,5 @@
use crate::InputDevice;
pub fn grab_input_device(kb: InputDevice, grab: bool) {
get!().grab(kb, grab);
}

View 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
}
}

View 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;
}
}

View 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
}
}

File diff suppressed because it is too large Load diff

196
jay-config/src/lib.rs Normal file
View 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
View 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
View 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)
}