#![feature(prelude_import)] #![warn(clippy::pedantic)] #[prelude_import] use std::prelude::rust_2021::*; #[macro_use] extern crate std; use std::fmt::{Debug, Display}; use breadx::{ auto::xproto::{GrabKeyRequest, GrabMode, KeyButMask, ModMask}, keyboard::KeyboardState, prelude::{AsyncDisplay, AsyncDisplayXprotoExt, MapState}, traits::DisplayBase, AsyncDisplayConnection, AsyncDisplayExt, BreadError, ConfigureWindowParameters, Event, EventMask, Window, }; use lazy_static::lazy_static; use tokio::sync::mpsc::unbounded_channel; mod config { #![allow(dead_code, clippy::module_name_repetitions)] use crate::msg_listener::Action; use crate::Result; use breadx::auto::xproto::KeyButMask; use serde::{ de::{Deserializer, Visitor}, Deserialize, }; use std::collections::HashMap; use std::path::PathBuf; pub struct XcrabConfig { border_color: Option, focused_color: Option, border_size: Option, gap_size: Option, outer_gap_size: Option, pub msg: Option, #[allow(clippy::zero_sized_map_values)] #[serde(default)] pub binds: HashMap, } #[automatically_derived] impl ::core::clone::Clone for XcrabConfig { #[inline] fn clone(&self) -> XcrabConfig { XcrabConfig { border_color: ::core::clone::Clone::clone(&self.border_color), focused_color: ::core::clone::Clone::clone(&self.focused_color), border_size: ::core::clone::Clone::clone(&self.border_size), gap_size: ::core::clone::Clone::clone(&self.gap_size), outer_gap_size: ::core::clone::Clone::clone(&self.outer_gap_size), msg: ::core::clone::Clone::clone(&self.msg), binds: ::core::clone::Clone::clone(&self.binds), } } } #[automatically_derived] impl ::core::fmt::Debug for XcrabConfig { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { let names: &'static _ = &[ "border_color", "focused_color", "border_size", "gap_size", "outer_gap_size", "msg", "binds", ]; let values: &[&dyn ::core::fmt::Debug] = &[ &self.border_color, &self.focused_color, &self.border_size, &self.gap_size, &self.outer_gap_size, &self.msg, &&self.binds, ]; ::core::fmt::Formatter::debug_struct_fields_finish( f, "XcrabConfig", names, values, ) } } #[doc(hidden)] #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] const _: () = { #[allow(unused_extern_crates, clippy::useless_attribute)] extern crate serde as _serde; #[automatically_derived] impl<'de> _serde::Deserialize<'de> for XcrabConfig { fn deserialize<__D>( __deserializer: __D, ) -> _serde::__private::Result where __D: _serde::Deserializer<'de>, { #[allow(non_camel_case_types)] enum __Field { __field0, __field1, __field2, __field3, __field4, __field5, __field6, __ignore, } struct __FieldVisitor; impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { type Value = __Field; fn expecting( &self, __formatter: &mut _serde::__private::Formatter, ) -> _serde::__private::fmt::Result { _serde::__private::Formatter::write_str( __formatter, "field identifier", ) } fn visit_u64<__E>( self, __value: u64, ) -> _serde::__private::Result where __E: _serde::de::Error, { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), 1u64 => _serde::__private::Ok(__Field::__field1), 2u64 => _serde::__private::Ok(__Field::__field2), 3u64 => _serde::__private::Ok(__Field::__field3), 4u64 => _serde::__private::Ok(__Field::__field4), 5u64 => _serde::__private::Ok(__Field::__field5), 6u64 => _serde::__private::Ok(__Field::__field6), _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( self, __value: &str, ) -> _serde::__private::Result where __E: _serde::de::Error, { match __value { "border_color" => _serde::__private::Ok(__Field::__field0), "focused_color" => _serde::__private::Ok(__Field::__field1), "border_size" => _serde::__private::Ok(__Field::__field2), "gap_size" => _serde::__private::Ok(__Field::__field3), "outer_gap_size" => _serde::__private::Ok(__Field::__field4), "msg" => _serde::__private::Ok(__Field::__field5), "binds" => _serde::__private::Ok(__Field::__field6), _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_bytes<__E>( self, __value: &[u8], ) -> _serde::__private::Result where __E: _serde::de::Error, { match __value { b"border_color" => _serde::__private::Ok(__Field::__field0), b"focused_color" => _serde::__private::Ok(__Field::__field1), b"border_size" => _serde::__private::Ok(__Field::__field2), b"gap_size" => _serde::__private::Ok(__Field::__field3), b"outer_gap_size" => _serde::__private::Ok(__Field::__field4), b"msg" => _serde::__private::Ok(__Field::__field5), b"binds" => _serde::__private::Ok(__Field::__field6), _ => _serde::__private::Ok(__Field::__ignore), } } } impl<'de> _serde::Deserialize<'de> for __Field { #[inline] fn deserialize<__D>( __deserializer: __D, ) -> _serde::__private::Result where __D: _serde::Deserializer<'de>, { _serde::Deserializer::deserialize_identifier( __deserializer, __FieldVisitor, ) } } struct __Visitor<'de> { marker: _serde::__private::PhantomData, lifetime: _serde::__private::PhantomData<&'de ()>, } impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> { type Value = XcrabConfig; fn expecting( &self, __formatter: &mut _serde::__private::Formatter, ) -> _serde::__private::fmt::Result { _serde::__private::Formatter::write_str( __formatter, "struct XcrabConfig", ) } #[inline] fn visit_seq<__A>( self, mut __seq: __A, ) -> _serde::__private::Result where __A: _serde::de::SeqAccess<'de>, { let __field0 = match match _serde::de::SeqAccess::next_element::< Option, >(&mut __seq) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { _serde::__private::Some(__value) => __value, _serde::__private::None => { return _serde::__private::Err( _serde::de::Error::invalid_length( 0usize, &"struct XcrabConfig with 7 elements", ), ); } }; let __field1 = match match _serde::de::SeqAccess::next_element::< Option, >(&mut __seq) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { _serde::__private::Some(__value) => __value, _serde::__private::None => { return _serde::__private::Err( _serde::de::Error::invalid_length( 1usize, &"struct XcrabConfig with 7 elements", ), ); } }; let __field2 = match match _serde::de::SeqAccess::next_element::< Option, >(&mut __seq) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { _serde::__private::Some(__value) => __value, _serde::__private::None => { return _serde::__private::Err( _serde::de::Error::invalid_length( 2usize, &"struct XcrabConfig with 7 elements", ), ); } }; let __field3 = match match _serde::de::SeqAccess::next_element::< Option, >(&mut __seq) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { _serde::__private::Some(__value) => __value, _serde::__private::None => { return _serde::__private::Err( _serde::de::Error::invalid_length( 3usize, &"struct XcrabConfig with 7 elements", ), ); } }; let __field4 = match match _serde::de::SeqAccess::next_element::< Option, >(&mut __seq) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { _serde::__private::Some(__value) => __value, _serde::__private::None => { return _serde::__private::Err( _serde::de::Error::invalid_length( 4usize, &"struct XcrabConfig with 7 elements", ), ); } }; let __field5 = match match _serde::de::SeqAccess::next_element::< Option, >(&mut __seq) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { _serde::__private::Some(__value) => __value, _serde::__private::None => { return _serde::__private::Err( _serde::de::Error::invalid_length( 5usize, &"struct XcrabConfig with 7 elements", ), ); } }; let __field6 = match match _serde::de::SeqAccess::next_element::< HashMap, >(&mut __seq) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { _serde::__private::Some(__value) => __value, _serde::__private::None => { _serde::__private::Default::default() } }; _serde::__private::Ok(XcrabConfig { border_color: __field0, focused_color: __field1, border_size: __field2, gap_size: __field3, outer_gap_size: __field4, msg: __field5, binds: __field6, }) } #[inline] fn visit_map<__A>( self, mut __map: __A, ) -> _serde::__private::Result where __A: _serde::de::MapAccess<'de>, { let mut __field0: _serde::__private::Option> = _serde::__private::None; let mut __field1: _serde::__private::Option> = _serde::__private::None; let mut __field2: _serde::__private::Option> = _serde::__private::None; let mut __field3: _serde::__private::Option> = _serde::__private::None; let mut __field4: _serde::__private::Option> = _serde::__private::None; let mut __field5: _serde::__private::Option< Option, > = _serde::__private::None; let mut __field6: _serde::__private::Option< HashMap, > = _serde::__private::None; while let _serde::__private::Some(__key) = match _serde::de::MapAccess::next_key::< __Field, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { match __key { __Field::__field0 => { if _serde::__private::Option::is_some(&__field0) { return _serde::__private::Err( <__A::Error as _serde::de::Error>::duplicate_field( "border_color", ), ); } __field0 = _serde::__private::Some( match _serde::de::MapAccess::next_value::< Option, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }, ); } __Field::__field1 => { if _serde::__private::Option::is_some(&__field1) { return _serde::__private::Err( <__A::Error as _serde::de::Error>::duplicate_field( "focused_color", ), ); } __field1 = _serde::__private::Some( match _serde::de::MapAccess::next_value::< Option, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }, ); } __Field::__field2 => { if _serde::__private::Option::is_some(&__field2) { return _serde::__private::Err( <__A::Error as _serde::de::Error>::duplicate_field( "border_size", ), ); } __field2 = _serde::__private::Some( match _serde::de::MapAccess::next_value::< Option, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }, ); } __Field::__field3 => { if _serde::__private::Option::is_some(&__field3) { return _serde::__private::Err( <__A::Error as _serde::de::Error>::duplicate_field( "gap_size", ), ); } __field3 = _serde::__private::Some( match _serde::de::MapAccess::next_value::< Option, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }, ); } __Field::__field4 => { if _serde::__private::Option::is_some(&__field4) { return _serde::__private::Err( <__A::Error as _serde::de::Error>::duplicate_field( "outer_gap_size", ), ); } __field4 = _serde::__private::Some( match _serde::de::MapAccess::next_value::< Option, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }, ); } __Field::__field5 => { if _serde::__private::Option::is_some(&__field5) { return _serde::__private::Err( <__A::Error as _serde::de::Error>::duplicate_field("msg"), ); } __field5 = _serde::__private::Some( match _serde::de::MapAccess::next_value::< Option, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }, ); } __Field::__field6 => { if _serde::__private::Option::is_some(&__field6) { return _serde::__private::Err( <__A::Error as _serde::de::Error>::duplicate_field("binds"), ); } __field6 = _serde::__private::Some( match _serde::de::MapAccess::next_value::< HashMap, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }, ); } _ => { let _ = match _serde::de::MapAccess::next_value::< _serde::de::IgnoredAny, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }; } } } let __field0 = match __field0 { _serde::__private::Some(__field0) => __field0, _serde::__private::None => { match _serde::__private::de::missing_field("border_color") { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } } }; let __field1 = match __field1 { _serde::__private::Some(__field1) => __field1, _serde::__private::None => { match _serde::__private::de::missing_field( "focused_color", ) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } } }; let __field2 = match __field2 { _serde::__private::Some(__field2) => __field2, _serde::__private::None => { match _serde::__private::de::missing_field("border_size") { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } } }; let __field3 = match __field3 { _serde::__private::Some(__field3) => __field3, _serde::__private::None => { match _serde::__private::de::missing_field("gap_size") { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } } }; let __field4 = match __field4 { _serde::__private::Some(__field4) => __field4, _serde::__private::None => { match _serde::__private::de::missing_field( "outer_gap_size", ) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } } }; let __field5 = match __field5 { _serde::__private::Some(__field5) => __field5, _serde::__private::None => { match _serde::__private::de::missing_field("msg") { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } } }; let __field6 = match __field6 { _serde::__private::Some(__field6) => __field6, _serde::__private::None => { _serde::__private::Default::default() } }; _serde::__private::Ok(XcrabConfig { border_color: __field0, focused_color: __field1, border_size: __field2, gap_size: __field3, outer_gap_size: __field4, msg: __field5, binds: __field6, }) } } const FIELDS: &'static [&'static str] = &[ "border_color", "focused_color", "border_size", "gap_size", "outer_gap_size", "msg", "binds", ]; _serde::Deserializer::deserialize_struct( __deserializer, "XcrabConfig", FIELDS, __Visitor { marker: _serde::__private::PhantomData::, lifetime: _serde::__private::PhantomData, }, ) } } }; pub struct XcrabMsgConfig { pub socket_path: PathBuf, } #[automatically_derived] impl ::core::clone::Clone for XcrabMsgConfig { #[inline] fn clone(&self) -> XcrabMsgConfig { XcrabMsgConfig { socket_path: ::core::clone::Clone::clone(&self.socket_path), } } } #[automatically_derived] impl ::core::fmt::Debug for XcrabMsgConfig { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field1_finish( f, "XcrabMsgConfig", "socket_path", &&self.socket_path, ) } } #[doc(hidden)] #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] const _: () = { #[allow(unused_extern_crates, clippy::useless_attribute)] extern crate serde as _serde; #[automatically_derived] impl<'de> _serde::Deserialize<'de> for XcrabMsgConfig { fn deserialize<__D>( __deserializer: __D, ) -> _serde::__private::Result where __D: _serde::Deserializer<'de>, { #[allow(non_camel_case_types)] enum __Field { __field0, __ignore, } struct __FieldVisitor; impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { type Value = __Field; fn expecting( &self, __formatter: &mut _serde::__private::Formatter, ) -> _serde::__private::fmt::Result { _serde::__private::Formatter::write_str( __formatter, "field identifier", ) } fn visit_u64<__E>( self, __value: u64, ) -> _serde::__private::Result where __E: _serde::de::Error, { match __value { 0u64 => _serde::__private::Ok(__Field::__field0), _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_str<__E>( self, __value: &str, ) -> _serde::__private::Result where __E: _serde::de::Error, { match __value { "socket_path" => _serde::__private::Ok(__Field::__field0), _ => _serde::__private::Ok(__Field::__ignore), } } fn visit_bytes<__E>( self, __value: &[u8], ) -> _serde::__private::Result where __E: _serde::de::Error, { match __value { b"socket_path" => _serde::__private::Ok(__Field::__field0), _ => _serde::__private::Ok(__Field::__ignore), } } } impl<'de> _serde::Deserialize<'de> for __Field { #[inline] fn deserialize<__D>( __deserializer: __D, ) -> _serde::__private::Result where __D: _serde::Deserializer<'de>, { _serde::Deserializer::deserialize_identifier( __deserializer, __FieldVisitor, ) } } struct __Visitor<'de> { marker: _serde::__private::PhantomData, lifetime: _serde::__private::PhantomData<&'de ()>, } impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> { type Value = XcrabMsgConfig; fn expecting( &self, __formatter: &mut _serde::__private::Formatter, ) -> _serde::__private::fmt::Result { _serde::__private::Formatter::write_str( __formatter, "struct XcrabMsgConfig", ) } #[inline] fn visit_seq<__A>( self, mut __seq: __A, ) -> _serde::__private::Result where __A: _serde::de::SeqAccess<'de>, { let __field0 = match match _serde::de::SeqAccess::next_element::< PathBuf, >(&mut __seq) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { _serde::__private::Some(__value) => __value, _serde::__private::None => { return _serde::__private::Err( _serde::de::Error::invalid_length( 0usize, &"struct XcrabMsgConfig with 1 element", ), ); } }; _serde::__private::Ok(XcrabMsgConfig { socket_path: __field0, }) } #[inline] fn visit_map<__A>( self, mut __map: __A, ) -> _serde::__private::Result where __A: _serde::de::MapAccess<'de>, { let mut __field0: _serde::__private::Option = _serde::__private::None; while let _serde::__private::Some(__key) = match _serde::de::MapAccess::next_key::< __Field, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } { match __key { __Field::__field0 => { if _serde::__private::Option::is_some(&__field0) { return _serde::__private::Err( <__A::Error as _serde::de::Error>::duplicate_field( "socket_path", ), ); } __field0 = _serde::__private::Some( match _serde::de::MapAccess::next_value::< PathBuf, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }, ); } _ => { let _ = match _serde::de::MapAccess::next_value::< _serde::de::IgnoredAny, >(&mut __map) { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } }; } } } let __field0 = match __field0 { _serde::__private::Some(__field0) => __field0, _serde::__private::None => { match _serde::__private::de::missing_field("socket_path") { _serde::__private::Ok(__val) => __val, _serde::__private::Err(__err) => { return _serde::__private::Err(__err); } } } }; _serde::__private::Ok(XcrabMsgConfig { socket_path: __field0, }) } } const FIELDS: &'static [&'static str] = &["socket_path"]; _serde::Deserializer::deserialize_struct( __deserializer, "XcrabMsgConfig", FIELDS, __Visitor { marker: _serde::__private::PhantomData::, lifetime: _serde::__private::PhantomData, }, ) } } }; const DEFAULT_BORDER_COLOR: u32 = 0xff_00_00; const DEFAULT_FOCUSED_COLOR: u32 = 0x00_00_ff; const DEFAULT_BORDER_SIZE: u16 = 5; const DEFAULT_GAP_SIZE: u16 = 20; impl Default for XcrabConfig { fn default() -> Self { Self { border_color: Some(DEFAULT_BORDER_COLOR), focused_color: Some(DEFAULT_FOCUSED_COLOR), border_size: Some(DEFAULT_BORDER_SIZE), gap_size: Some(DEFAULT_GAP_SIZE), outer_gap_size: None, msg: Some(XcrabMsgConfig::default()), binds: HashMap::new(), } } } impl Default for XcrabMsgConfig { fn default() -> Self { let home_dir = get_home().expect("Error: $HOME variable not set"); Self { socket_path: { let res = ::alloc::fmt::format( format_args!("{0}/.config/xcrab/msg.sock", home_dir), ); res } .into(), } } } impl XcrabConfig { pub fn border_color(&self) -> u32 { self.border_color.unwrap_or(DEFAULT_BORDER_COLOR) } pub fn focused_color(&self) -> u32 { self.focused_color.unwrap_or(DEFAULT_FOCUSED_COLOR) } pub fn border_size(&self) -> u16 { self.border_size.unwrap_or(DEFAULT_BORDER_SIZE) } pub fn gap_size(&self) -> u16 { self.gap_size.unwrap_or(DEFAULT_GAP_SIZE) } pub fn outer_gap_size(&self) -> u16 { self.outer_gap_size.unwrap_or_else(|| self.gap_size()) } } pub fn load_file() -> Result { let home_dir = get_home()?; let contents = std::fs::read_to_string({ let res = ::alloc::fmt::format( format_args!("{0}/.config/xcrab/config.toml", home_dir), ); res })?; let config: XcrabConfig = toml::from_str(&contents)?; Ok(config) } fn get_home() -> Result { Ok(std::env::var("HOME")?) } struct ActionVisitor; impl<'de> Visitor<'de> for ActionVisitor { type Value = Action; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("a valid WM action") } fn visit_str( self, value: &str, ) -> std::result::Result { value.parse().map_err(|s| E::custom(s)) } } impl<'de> Deserialize<'de> for Action { fn deserialize>( deserializer: D, ) -> std::result::Result { deserializer.deserialize_str(ActionVisitor) } } pub struct Keybind { pub key: char, pub mods: KeyButMask, } #[automatically_derived] impl ::core::clone::Clone for Keybind { #[inline] fn clone(&self) -> Keybind { let _: ::core::clone::AssertParamIsClone; let _: ::core::clone::AssertParamIsClone; *self } } #[automatically_derived] impl ::core::marker::Copy for Keybind {} #[automatically_derived] impl ::core::fmt::Debug for Keybind { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field2_finish( f, "Keybind", "key", &self.key, "mods", &&self.mods, ) } } #[automatically_derived] impl ::core::hash::Hash for Keybind { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&self.key, state); ::core::hash::Hash::hash(&self.mods, state) } } #[automatically_derived] impl ::core::marker::StructuralPartialEq for Keybind {} #[automatically_derived] impl ::core::cmp::PartialEq for Keybind { #[inline] fn eq(&self, other: &Keybind) -> bool { self.key == other.key && self.mods == other.mods } } #[automatically_derived] impl ::core::marker::StructuralEq for Keybind {} #[automatically_derived] impl ::core::cmp::Eq for Keybind { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; } } struct KeybindVisitor; impl<'de> Visitor<'de> for KeybindVisitor { type Value = Keybind; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("a keybind in the form of 'M-x'") } fn visit_str( self, value: &str, ) -> std::result::Result { let mut mask = KeyButMask::default(); for part in value.split('-') { if part.len() > 1 { return Err(E::custom("parts may only contain one character")); } let c = part .chars() .next() .ok_or_else(|| E::custom( "parts must contain at least one character", ))?; if c.is_ascii_uppercase() { match c { 'C' => mask.set_control(true), 'S' => mask.set_shift(true), 'A' => mask.set_mod1(true), 'W' => mask.set_mod4(true), _ => { return Err( E::custom({ let res = ::alloc::fmt::format( format_args!("no such modifier: {0}", c), ); res }), ); } }; } } let c = value .split('-') .flat_map(str::chars) .find(char::is_ascii_lowercase) .ok_or_else(|| E::custom("must specify one normal key"))? .to_ascii_uppercase(); Ok(Keybind { key: c, mods: mask }) } } impl<'de> Deserialize<'de> for Keybind { fn deserialize>( deserializer: D, ) -> std::result::Result { deserializer.deserialize_str(KeybindVisitor) } } } mod msg_listener { use crate::x11::client::XcrabWindowManager; use crate::Result; use breadx::AsyncDisplay; use std::path::Path; use std::str::FromStr; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::UnixListener; use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; use crate::XcrabError; pub async fn listener_task>( socket_path: P, sender: UnboundedSender, mut result_recv: UnboundedReceiver>, ) -> Result<()> { let socket_path = socket_path.as_ref(); if socket_path.exists() { std::fs::remove_file(socket_path)?; } let listener = UnixListener::bind(socket_path)?; loop { let (mut stream, _) = match listener.accept().await { Ok(v) => v, Err(_) => continue, }; let mut buf = String::new(); stream.read_to_string(&mut buf).await?; drop(sender.send(buf)); if let Err(e) = result_recv.recv().await.unwrap() { stream .write_all( { let res = ::alloc::fmt::format(format_args!("{0}", e)); res } .as_bytes(), ) .await?; } else { stream.write_all(&[]).await?; } } } pub async fn on_recv( data: String, manager: &mut XcrabWindowManager, conn: &mut Dpy, result_sender: &UnboundedSender>, ) -> Result<()> { let res = { data.parse::() }; if let Ok(ref a) = res { a.eval(manager, conn).await?; } drop(result_sender.send(res.map(|_| ()))); Ok(()) } #[non_exhaustive] pub enum Action { Close, } #[automatically_derived] impl ::core::fmt::Debug for Action { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::write_str(f, "Close") } } #[automatically_derived] impl ::core::clone::Clone for Action { #[inline] fn clone(&self) -> Action { Action::Close } } impl FromStr for Action { type Err = XcrabError; fn from_str(s: &str) -> std::result::Result { #[allow(clippy::enum_glob_use)] use Action::*; let parts: Vec = s .split(' ') .map(str::to_ascii_lowercase) .filter(|s| !s.is_empty()) .collect(); if parts.is_empty() { return Err(XcrabError::Custom(String::from("No action provided"))); } if parts[0].eq_ignore_ascii_case("close") { Ok(Close) } else { Err( XcrabError::Custom({ let res = ::alloc::fmt::format( format_args!("Unknown action: {0}", s), ); res }), ) } } } impl Action { pub async fn eval( &self, manager: &mut XcrabWindowManager, conn: &mut Dpy, ) -> Result<()> { #[allow(clippy::enum_glob_use)] use Action::*; match self { Close => manager.destroy_focused_client(conn).await?, } Ok(()) } } } mod x11 { pub mod client { use breadx::auto::xproto::{KeyButMask, Keycode, Keysym}; use breadx::{ auto::xproto::{ClientMessageEvent, InputFocus, SetInputFocusRequest}, client_message_data::ClientMessageData, prelude::{AsByteSequence, AsyncDisplayXprotoExt, PropertyType, SetMode}, AsyncDisplay, AsyncDisplayExt, Atom, BreadError, ConfigureWindowParameters, ErrorCode, Event, EventMask, KeyboardState, Window, WindowParameters, XidType, }; use slotmap::{new_key_type, SlotMap}; use std::{collections::HashMap, future::Future, pin::Pin, slice}; use crate::{Result, XcrabError, CONFIG}; pub enum Direction { Up, Down, Left, Right, } #[automatically_derived] impl ::core::fmt::Debug for Direction { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::write_str( f, match self { Direction::Up => "Up", Direction::Down => "Down", Direction::Left => "Left", Direction::Right => "Right", }, ) } } #[automatically_derived] impl ::core::clone::Clone for Direction { #[inline] fn clone(&self) -> Direction { *self } } #[automatically_derived] impl ::core::marker::Copy for Direction {} pub enum Directionality { Horizontal, Vertical, } #[automatically_derived] impl ::core::fmt::Debug for Directionality { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::write_str( f, match self { Directionality::Horizontal => "Horizontal", Directionality::Vertical => "Vertical", }, ) } } #[automatically_derived] impl ::core::clone::Clone for Directionality { #[inline] fn clone(&self) -> Directionality { *self } } #[automatically_derived] impl ::core::marker::Copy for Directionality {} #[automatically_derived] impl ::core::marker::StructuralPartialEq for Directionality {} #[automatically_derived] impl ::core::cmp::PartialEq for Directionality { #[inline] fn eq(&self, other: &Directionality) -> bool { let __self_tag = ::core::intrinsics::discriminant_value(self); let __arg1_tag = ::core::intrinsics::discriminant_value(other); __self_tag == __arg1_tag } } #[automatically_derived] impl ::core::marker::StructuralEq for Directionality {} #[automatically_derived] impl ::core::cmp::Eq for Directionality { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () {} } pub struct Dimensions { x: u16, y: u16, width: u16, height: u16, } #[automatically_derived] impl ::core::fmt::Debug for Dimensions { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field4_finish( f, "Dimensions", "x", &self.x, "y", &self.y, "width", &self.width, "height", &&self.height, ) } } #[automatically_derived] impl ::core::clone::Clone for Dimensions { #[inline] fn clone(&self) -> Dimensions { let _: ::core::clone::AssertParamIsClone; *self } } #[automatically_derived] impl ::core::marker::Copy for Dimensions {} #[automatically_derived] impl ::core::default::Default for Dimensions { #[inline] fn default() -> Dimensions { Dimensions { x: ::core::default::Default::default(), y: ::core::default::Default::default(), width: ::core::default::Default::default(), height: ::core::default::Default::default(), } } } impl Dimensions { fn split(self, direction: Directionality, count: usize) -> Vec { let count_u16 = u16::try_from(count).unwrap(); match direction { Directionality::Horizontal => { let amount_for_windows = self.width - CONFIG.gap_size() * (count_u16 - 1); let excess = amount_for_windows % count_u16; let window_size = amount_for_windows / count_u16; let window_stride = window_size + CONFIG.gap_size(); (0..count.try_into().unwrap()) .map(|i| Dimensions { x: self.x + i * window_stride + if i < excess { 1 } else { 0 }, width: window_size, ..self }) .collect() } Directionality::Vertical => { let amount_for_windows = self.height - CONFIG.gap_size() * (count_u16 - 1); let excess = amount_for_windows % count_u16; let window_size = amount_for_windows / count_u16; let window_stride = window_size + CONFIG.gap_size(); (0..count.try_into().unwrap()) .map(|i| Dimensions { y: self.y + i * window_stride + if i < excess { 1 } else { 0 }, height: window_size, ..self }) .collect() } } } } #[repr(transparent)] struct XcrabKey(::slotmap::KeyData); #[automatically_derived] impl ::core::marker::Copy for XcrabKey {} #[automatically_derived] impl ::core::clone::Clone for XcrabKey { #[inline] fn clone(&self) -> XcrabKey { let _: ::core::clone::AssertParamIsClone<::slotmap::KeyData>; *self } } #[automatically_derived] impl ::core::default::Default for XcrabKey { #[inline] fn default() -> XcrabKey { XcrabKey(::core::default::Default::default()) } } #[automatically_derived] impl ::core::marker::StructuralEq for XcrabKey {} #[automatically_derived] impl ::core::cmp::Eq for XcrabKey { #[inline] #[doc(hidden)] #[no_coverage] fn assert_receiver_is_total_eq(&self) -> () { let _: ::core::cmp::AssertParamIsEq<::slotmap::KeyData>; } } #[automatically_derived] impl ::core::marker::StructuralPartialEq for XcrabKey {} #[automatically_derived] impl ::core::cmp::PartialEq for XcrabKey { #[inline] fn eq(&self, other: &XcrabKey) -> bool { self.0 == other.0 } } #[automatically_derived] impl ::core::cmp::Ord for XcrabKey { #[inline] fn cmp(&self, other: &XcrabKey) -> ::core::cmp::Ordering { ::core::cmp::Ord::cmp(&self.0, &other.0) } } #[automatically_derived] impl ::core::cmp::PartialOrd for XcrabKey { #[inline] fn partial_cmp( &self, other: &XcrabKey, ) -> ::core::option::Option<::core::cmp::Ordering> { ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) } } #[automatically_derived] impl ::core::hash::Hash for XcrabKey { fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { ::core::hash::Hash::hash(&self.0, state) } } #[automatically_derived] impl ::core::fmt::Debug for XcrabKey { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_tuple_field1_finish( f, "XcrabKey", &&self.0, ) } } impl From<::slotmap::KeyData> for XcrabKey { fn from(k: ::slotmap::KeyData) -> Self { XcrabKey(k) } } unsafe impl ::slotmap::Key for XcrabKey { fn data(&self) -> ::slotmap::KeyData { self.0 } } pub struct XcrabWindowManager { clients: HashMap, rects: SlotMap, focused: Option, } #[automatically_derived] impl ::core::fmt::Debug for XcrabWindowManager { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field3_finish( f, "XcrabWindowManager", "clients", &self.clients, "rects", &self.rects, "focused", &&self.focused, ) } } #[automatically_derived] impl ::core::clone::Clone for XcrabWindowManager { #[inline] fn clone(&self) -> XcrabWindowManager { XcrabWindowManager { clients: ::core::clone::Clone::clone(&self.clients), rects: ::core::clone::Clone::clone(&self.rects), focused: ::core::clone::Clone::clone(&self.focused), } } } #[automatically_derived] impl ::core::default::Default for XcrabWindowManager { #[inline] fn default() -> XcrabWindowManager { XcrabWindowManager { clients: ::core::default::Default::default(), rects: ::core::default::Default::default(), focused: ::core::default::Default::default(), } } } struct Rectangle { parent: XcrabKey, cached_dimensions: Dimensions, contents: RectangleContents, } #[automatically_derived] impl ::core::fmt::Debug for Rectangle { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field3_finish( f, "Rectangle", "parent", &self.parent, "cached_dimensions", &self.cached_dimensions, "contents", &&self.contents, ) } } #[automatically_derived] impl ::core::clone::Clone for Rectangle { #[inline] fn clone(&self) -> Rectangle { Rectangle { parent: ::core::clone::Clone::clone(&self.parent), cached_dimensions: ::core::clone::Clone::clone( &self.cached_dimensions, ), contents: ::core::clone::Clone::clone(&self.contents), } } } impl Rectangle { fn unwrap_pane(&self) -> &Pane { match &self.contents { RectangleContents::Pane(pane) => pane, RectangleContents::Client(_) => { ::core::panicking::panic( "internal error: entered unreachable code", ) } } } fn unwrap_client(&self) -> &Client { match &self.contents { RectangleContents::Pane(_) => { ::core::panicking::panic( "internal error: entered unreachable code", ) } RectangleContents::Client(client) => client, } } fn unwrap_pane_mut(&mut self) -> &mut Pane { match &mut self.contents { RectangleContents::Pane(pane) => pane, RectangleContents::Client(_) => { ::core::panicking::panic( "internal error: entered unreachable code", ) } } } fn unwrap_client_mut(&mut self) -> &mut Client { match &mut self.contents { RectangleContents::Pane(_) => { ::core::panicking::panic( "internal error: entered unreachable code", ) } RectangleContents::Client(client) => client, } } } enum RectangleContents { Pane(Pane), Client(Client), } #[automatically_derived] impl ::core::fmt::Debug for RectangleContents { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match self { RectangleContents::Pane(__self_0) => { ::core::fmt::Formatter::debug_tuple_field1_finish( f, "Pane", &__self_0, ) } RectangleContents::Client(__self_0) => { ::core::fmt::Formatter::debug_tuple_field1_finish( f, "Client", &__self_0, ) } } } } #[automatically_derived] impl ::core::clone::Clone for RectangleContents { #[inline] fn clone(&self) -> RectangleContents { match self { RectangleContents::Pane(__self_0) => { RectangleContents::Pane(::core::clone::Clone::clone(__self_0)) } RectangleContents::Client(__self_0) => { RectangleContents::Client(::core::clone::Clone::clone(__self_0)) } } } } struct Pane { children: Vec, directionality: Directionality, } #[automatically_derived] impl ::core::fmt::Debug for Pane { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field2_finish( f, "Pane", "children", &self.children, "directionality", &&self.directionality, ) } } #[automatically_derived] impl ::core::clone::Clone for Pane { #[inline] fn clone(&self) -> Pane { Pane { children: ::core::clone::Clone::clone(&self.children), directionality: ::core::clone::Clone::clone(&self.directionality), } } } struct Client { frame: FramedWindow, } #[automatically_derived] impl ::core::fmt::Debug for Client { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field1_finish( f, "Client", "frame", &&self.frame, ) } } #[automatically_derived] impl ::core::clone::Clone for Client { #[inline] fn clone(&self) -> Client { let _: ::core::clone::AssertParamIsClone; *self } } #[automatically_derived] impl ::core::marker::Copy for Client {} impl XcrabWindowManager { pub fn new() -> Self { XcrabWindowManager::default() } /// Given the `rect_key` from a `parent -> rect` relationship, makes A /// `parent -> new_pane -> rect` relationship, then returns `new_pane_key` fn insert_pane_above( &mut self, rect_key: XcrabKey, directionality: Directionality, ) -> Option { let rect = self.rects.get(rect_key)?; let rect_dimensions = rect.cached_dimensions; let parent_key = rect.parent; let new_pane = Rectangle { parent: parent_key, cached_dimensions: rect_dimensions, contents: RectangleContents::Pane(Pane { children: <[_]>::into_vec( #[rustc_box] ::alloc::boxed::Box::new([rect_key]), ), directionality, }), }; let new_pane_key = if parent_key == rect_key { self.rects .insert_with_key(|key| Rectangle { parent: key, ..new_pane }) } else { let new_pane_key = self.rects.insert(new_pane); let parent_pane = self .rects .get_mut(parent_key) .unwrap() .unwrap_pane_mut(); let index = parent_pane .children .iter() .copied() .position(|v| v == rect_key) .unwrap(); parent_pane.children[index] = new_pane_key; new_pane_key }; let rect = self.rects.get_mut(rect_key).unwrap(); rect.parent = new_pane_key; Some(new_pane_key) } async fn focus_update_map( &mut self, conn: &mut Dpy, frame: FramedWindow, parent_key: XcrabKey, ) -> Result<()> { let win = frame.win; self.focused = Some(win); self.update_rectangle(conn, parent_key, None).await?; frame.map(conn).await?; self.update_focused(conn).await?; Ok(()) } /// Tells x about the currently focused window. pub async fn update_focused( &mut self, conn: &mut Dpy, ) -> Result<()> { let mut req = SetInputFocusRequest { req_type: 42, revert_to: InputFocus::None, length: 3, focus: Window::from_xid(0), time: 0, }; if let Some(focus) = self.focused { req.focus = focus; } conn.exchange_request_async(req).await?; Ok(()) } /// Adds a new client. pub async fn add_client( &mut self, conn: &mut Dpy, win: Window, ) -> Result<()> { self.add_client_direction(conn, win, Direction::Right).await } /// Adds a new client in the given direction from the focused window. pub async fn add_client_direction( &mut self, conn: &mut Dpy, win: Window, direction: Direction, ) -> Result<()> { #[allow(clippy::enum_glob_use)] use {Direction::*, Directionality::*}; let focused = match self.focused { Some(v) => v, None => return self.add_first_client(conn, win).await, }; let frame = frame(conn, win).await?; let focused_client_key = *self .clients .get(&focused) .ok_or(XcrabError::ClientDoesntExist)?; let target_directionality = match direction { Up | Down => Vertical, Left | Right => Horizontal, }; let mut child_key = focused_client_key; let parent_key = loop { let parent_key = self.rects.get(child_key).unwrap().parent; if parent_key == child_key { break self .insert_pane_above(child_key, target_directionality) .unwrap(); } let parent = self.rects.get(parent_key).unwrap(); if parent.unwrap_pane().directionality == target_directionality { break parent_key; } child_key = parent_key; }; let new_rect_key = self .rects .insert(Rectangle { parent: parent_key, cached_dimensions: Dimensions::default(), contents: RectangleContents::Client(Client { frame }), }); let parent_pane = self .rects .get_mut(parent_key) .unwrap() .unwrap_pane_mut(); let mut index = parent_pane .children .iter() .copied() .position(|v| v == child_key) .unwrap(); if let Down | Right = direction { index += 1; } parent_pane.children.insert(index, new_rect_key); self.clients.insert(win, new_rect_key); self.focus_update_map(conn, frame, parent_key).await?; Ok(()) } /// Adds a new client in the given direction directly adjacent to the focused window, creating a new pane if needed. pub async fn add_client_direction_immediate( &mut self, conn: &mut Dpy, win: Window, direction: Direction, ) -> Result<()> { #[allow(clippy::enum_glob_use)] use {Direction::*, Directionality::*}; let focused = match self.focused { Some(v) => v, None => return self.add_first_client(conn, win).await, }; let frame = frame(conn, win).await?; let focused_client_key = *self.clients.get(&focused).unwrap(); let focused_client = self.rects.get(focused_client_key).unwrap(); let mut parent_key = focused_client.parent; let parent_pane_dir = match &self.rects.get(parent_key).unwrap().contents { RectangleContents::Pane(pane) => Some(pane.directionality), RectangleContents::Client(_) => None, }; let target_directionality = match direction { Up | Down => Vertical, Left | Right => Horizontal, }; if parent_pane_dir.is_none() || parent_pane_dir.unwrap() != target_directionality { parent_key = self .insert_pane_above(focused_client_key, target_directionality) .unwrap(); } let new_rect_key = self .rects .insert(Rectangle { parent: parent_key, cached_dimensions: Dimensions::default(), contents: RectangleContents::Client(Client { frame }), }); let parent_pane = self .rects .get_mut(parent_key) .unwrap() .unwrap_pane_mut(); let mut index = parent_pane .children .iter() .copied() .position(|v| v == focused_client_key) .unwrap(); if let Down | Right = direction { index += 1; } parent_pane.children.insert(index, new_rect_key); self.clients.insert(win, new_rect_key); self.focus_update_map(conn, frame, parent_key).await?; Ok(()) } async fn add_first_client( &mut self, conn: &mut Dpy, win: Window, ) -> Result<()> { let frame = frame(conn, win).await?; let root_geo = conn.default_root().geometry_immediate_async(conn).await?; let outer_gap_size = CONFIG.outer_gap_size(); let key = self .rects .insert_with_key(|key| Rectangle { parent: key, cached_dimensions: Dimensions { x: u16::try_from(root_geo.x).unwrap() + outer_gap_size, y: u16::try_from(root_geo.y).unwrap() + outer_gap_size, width: root_geo.width - 2 * outer_gap_size, height: root_geo.height - 2 * outer_gap_size, }, contents: RectangleContents::Client(Client { frame }), }); self.clients.insert(win, key); self.focus_update_map(conn, frame, key).await?; Ok(()) } #[must_use] fn update_rectangle<'a, Dpy: AsyncDisplay + ?Sized>( &'a mut self, conn: &'a mut Dpy, key: XcrabKey, dimensions: Option, ) -> Pin> + 'a>> { Box::pin(async move { let rect = self .rects .get_mut(key) .ok_or(XcrabError::ClientDoesntExist)?; let dimensions = dimensions.unwrap_or(rect.cached_dimensions); rect.cached_dimensions = dimensions; match &mut rect.contents { RectangleContents::Pane(pane) => { if !pane.children.is_empty() { let new_dimensions = dimensions .split(pane.directionality, pane.children.len()); for (key, dimensions) in pane .children .clone() .into_iter() .zip(new_dimensions.into_iter()) { self.update_rectangle(conn, key, Some(dimensions)).await?; } } } RectangleContents::Client(client) => { client .frame .configure( conn, ConfigureWindowParameters { x: Some(dimensions.x.into()), y: Some(dimensions.y.into()), width: Some(dimensions.width.into()), height: Some(dimensions.height.into()), ..Default::default() }, self.focused.unwrap(), ) .await?; } } Ok(()) }) } pub fn has_client(&self, win: Window) -> bool { self.clients.contains_key(&win) } pub async fn remove_client( &mut self, conn: &mut Dpy, win: Window, ) -> Result<()> { let client_key = *self .clients .get(&win) .ok_or(XcrabError::ClientDoesntExist)?; let client = self.rects.get(client_key).unwrap(); client.unwrap_client().frame.unframe(conn).await?; let parent_key = client.parent; let parent = self.rects.get_mut(parent_key).unwrap(); parent.unwrap_pane_mut().children.retain(|&v| v != client_key); self.clients.remove(&win); self.rects.remove(client_key); if self.focused.unwrap() == win { self.focused = self.clients.keys().copied().next(); self.update_focused(conn).await?; } self.update_rectangle(conn, parent_key, None).await?; Ok(()) } pub async fn destroy_focused_client( &mut self, conn: &mut Dpy, ) -> Result<()> { if let Some(focused) = self.focused { let client_key = *self .clients .get(&focused) .ok_or(XcrabError::ClientDoesntExist)?; let frame = self .rects .get(client_key) .unwrap() .unwrap_client() .frame; self.remove_client(conn, focused).await?; frame.kill_client(conn).await?; Ok(()) } else { Ok(()) } } pub async fn set_focus( &mut self, conn: &mut Dpy, win: Window, ) -> Result<()> { let client_key = *self .clients .get(&win) .ok_or(XcrabError::ClientDoesntExist)?; self.focused = Some(win); self.update_focused(conn).await?; self.update_rectangle( conn, self.rects.get(client_key).unwrap().parent, None, ) .await?; Ok(()) } pub async fn get_focused(&self) -> Option { self.focused } pub async fn get_framed_window(&self, window: Window) -> FramedWindow { let focused_key = self.clients.get(&window).unwrap(); let focused = self.rects.get(*focused_key).unwrap(); let focused_frame = focused.unwrap_client().frame; focused_frame } } pub fn may_not_exist(res: breadx::Result) -> breadx::Result { match res { Err(BreadError::XProtocol { error_code: ErrorCode(3), .. }) => Ok(()), v => v, } } pub struct FramedWindow { pub frame: Window, pub win: Window, } #[automatically_derived] impl ::core::fmt::Debug for FramedWindow { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { ::core::fmt::Formatter::debug_struct_field2_finish( f, "FramedWindow", "frame", &self.frame, "win", &&self.win, ) } } #[automatically_derived] impl ::core::clone::Clone for FramedWindow { #[inline] fn clone(&self) -> FramedWindow { let _: ::core::clone::AssertParamIsClone; *self } } #[automatically_derived] impl ::core::marker::Copy for FramedWindow {} impl FramedWindow { async fn configure( self, conn: &mut Dpy, props: ConfigureWindowParameters, focused_win: Window, ) -> Result<()> { let inset = 2 * u32::from(CONFIG.border_size()); let width = props.width.map(|v| v - inset); let height = props.height.map(|v| v - inset); let focused = focused_win == self.win; self.frame .change_attributes_async( conn, WindowParameters { border_pixel: Some( if focused { CONFIG.focused_color() } else { CONFIG.border_color() }, ), ..Default::default() }, ) .await?; self.frame .configure_async( conn, ConfigureWindowParameters { x: props.x, y: props.y, width, height, border_width: Some(CONFIG.border_size().into()), ..Default::default() }, ) .await?; may_not_exist( self .win .configure_async( conn, ConfigureWindowParameters { x: Some(-1), y: Some(-1), width, height, ..Default::default() }, ) .await, )?; Ok(()) } async fn map( self, conn: &mut Dpy, ) -> Result<()> { may_not_exist(self.win.map_async(conn).await)?; self.frame.map_async(conn).await?; Ok(()) } async fn unframe( self, conn: &mut Dpy, ) -> Result<()> { let root = conn.default_root(); self.frame.unmap_async(conn).await?; may_not_exist(self.win.unmap_async(conn).await)?; may_not_exist(self.win.reparent_async(conn, root, 0, 0).await)?; may_not_exist( self.win.change_save_set_async(conn, SetMode::Delete).await, )?; self.frame.free_async(conn).await?; Ok(()) } async fn kill_client( self, conn: &mut Dpy, ) -> Result<()> { struct ListOfAtom(Vec); impl AsByteSequence for ListOfAtom { fn size(&self) -> usize { ::core::panicking::panic("not implemented") } fn as_bytes(&self, _: &mut [u8]) -> usize { ::core::panicking::panic("not implemented") } fn from_bytes(mut bytes: &[u8]) -> Option<(Self, usize)> { let mut index = 0; let mut vec = Vec::new(); while let Some((atom, index2)) = Atom::from_bytes(bytes) { vec.push(atom); index += index2; bytes = &bytes[index2..]; } Some((Self(vec), index)) } } fn as_u8_slice(data: &[u32]) -> &[u8] { unsafe { slice::from_raw_parts( data.as_ptr().cast::(), data.len().checked_mul(4).unwrap(), ) } } let wm_protocols = conn .intern_atom_immediate_async("WM_PROTOCOLS", true) .await?; if !(wm_protocols.xid != 0) { ::core::panicking::panic("assertion failed: wm_protocols.xid != 0") } let wm_delete_window = conn .intern_atom_immediate_async("WM_DELETE_WINDOW", true) .await?; if !(wm_delete_window.xid != 0) { ::core::panicking::panic( "assertion failed: wm_delete_window.xid != 0", ) } let prop = self .win .get_property_immediate_async::< _, ListOfAtom, >(conn, wm_protocols, PropertyType::Atom, false) .await?; let protocols = prop.unwrap().0; if protocols.contains(&wm_delete_window) { let data = [wm_delete_window.xid, 0, 0, 0, 0]; let data_bytes = as_u8_slice(&data); conn.send_event_async( self.win, EventMask::default(), Event::ClientMessage(ClientMessageEvent { event_type: 33, format: 32, sequence: 0, window: self.win, ty: wm_protocols, data: ClientMessageData::from_bytes(data_bytes).unwrap().0, }), ) .await?; } else { self.win.free_async(conn).await?; } Ok(()) } } async fn frame( conn: &mut Dpy, win: Window, ) -> Result { let root = conn.default_root(); let geometry = win.geometry_immediate_async(conn).await?; let frame = conn .create_simple_window_async( root, geometry.x, geometry.y, geometry.width, geometry.height, CONFIG.border_size(), CONFIG.border_color(), 0x00_00_00, ) .await?; frame .set_event_mask_async( conn, EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY, ) .await?; win.set_event_mask_async(conn, EventMask::BUTTON_PRESS).await?; may_not_exist(win.change_save_set_async(conn, SetMode::Insert).await)?; may_not_exist(win.reparent_async(conn, frame, 0, 0).await)?; Ok(FramedWindow { frame, win }) } pub fn keymap(state: &mut KeyboardState) -> HashMap { let mut map: HashMap = HashMap::new(); for keycode in 8..255_u8 { let key = state.process_keycode(keycode, KeyButMask::default()); let keysyms = state.lookup_keysyms(keycode); if key != None { for keysym in keysyms { map.insert(*keysym, keycode); } } } map } } } use x11::client::{may_not_exist, XcrabWindowManager}; #[non_exhaustive] pub enum XcrabError { #[error("breadx error: {0}")] Bread(#[from] BreadError), #[error("io error: {0}")] Io(#[from] std::io::Error), #[error("toml error: {0}")] Toml(#[from] toml::de::Error), #[error("env var error: {0}")] Var(#[from] std::env::VarError), #[error("client doesnt exist")] ClientDoesntExist, #[error("{0}")] Custom(String), } #[allow(unused_qualifications)] impl std::error::Error for XcrabError { fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> { use thiserror::__private::AsDynError; #[allow(deprecated)] match self { XcrabError::Bread { 0: source, .. } => { std::option::Option::Some(source.as_dyn_error()) } XcrabError::Io { 0: source, .. } => { std::option::Option::Some(source.as_dyn_error()) } XcrabError::Toml { 0: source, .. } => { std::option::Option::Some(source.as_dyn_error()) } XcrabError::Var { 0: source, .. } => { std::option::Option::Some(source.as_dyn_error()) } XcrabError::ClientDoesntExist { .. } => std::option::Option::None, XcrabError::Custom { .. } => std::option::Option::None, } } } #[allow(unused_qualifications)] impl std::fmt::Display for XcrabError { fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result { #[allow(unused_imports)] use thiserror::__private::{DisplayAsDisplay, PathAsDisplay}; #[allow(unused_variables, deprecated, clippy::used_underscore_binding)] match self { XcrabError::Bread(_0) => { __formatter.write_fmt(format_args!("breadx error: {0}", _0.as_display())) } XcrabError::Io(_0) => { __formatter.write_fmt(format_args!("io error: {0}", _0.as_display())) } XcrabError::Toml(_0) => { __formatter.write_fmt(format_args!("toml error: {0}", _0.as_display())) } XcrabError::Var(_0) => { __formatter .write_fmt(format_args!("env var error: {0}", _0.as_display())) } XcrabError::ClientDoesntExist {} => { __formatter.write_fmt(format_args!("client doesnt exist")) } XcrabError::Custom(_0) => { __formatter.write_fmt(format_args!("{0}", _0.as_display())) } } } } #[allow(unused_qualifications)] impl std::convert::From for XcrabError { #[allow(deprecated)] fn from(source: BreadError) -> Self { XcrabError::Bread { 0: source } } } #[allow(unused_qualifications)] impl std::convert::From for XcrabError { #[allow(deprecated)] fn from(source: std::io::Error) -> Self { XcrabError::Io { 0: source } } } #[allow(unused_qualifications)] impl std::convert::From for XcrabError { #[allow(deprecated)] fn from(source: toml::de::Error) -> Self { XcrabError::Toml { 0: source } } } #[allow(unused_qualifications)] impl std::convert::From for XcrabError { #[allow(deprecated)] fn from(source: std::env::VarError) -> Self { XcrabError::Var { 0: source } } } #[allow(missing_copy_implementations)] #[allow(non_camel_case_types)] #[allow(dead_code)] pub struct CONFIG { __private_field: (), } #[doc(hidden)] pub static CONFIG: CONFIG = CONFIG { __private_field: () }; impl ::lazy_static::__Deref for CONFIG { type Target = config::XcrabConfig; fn deref(&self) -> &config::XcrabConfig { #[inline(always)] fn __static_ref_initialize() -> config::XcrabConfig { config::load_file() .unwrap_or_else(|e| { { ::std::io::_print( format_args!("[CONFIG] Error parsing config: {0}\n", e), ); }; { ::std::io::_print( format_args!("[CONFIG] Falling back to default config\n"), ); }; config::XcrabConfig::default() }) } #[inline(always)] fn __stability() -> &'static config::XcrabConfig { static LAZY: ::lazy_static::lazy::Lazy = ::lazy_static::lazy::Lazy::INIT; LAZY.get(__static_ref_initialize) } __stability() } } impl ::lazy_static::LazyStatic for CONFIG { fn initialize(lazy: &Self) { let _ = &**lazy; } } impl Debug for XcrabError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Display::fmt(self, f) } } type Result = std::result::Result; fn main() -> Result<()> { let body = async { let mut conn = AsyncDisplayConnection::create_async(None, None).await?; let root = conn.default_root(); root.set_event_mask_async( &mut conn, EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY | EventMask::KEY_PRESS, ) .await?; let mut manager = XcrabWindowManager::new(); conn.grab_server_async().await?; let top_level_windows = root .query_tree_immediate_async(&mut conn) .await? .children; for &win in top_level_windows.iter() { let attrs = win.window_attributes_immediate_async(&mut conn).await?; if !attrs.override_redirect && attrs.map_state == MapState::Viewable { manager.add_client(&mut conn, win).await?; } } conn.ungrab_server_async().await?; let mut mask = ModMask::new( false, false, true, false, false, false, false, false, false, ); let mut keyboard_state = KeyboardState::new_async(&mut conn).await?; let keymap = x11::client::keymap(&mut keyboard_state); let mut request_key = *keymap .get(&120) .ok_or_else(|| { XcrabError::Custom( "At least one letter could not be found in the keymap".to_string(), ) })?; for &binds in CONFIG.binds.keys() { for keysym in 97..122_u32 { let keycode = keymap .get(&keysym) .ok_or_else(|| { XcrabError::Custom( "At least one letter could not be found in the keymap" .to_string(), ) })?; let iter_char = keyboard_state .process_keycode(*keycode, KeyButMask::default()) .ok_or_else(|| { XcrabError::Custom( "The keycode returned from the keymap could not be processed" .to_string(), ) })? .as_char() .ok_or_else(|| { XcrabError::Custom( "The processed Key could not be cast as a char".to_string(), ) })?; if iter_char == binds.key { request_key = *keycode; mask.inner = binds.mods.inner; } } } mask.set_Two(true); conn.exchange_request_async(GrabKeyRequest { req_type: 33, owner_events: false, length: 4, grab_window: root, modifiers: mask, key: request_key, pointer_mode: GrabMode::Async, keyboard_mode: GrabMode::Async, }) .await?; mask.set_Two(false); conn.exchange_request_async(GrabKeyRequest { req_type: 33, owner_events: false, length: 4, grab_window: root, modifiers: mask, key: request_key, pointer_mode: GrabMode::Async, keyboard_mode: GrabMode::Async, }) .await?; let (send, mut recv) = unbounded_channel(); let (result_send, result_recv) = unbounded_channel(); tokio::spawn( msg_listener::listener_task( CONFIG.msg.clone().unwrap_or_default().socket_path, send, result_recv, ), ); loop { { #[doc(hidden)] mod __tokio_select_util { pub(super) enum Out<_0, _1> { _0(_0), _1(_1), Disabled, } pub(super) type Mask = u8; } use ::tokio::macros::support::Future; use ::tokio::macros::support::Pin; use ::tokio::macros::support::Poll::{Ready, Pending}; const BRANCHES: u32 = 2; let mut disabled: __tokio_select_util::Mask = Default::default(); if !true { let mask: __tokio_select_util::Mask = 1 << 0; disabled |= mask; } if !true { let mask: __tokio_select_util::Mask = 1 << 1; disabled |= mask; } let mut output = { let mut futures = (recv.recv(), conn.wait_for_event_async()); ::tokio::macros::support::poll_fn(|cx| { let mut is_pending = false; let start = 0; for i in 0..BRANCHES { let branch; #[allow(clippy::modulo_one)] { branch = (start + i) % BRANCHES; } match branch { #[allow(unreachable_code)] 0 => { let mask = 1 << branch; if disabled & mask == mask { continue; } let (fut, ..) = &mut futures; let mut fut = unsafe { Pin::new_unchecked(fut) }; let out = match Future::poll(fut, cx) { Ready(out) => out, Pending => { is_pending = true; continue; } }; disabled |= mask; #[allow(unused_variables)] #[allow(unused_mut)] match &out { Some(s) => {} _ => continue, } return Ready(__tokio_select_util::Out::_0(out)); } #[allow(unreachable_code)] 1 => { let mask = 1 << branch; if disabled & mask == mask { continue; } let (_, fut, ..) = &mut futures; let mut fut = unsafe { Pin::new_unchecked(fut) }; let out = match Future::poll(fut, cx) { Ready(out) => out, Pending => { is_pending = true; continue; } }; disabled |= mask; #[allow(unused_variables)] #[allow(unused_mut)] match &out { Ok(ev) => {} _ => continue, } return Ready(__tokio_select_util::Out::_1(out)); } _ => { ::core::panicking::unreachable_display( &"reaching this means there probably is an off by one bug", ) } } } if is_pending { Pending } else { Ready(__tokio_select_util::Out::Disabled) } }) .await }; match output { __tokio_select_util::Out::_0(Some(s)) => { msg_listener::on_recv(s, &mut manager, &mut conn, &result_send) .await? } __tokio_select_util::Out::_1(Ok(ev)) => { process_event( ev, &mut manager, &mut conn, root, &mut keyboard_state, ) .await? } __tokio_select_util::Out::Disabled => { ::std::rt::begin_panic( "all branches are disabled and there is no else branch", ) } _ => ::core::panicking::unreachable_display(&"failed to match bind"), } } } }; #[allow(clippy::expect_used, clippy::diverging_sub_expression)] { return tokio::runtime::Builder::new_multi_thread() .enable_all() .build() .expect("Failed building the Runtime") .block_on(body); } } #[allow(clippy::too_many_lines)] async fn process_event( ev: Event, manager: &mut XcrabWindowManager, conn: &mut Dpy, root: Window, keyboard_state: &mut KeyboardState, ) -> Result<()> { match ev { Event::MapRequest(ev) => { manager.add_client(conn, ev.window).await?; } Event::ConfigureRequest(ev) => { let mut params = ConfigureWindowParameters { x: Some(ev.x.into()), y: Some(ev.y.into()), width: Some(ev.width.into()), height: Some(ev.height.into()), border_width: Some(ev.border_width.into()), sibling: None, stack_mode: Some(ev.stack_mode), }; if manager.has_client(ev.window) { params.x = None; params.y = None; params.width = None; params.height = None; } may_not_exist(ev.window.configure_async(conn, params).await)?; } Event::UnmapNotify(ev) => { if ev.event != root && manager.has_client(ev.window) { manager.remove_client(conn, ev.window).await?; } } Event::ButtonPress(ev) => { if ev.detail == 1 { manager.set_focus(conn, ev.event).await?; } } Event::KeyPress(ev) => { if let Some(k) = keyboard_state.process_keycode(ev.detail, ev.state) { if let Some(c) = k.as_char() { for (&bind, action) in &CONFIG.binds { if bind.key == c { action.eval(manager, conn).await?; } } } } } _ => {} } Ok(()) }