wzrd

An ICCCM & EWMH compliant X11 reparenting, dynamic window manager, written in Rust
git clone git://git.deurzen.net/wzrd
Log | Files | Refs | LICENSE

util.rs (7242B)


      1 use crate::change::Change;
      2 use crate::change::Direction;
      3 use crate::identify::Index;
      4 
      5 use winsys::input::Button;
      6 use winsys::input::Modifier;
      7 
      8 use std::cmp::Ord;
      9 use std::hash::BuildHasher;
     10 use std::hash::Hasher;
     11 use std::ops::Add;
     12 use std::ops::AddAssign;
     13 use std::ops::Mul;
     14 use std::ops::MulAssign;
     15 use std::ops::Sub;
     16 use std::ops::SubAssign;
     17 use std::process::Command;
     18 use std::process::Stdio;
     19 
     20 use x11rb::protocol::xproto::ModMask;
     21 
     22 #[derive(Default)]
     23 pub struct IdHasher {
     24     state: u64,
     25 }
     26 
     27 impl Hasher for IdHasher {
     28     #[inline]
     29     fn write(
     30         &mut self,
     31         bytes: &[u8],
     32     ) {
     33         for &byte in bytes {
     34             self.state = self.state.rotate_left(8) + u64::from(byte);
     35         }
     36     }
     37 
     38     #[inline]
     39     fn finish(&self) -> u64 {
     40         self.state
     41     }
     42 }
     43 
     44 #[derive(Default, Clone)]
     45 pub struct BuildIdHasher;
     46 
     47 impl BuildHasher for BuildIdHasher {
     48     type Hasher = IdHasher;
     49 
     50     #[inline]
     51     fn build_hasher(&self) -> Self::Hasher {
     52         Self::Hasher {
     53             state: 0,
     54         }
     55     }
     56 }
     57 
     58 pub struct Util;
     59 
     60 impl Util {
     61     #[inline]
     62     pub fn last_index(iter: impl ExactSizeIterator) -> Index {
     63         if iter.len() != 0 {
     64             iter.len() - 1
     65         } else {
     66             0
     67         }
     68     }
     69 
     70     #[inline]
     71     pub fn next_index(
     72         iter: impl ExactSizeIterator,
     73         index: Index,
     74         dir: Direction,
     75     ) -> Index {
     76         match dir {
     77             Direction::Forward => (index + 1) % iter.len(),
     78             Direction::Backward => {
     79                 if index == 0 {
     80                     iter.len() - 1
     81                 } else {
     82                     index - 1
     83                 }
     84             },
     85         }
     86     }
     87 
     88     #[inline]
     89     pub fn change_within_range<T>(
     90         min: T,
     91         max: T,
     92         mut base: T,
     93         change: Change<T>,
     94     ) -> T
     95     where
     96         T: Ord
     97             + Add<Output = T>
     98             + AddAssign
     99             + Mul<Output = T>
    100             + MulAssign
    101             + Sub<Output = T>
    102             + SubAssign
    103             + Copy,
    104     {
    105         match change {
    106             Change::Inc(delta) => {
    107                 base += delta;
    108                 if base > max {
    109                     max
    110                 } else {
    111                     base
    112                 }
    113             },
    114             Change::Dec(delta) => {
    115                 if base >= min + delta {
    116                     base - delta
    117                 } else {
    118                     min
    119                 }
    120             },
    121         }
    122     }
    123 
    124     pub fn spawn<S: Into<String>>(cmd: S) {
    125         let cmd = cmd.into();
    126         let args: Vec<&str> = cmd.split_whitespace().collect();
    127 
    128         if args.len() > 1 {
    129             Command::new(args[0])
    130                 .args(&args[1..])
    131                 .stdout(Stdio::null())
    132                 .stderr(Stdio::null())
    133                 .spawn()
    134                 .ok();
    135         } else {
    136             Command::new(args[0])
    137                 .stdout(Stdio::null())
    138                 .stderr(Stdio::null())
    139                 .spawn()
    140                 .ok();
    141         };
    142     }
    143 
    144     pub fn spawn_shell<S: Into<String>>(cmd: S) {
    145         let cmd = cmd.into();
    146 
    147         Command::new("sh")
    148             .arg("-c")
    149             .arg(cmd)
    150             .stdout(Stdio::null())
    151             .stderr(Stdio::null())
    152             .spawn()
    153             .ok();
    154     }
    155 
    156     // pub fn system_keycodes() -> CodeMap {
    157     //     match Command::new("xmodmap").arg("-pke").output() {
    158     //         Err(e) => panic!("unable to fetch keycodes via xmodmap: {}", e),
    159     //         Ok(o) => match String::from_utf8(o.stdout) {
    160     //             Err(e) => panic!("invalid utf8 from xmodmap: {}", e),
    161     //             Ok(s) => s
    162     //                 .lines()
    163     //                 .flat_map(|l| {
    164     //                     let mut words = l.split_whitespace();
    165     //                     let key_code: u8 = words.nth(1).unwrap().parse().unwrap();
    166 
    167     // words.skip(1).map(move |name| (name.into(), key_code))
    168     // })
    169     // .collect::<CodeMap>(),
    170     // },
    171     // }
    172     // }
    173 
    174     // pub fn parse_key_binding(
    175     //     key_binding: impl Into<String>,
    176     //     keycodes: &CodeMap,
    177     // ) -> Option<KeyCode> {
    178     //     let s = key_binding.into();
    179     //     let mut constituents: Vec<&str> = s.split('-').collect();
    180 
    181     // match keycodes.get(constituents.remove(constituents.len() - 1)) {
    182     //     Some(&code) => {
    183     //         let mask = constituents
    184     //             .iter()
    185     //             .map(|&modifier| match modifier {
    186     //                 "A" | "Alt" | "Meta" => u16::from(ModMask::M1),
    187     //                 "M" | "Super" => u16::from(ModMask::M4),
    188     //                 "S" | "Shift" => u16::from(ModMask::SHIFT),
    189     //                 "C" | "Ctrl" | "Control" => u16::from(ModMask::CONTROL),
    190     //                 "1" | "Mod" => u16::from(if cfg!(debug_assertions) {
    191     //                     ModMask::M1
    192     //                 } else {
    193     //                     ModMask::M4
    194     //                 }),
    195     //                 "2" | "Sec" => u16::from(if cfg!(debug_assertions) {
    196     //                     ModMask::M4
    197     //                 } else {
    198     //                     ModMask::M1
    199     //                 }),
    200     //                 _ => panic!("invalid modifier: {}", s),
    201     //             })
    202     //             .fold(0, |acc, modifier| acc | modifier);
    203 
    204     // Some(KeyCode {
    205     //     mask,
    206     //     code,
    207     // })
    208     // },
    209     // None => None,
    210     // }
    211     // }
    212 
    213     // pub fn parse_mouse_binding(mouse_binding: impl Into<String>) -> Option<MouseShortcut> {
    214     //     let s = mouse_binding.into();
    215     //     let mut constituents: Vec<&str> = s.split('-').collect();
    216 
    217     // let button = match constituents.remove(constituents.len() - 1) {
    218     //     "1" | "Left" => Button::Left,
    219     //     "2" | "Middle" => Button::Middle,
    220     //     "3" | "Right" => Button::Right,
    221     //     "4" | "ScrollUp" => Button::ScrollUp,
    222     //     "5" | "ScrollDown" => Button::ScrollDown,
    223     //     "8" | "Backward" => Button::Backward,
    224     //     "9" | "Forward" => Button::Forward,
    225     //     s => panic!("invalid button: {}", s),
    226     // };
    227 
    228     // let mut modifiers = constituents
    229     //     .iter()
    230     //     .map(|&modifier| match modifier {
    231     //         "A" | "Alt" | "Meta" => Modifier::Alt,
    232     //         "AGr" | "AltGr" => Modifier::AltGr,
    233     //         "M" | "Super" => Modifier::Super,
    234     //         "S" | "Shift" => Modifier::Shift,
    235     //         "C" | "Ctrl" | "Control" => Modifier::Ctrl,
    236     //         "N" | "NumLock" => Modifier::NumLock,
    237     //         "L" | "ScrollLock" => Modifier::ScrollLock,
    238     //         "1" | "Mod" => {
    239     //             if cfg!(debug_assertions) {
    240     //                 Modifier::Alt
    241     //             } else {
    242     //                 Modifier::Super
    243     //             }
    244     //         },
    245     //         "2" | "Sec" => {
    246     //             if cfg!(debug_assertions) {
    247     //                 Modifier::Super
    248     //             } else {
    249     //                 Modifier::Alt
    250     //             }
    251     //         },
    252     //         _ => panic!("invalid modifier: {}", s),
    253     //     })
    254     //     .collect::<Vec<Modifier>>();
    255 
    256     // modifiers.sort();
    257 
    258     // Some(MouseShortcut {
    259     //     button,
    260     //     modifiers,
    261     // })
    262     // }
    263 }