hopefully Client-Logic that actually works now
This commit is contained in:
parent
5608f1d9da
commit
08a0c6b089
|
@ -10,5 +10,5 @@ edition = "2018"
|
||||||
nix = "0.19.1"
|
nix = "0.19.1"
|
||||||
x11 = {version = "2.18.2", features = ["xlib"] }
|
x11 = {version = "2.18.2", features = ["xlib"] }
|
||||||
log = "0.4.13"
|
log = "0.4.13"
|
||||||
weak-table = {path = "/mnt/storage/rust/weak-table-rs"}
|
weak-table = "0.3.0"
|
||||||
simple_logger = "1.11.0"
|
simple_logger = "1.11.0"
|
463
src/clients.rs
463
src/clients.rs
|
@ -1,15 +1,9 @@
|
||||||
use std::{
|
use std::{borrow::Borrow, cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
borrow::{Borrow, BorrowMut},
|
|
||||||
collections::HashSet,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
use std::{
|
use std::{
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
rc::Weak,
|
rc::Weak,
|
||||||
};
|
};
|
||||||
|
|
||||||
use weak_table::WeakHashSet;
|
|
||||||
use x11::xlib::Window;
|
use x11::xlib::Window;
|
||||||
|
|
||||||
use crate::util::BuildIdentityHasher;
|
use crate::util::BuildIdentityHasher;
|
||||||
|
@ -36,6 +30,12 @@ impl PartialEq for Client {
|
||||||
|
|
||||||
impl Eq for Client {}
|
impl Eq for Client {}
|
||||||
|
|
||||||
|
impl Borrow<Window> for Client {
|
||||||
|
fn borrow(&self) -> &Window {
|
||||||
|
&self.window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trait ClientKey {
|
trait ClientKey {
|
||||||
fn key(&self) -> u64;
|
fn key(&self) -> u64;
|
||||||
}
|
}
|
||||||
|
@ -84,135 +84,348 @@ impl<'a> Borrow<dyn ClientKey + 'a> for Rc<Client> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ClientList {
|
|
||||||
fn contains_key<T>(&self, key: &T) -> bool
|
|
||||||
where
|
|
||||||
T: ClientKey;
|
|
||||||
|
|
||||||
fn get_with_key<T>(&self, key: &T) -> Option<Rc<Client>>
|
|
||||||
where
|
|
||||||
T: ClientKey;
|
|
||||||
|
|
||||||
fn remove_key<T>(&mut self, key: &T) -> bool
|
|
||||||
where
|
|
||||||
T: ClientKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Clients(HashSet<Rc<Client>, BuildIdentityHasher>);
|
|
||||||
|
|
||||||
impl Default for Clients {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Clients {
|
|
||||||
type Target = HashSet<Rc<Client>, BuildIdentityHasher>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for Clients {
|
|
||||||
fn deref_mut(&mut self) -> &mut HashSet<Rc<Client>, BuildIdentityHasher> {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientList for Clients {
|
|
||||||
fn contains_key<T>(&self, key: &T) -> bool
|
|
||||||
where
|
|
||||||
T: ClientKey,
|
|
||||||
{
|
|
||||||
self.0.contains(key as &dyn ClientKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_with_key<T>(&self, key: &T) -> Option<Rc<Client>>
|
|
||||||
where
|
|
||||||
T: ClientKey,
|
|
||||||
{
|
|
||||||
self.0.get(key as &dyn ClientKey).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_key<T>(&mut self, key: &T) -> bool
|
|
||||||
where
|
|
||||||
T: ClientKey,
|
|
||||||
{
|
|
||||||
self.0.remove(key as &dyn ClientKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ClientRefs(WeakHashSet<Weak<Client>, BuildIdentityHasher>);
|
|
||||||
|
|
||||||
impl Default for ClientRefs {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for ClientRefs {
|
|
||||||
type Target = WeakHashSet<Weak<Client>, BuildIdentityHasher>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for ClientRefs {
|
|
||||||
fn deref_mut(&mut self) -> &mut WeakHashSet<Weak<Client>, BuildIdentityHasher> {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientList for ClientRefs {
|
|
||||||
fn contains_key<T>(&self, key: &T) -> bool
|
|
||||||
where
|
|
||||||
T: ClientKey,
|
|
||||||
{
|
|
||||||
self.0.contains(key as &dyn ClientKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_with_key<T>(&self, key: &T) -> Option<Rc<Client>>
|
|
||||||
where
|
|
||||||
T: ClientKey,
|
|
||||||
{
|
|
||||||
self.0.get(key as &dyn ClientKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_key<T>(&mut self, key: &T) -> bool
|
|
||||||
where
|
|
||||||
T: ClientKey,
|
|
||||||
{
|
|
||||||
self.0.remove(key as &dyn ClientKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn client_lists_test() {
|
fn client_lists_test() {}
|
||||||
let mut clients: Clients = Default::default();
|
}
|
||||||
|
|
||||||
clients.insert(Rc::new(Client {
|
mod no_refcell {
|
||||||
window: 1,
|
use std::{collections::VecDeque, iter::repeat};
|
||||||
floating: false,
|
|
||||||
position: (1, 1),
|
|
||||||
size: (1, 1),
|
|
||||||
}));
|
|
||||||
|
|
||||||
assert!(clients.contains_key(&1u64));
|
use super::*;
|
||||||
|
|
||||||
let mut client_refs = ClientRefs::default();
|
type ClientsWrapped = Rc<RefCell<Clients>>;
|
||||||
|
type Clients = HashMap<Window, Client, BuildIdentityHasher>;
|
||||||
|
type ClientRef = u64;
|
||||||
|
type ClientRefs = Vec<ClientRef>;
|
||||||
|
|
||||||
client_refs.insert(clients.get_with_key(&1u64).unwrap());
|
struct ClientState {
|
||||||
|
clients: Clients,
|
||||||
|
virtual_screens: VecDeque<VirtualScreen>,
|
||||||
|
}
|
||||||
|
|
||||||
assert!(client_refs.contains_key(&1u64));
|
struct VirtualScreen {
|
||||||
|
master: ClientRefs,
|
||||||
|
aux: ClientRefs,
|
||||||
|
focused: Option<ClientRef>,
|
||||||
|
}
|
||||||
|
|
||||||
clients.remove_key(&1u64);
|
impl ClientState {
|
||||||
|
fn insert(&mut self, client: Client) {
|
||||||
|
let key = client.key();
|
||||||
|
|
||||||
assert!(!client_refs.contains_key(&1u64));
|
self.clients.insert(key, client);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get<K>(&self, key: &K) -> Option<&Client>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.clients.get(&key.key())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut<K>(&mut self, key: &K) -> Option<&mut Client>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.clients.get_mut(&key.key())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_floating<K>(&mut self, key: &K) -> Option<bool>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
match self.get_mut(key) {
|
||||||
|
Some(client) => {
|
||||||
|
client.floating = !client.floating;
|
||||||
|
Some(client.floating)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_virtualscreen_for_client<K>(&self, key: &K) -> Option<&VirtualScreen>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.virtual_screens.iter().find_map(
|
||||||
|
|vs| {
|
||||||
|
if vs.contains(key) {
|
||||||
|
Some(vs)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut_virtualscreen_for_client<K>(&mut self, key: &K) -> Option<&mut VirtualScreen>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.virtual_screens.iter_mut().find_map(
|
||||||
|
|vs| {
|
||||||
|
if vs.contains(key) {
|
||||||
|
Some(vs)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// focuses client `key` on current virtual screen
|
||||||
|
fn focus_client<K>(&mut self, key: &K)
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
match self.virtual_screens.front_mut() {
|
||||||
|
Some(vs) => vs.focus(key),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stack_unstacked(&mut self) {
|
||||||
|
let unstacked = self
|
||||||
|
.clients
|
||||||
|
.iter()
|
||||||
|
.filter(|&(key, client)| {
|
||||||
|
!client.floating && self.get_virtualscreen_for_client(key).is_some()
|
||||||
|
})
|
||||||
|
.map(|(key, _)| key)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
match self.virtual_screens.front_mut() {
|
||||||
|
Some(vs) => vs.aux.extend(unstacked.into_iter()),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn switch_stack_for_client<K>(&mut self, key: &K)
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
if let Some(vs) = self.get_mut_virtualscreen_for_client(key) {
|
||||||
|
match vs.master.iter().position(|&key| key == key.key()) {
|
||||||
|
Some(index) => {
|
||||||
|
vs.aux.extend(vs.master.drain(index..=index));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let index = vs.aux.iter().position(|&key| key == key.key()).unwrap();
|
||||||
|
vs.master.extend(vs.aux.drain(index..=index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn refresh_virtual_screen(&mut self) {
|
||||||
|
let clients = &self.clients;
|
||||||
|
|
||||||
|
if let Some(vs) = self.virtual_screens.front_mut() {
|
||||||
|
vs.master.retain(|key| match clients.get(key) {
|
||||||
|
Some(client) => !client.floating,
|
||||||
|
None => false,
|
||||||
|
});
|
||||||
|
vs.aux.retain(|key| match clients.get(key) {
|
||||||
|
Some(client) => !client.floating,
|
||||||
|
None => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// if master is empty but aux has at least one client, drain from aux to master
|
||||||
|
if vs.master.is_empty() && !vs.aux.is_empty() {
|
||||||
|
vs.master.extend(vs.aux.drain(..1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
resizes and moves clients on the current virtual screen with `width` and `height` as
|
||||||
|
screen width and screen height
|
||||||
|
*/
|
||||||
|
fn arange_virtual_screen(&mut self, width: i32, height: i32) {
|
||||||
|
// should be fine to unwrap since we will always have at least 1 virtual screen
|
||||||
|
|
||||||
|
if let Some(vs) = self.virtual_screens.front_mut() {
|
||||||
|
// if aux is empty -> width : width / 2
|
||||||
|
let width = width / 1 + i32::from(!vs.aux.is_empty());
|
||||||
|
|
||||||
|
// chaining master and aux together with `Zip`s for height and x reduces duplicate code
|
||||||
|
for ((i, key), (height, x)) in vs
|
||||||
|
.master
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
// add repeating height for each window and x pos for each window
|
||||||
|
.zip(repeat(height / vs.master.len() as i32).zip(repeat(0i32)))
|
||||||
|
.chain(
|
||||||
|
vs.aux
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.zip(repeat(height / vs.aux.len() as i32).zip(repeat(width))),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
let size = (width, height);
|
||||||
|
let position = (x, height * i as i32);
|
||||||
|
|
||||||
|
if let Some(client) = self.clients.get_mut(key) {
|
||||||
|
*client = Client {
|
||||||
|
size,
|
||||||
|
position,
|
||||||
|
..*client
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should have xlib send those changes back to the x server after this function
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualScreen {
|
||||||
|
fn contains<K>(&self, key: &K) -> bool
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.master.contains(&key.key()) || self.aux.contains(&key.key())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focus<K>(&mut self, key: &K)
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.focused = Some(key.key());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
mod refcell {
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
type ClientsWrapped = Rc<RefCell<Clients>>;
|
||||||
|
type Clients = HashMap<Window, Rc<RefCell<Client>>, BuildIdentityHasher>;
|
||||||
|
type ClientRef = Weak<RefCell<Client>>;
|
||||||
|
type ClientRefs = Vec<ClientRef>;
|
||||||
|
|
||||||
|
struct ClientState {
|
||||||
|
clients: Clients,
|
||||||
|
virtual_screens: VecDeque<VirtualScreen>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VirtualScreen {
|
||||||
|
master: ClientRefs,
|
||||||
|
aux: ClientRefs,
|
||||||
|
focused: Option<ClientRef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientState {
|
||||||
|
fn insert(&mut self, client: Client) {
|
||||||
|
let key = client.key();
|
||||||
|
|
||||||
|
self.clients.insert(key, Rc::new(RefCell::new(client)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get<K>(&self, key: &K) -> Option<&Rc<RefCell<Client>>>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.clients.get(&key.key())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_floating<K>(&mut self, key: &K) -> Option<bool>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
match self.get(key) {
|
||||||
|
Some(client) => {
|
||||||
|
let client = client.borrow_mut();
|
||||||
|
client.floating = !client.floating;
|
||||||
|
|
||||||
|
Some(client.floating)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_virtualscreen_for_client<K>(&self, key: &K) -> Option<&VirtualScreen>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.virtual_screens.iter().find_map(
|
||||||
|
|vs| {
|
||||||
|
if vs.contains(key) {
|
||||||
|
Some(vs)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut_virtualscreen_for_client<K>(&mut self, key: &K) -> Option<&mut VirtualScreen>
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.virtual_screens.iter_mut().find_map(
|
||||||
|
|vs| {
|
||||||
|
if vs.contains(key) {
|
||||||
|
Some(vs)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// focuses client `key` on current virtual screen
|
||||||
|
fn focus_client<K>(&mut self, key: &K)
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
match self.virtual_screens.front_mut() {
|
||||||
|
Some(vs) => vs.focus(key),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stack_unstacked(&mut self) {
|
||||||
|
let unstacked = self
|
||||||
|
.clients
|
||||||
|
.iter()
|
||||||
|
.filter(|&(key, client)| {
|
||||||
|
!client.as_ref().borrow().floating
|
||||||
|
&& self.get_virtualscreen_for_client(key).is_some()
|
||||||
|
})
|
||||||
|
.map(|(key, _)| key)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
match self.virtual_screens.front_mut() {
|
||||||
|
Some(vs) => vs.aux.extend(unstacked.into_iter()),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arrange(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualScreen {
|
||||||
|
fn contains<K>(&self, key: &K) -> bool
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.master.contains(&key.key()) || self.aux.contains(&key.key())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focus<K>(&mut self, key: &K)
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
self.focused = Some(key.key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
417
src/state.rs
Normal file
417
src/state.rs
Normal file
|
@ -0,0 +1,417 @@
|
||||||
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
collections::HashMap,
|
||||||
|
ffi::CString,
|
||||||
|
ptr::{null, null_mut},
|
||||||
|
rc::{Rc, Weak},
|
||||||
|
};
|
||||||
|
|
||||||
|
use x11::xlib::{
|
||||||
|
self, Atom, ControlMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, ShiftMask,
|
||||||
|
Window, XDefaultScreen, XEvent, XInternAtom, XOpenDisplay, XRootWindow,
|
||||||
|
};
|
||||||
|
use xlib::GrabModeAsync;
|
||||||
|
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
use crate::util::BuildIdentityHasher;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Display(Rc<*mut x11::xlib::Display>);
|
||||||
|
|
||||||
|
impl Display {
|
||||||
|
pub fn new(display: *mut x11::xlib::Display) -> Self {
|
||||||
|
Self {
|
||||||
|
0: Rc::new(display),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> *mut x11::xlib::Display {
|
||||||
|
*self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Client {
|
||||||
|
window: Window,
|
||||||
|
floating: bool,
|
||||||
|
size: (i32, i32),
|
||||||
|
position: (i32, i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Client {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
window: 0,
|
||||||
|
floating: false,
|
||||||
|
size: (0, 0),
|
||||||
|
position: (0, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn new(window: xlib::Window) -> Self {
|
||||||
|
Self {
|
||||||
|
window,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Client {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.window == other.window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Client {}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct VirtualScreen {
|
||||||
|
master_stack: HashMap<Window, Weak<RefCell<Client>>, BuildIdentityHasher>,
|
||||||
|
aux_stack: HashMap<Window, Weak<RefCell<Client>>, BuildIdentityHasher>,
|
||||||
|
focused_client: Weak<RefCell<Client>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualScreen {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
master_stack: HashMap::default(),
|
||||||
|
aux_stack: HashMap::default(),
|
||||||
|
focused_client: Weak::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains_client(&self, client: Rc<RefCell<Client>>) -> bool {
|
||||||
|
self.master_stack.contains_key(&client.borrow().window)
|
||||||
|
|| self.aux_stack.contains_key(&client.borrow().window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct XLibAtoms {
|
||||||
|
protocols: Atom,
|
||||||
|
delete_window: Atom,
|
||||||
|
active_window: Atom,
|
||||||
|
take_focus: Atom,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XLibAtoms {
|
||||||
|
fn init(display: Display) -> Self {
|
||||||
|
unsafe {
|
||||||
|
Self {
|
||||||
|
protocols: {
|
||||||
|
let name = CString::new("WM_PROTOCOLS").unwrap();
|
||||||
|
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0)
|
||||||
|
},
|
||||||
|
delete_window: {
|
||||||
|
let name = CString::new("WM_DELETE_WINDOW").unwrap();
|
||||||
|
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0)
|
||||||
|
},
|
||||||
|
active_window: {
|
||||||
|
let name = CString::new("WM_ACTIVE_WINDOW").unwrap();
|
||||||
|
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0)
|
||||||
|
},
|
||||||
|
take_focus: {
|
||||||
|
let name = CString::new("WM_TAKE_FOCUS").unwrap();
|
||||||
|
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct XLibState {
|
||||||
|
display: Display,
|
||||||
|
root: Window,
|
||||||
|
screen: i32,
|
||||||
|
// atoms
|
||||||
|
atoms: XLibAtoms,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XLibState {
|
||||||
|
fn new() -> Self {
|
||||||
|
let (display, screen, root) = unsafe {
|
||||||
|
let display = XOpenDisplay(null());
|
||||||
|
assert_ne!(display, null_mut());
|
||||||
|
|
||||||
|
let screen = XDefaultScreen(display);
|
||||||
|
let root = XRootWindow(display, screen);
|
||||||
|
|
||||||
|
(Display::new(display), screen, root)
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
atoms: XLibAtoms::init(display.clone()),
|
||||||
|
display,
|
||||||
|
root,
|
||||||
|
screen,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dpy(&self) -> *mut x11::xlib::Display {
|
||||||
|
self.display.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn root(&self) -> Window {
|
||||||
|
self.root
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen(&self) -> i32 {
|
||||||
|
self.screen
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grab_key(&self, window: xlib::Window, keycode: i32, mod_mask: u32) {
|
||||||
|
let numlock_mask = self.get_numlock_mask();
|
||||||
|
let modifiers = vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
|
||||||
|
for &modifier in modifiers.iter() {
|
||||||
|
unsafe {
|
||||||
|
xlib::XGrabKey(
|
||||||
|
self.dpy(),
|
||||||
|
keycode,
|
||||||
|
mod_mask | modifier,
|
||||||
|
window,
|
||||||
|
1, /* true */
|
||||||
|
GrabModeAsync,
|
||||||
|
GrabModeAsync,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grab_button(&self, window: xlib::Window, button: u32, mod_mask: u32, button_mask: i64) {
|
||||||
|
let numlock_mask = self.get_numlock_mask();
|
||||||
|
let modifiers = vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
|
||||||
|
|
||||||
|
modifiers.iter().for_each(|&modifier| {
|
||||||
|
unsafe {
|
||||||
|
xlib::XGrabButton(
|
||||||
|
self.dpy(),
|
||||||
|
button,
|
||||||
|
mod_mask | modifier,
|
||||||
|
window,
|
||||||
|
1, /*true */
|
||||||
|
button_mask as u32,
|
||||||
|
GrabModeAsync,
|
||||||
|
GrabModeAsync,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keycode(&self, string: &str) -> i32 {
|
||||||
|
let c_string = CString::new(string).unwrap();
|
||||||
|
unsafe {
|
||||||
|
let keysym = xlib::XStringToKeysym(c_string.as_ptr());
|
||||||
|
xlib::XKeysymToKeycode(self.dpy(), keysym) as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_for_protocol(&self, window: xlib::Window, proto: xlib::Atom) -> bool {
|
||||||
|
let mut protos: *mut xlib::Atom = null_mut();
|
||||||
|
let mut num_protos: i32 = 0;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if xlib::XGetWMProtocols(self.dpy(), window, &mut protos, &mut num_protos) != 0 {
|
||||||
|
for i in 0..num_protos {
|
||||||
|
if *protos.offset(i as isize) == proto {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_event(&self, window: xlib::Window, proto: Option<xlib::Atom>) -> bool {
|
||||||
|
if proto.is_some() && self.check_for_protocol(window, proto.unwrap()) {
|
||||||
|
let mut data = xlib::ClientMessageData::default();
|
||||||
|
data.set_long(0, proto.unwrap() as i64);
|
||||||
|
let mut event = XEvent {
|
||||||
|
client_message: xlib::XClientMessageEvent {
|
||||||
|
type_: xlib::ClientMessage,
|
||||||
|
serial: 0,
|
||||||
|
display: self.dpy(),
|
||||||
|
send_event: 0,
|
||||||
|
window,
|
||||||
|
format: 32,
|
||||||
|
message_type: self.atoms.protocols,
|
||||||
|
data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XSendEvent(self.dpy(), window, 0, xlib::NoEventMask, &mut event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_numlock_mask(&self) -> u32 {
|
||||||
|
unsafe {
|
||||||
|
let modmap = xlib::XGetModifierMapping(self.dpy());
|
||||||
|
let max_keypermod = (*modmap).max_keypermod;
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
for j in 0..max_keypermod {
|
||||||
|
if *(*modmap)
|
||||||
|
.modifiermap
|
||||||
|
.offset((i * max_keypermod + j) as isize)
|
||||||
|
== xlib::XKeysymToKeycode(self.dpy(), x11::keysym::XK_Num_Lock as u64)
|
||||||
|
{
|
||||||
|
return 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clean_mod_mask(&self) -> u32 {
|
||||||
|
!(self.get_numlock_mask() | LockMask)
|
||||||
|
& (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DisplayServer {
|
||||||
|
type Window;
|
||||||
|
|
||||||
|
fn grab_key(&self, window: Self::Window, keycode: i32, mod_mask: u32);
|
||||||
|
fn grab_button(&self, window: Self::Window, keycode: i32, button_mask: u32, mod_mask: u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WMState {
|
||||||
|
xlib_state: XLibState,
|
||||||
|
key_handlers: Vec<(i32, u32, Rc<dyn Fn(&Self, &XEvent)>)>,
|
||||||
|
// (button, mod_mask, button_mask)
|
||||||
|
buttons: Vec<(u32, u32, i64)>,
|
||||||
|
event_handlers: Vec<Rc<dyn Fn(&Self, &XEvent)>>,
|
||||||
|
|
||||||
|
//move_window:
|
||||||
|
// u64 : window to move
|
||||||
|
// (i32, i32) : initial cursor position
|
||||||
|
// (i32, i32) : initial window position
|
||||||
|
move_window: Option<(u64, (i32, i32), (i32, i32))>,
|
||||||
|
//resize_window:
|
||||||
|
// u64 : window to move
|
||||||
|
// (i32, i32) : initial window position
|
||||||
|
resize_window: Option<(u64, (i32, i32))>,
|
||||||
|
clients: HashMap<Window, Rc<RefCell<Client>>>,
|
||||||
|
focused_client: Weak<RefCell<Client>>,
|
||||||
|
current_vscreen: usize,
|
||||||
|
virtual_screens: Vec<VirtualScreen>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WMState {
|
||||||
|
fn stack_unstacked_clients(&mut self) {
|
||||||
|
info!("[stack_unstacked_clients] ");
|
||||||
|
let current_vscreen = self.current_vscreen;
|
||||||
|
|
||||||
|
self.clients
|
||||||
|
.iter()
|
||||||
|
.filter(|(w, c)| !c.borrow().floating && !self.is_client_stacked(w))
|
||||||
|
.map(|(w, c)| (w.clone(), Rc::downgrade(c)))
|
||||||
|
.collect::<Vec<(u64, Weak<RefCell<Client>>)>>()
|
||||||
|
.iter()
|
||||||
|
.for_each(|(w, c)| {
|
||||||
|
info!(
|
||||||
|
"[stack_unstacked_clients] inserting Window({:?}) into aux_stack",
|
||||||
|
w
|
||||||
|
);
|
||||||
|
|
||||||
|
self.virtual_screens[current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.insert(w.clone(), c.clone());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_client_stacked(&self, window: &Window) -> bool {
|
||||||
|
self.virtual_screens
|
||||||
|
.iter()
|
||||||
|
.any(|vs| vs.contains_window(window))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_for_window(&self, window: &Window) -> Option<Rc<RefCell<Client>>> {
|
||||||
|
self.clients
|
||||||
|
.iter()
|
||||||
|
.filter(|&(w, _)| *w == *window)
|
||||||
|
.next()
|
||||||
|
.map(|(_, c)| c.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn switch_stack_for_client(&mut self, window: &Window) {
|
||||||
|
if let Some(client) = self.client_for_window(window) {
|
||||||
|
info!("[switch_stack_for_client] client: {:#?}", client.borrow());
|
||||||
|
client.borrow_mut().floating = false;
|
||||||
|
|
||||||
|
if self.virtual_screens[self.current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.contains_key(window)
|
||||||
|
{
|
||||||
|
self.virtual_screens[self.current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.remove(window);
|
||||||
|
self.virtual_screens[self.current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.insert(*window, Rc::downgrade(&client));
|
||||||
|
info!("[switch_stack_for_client] moved to aux stack");
|
||||||
|
} else {
|
||||||
|
self.virtual_screens[self.current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.remove(window);
|
||||||
|
self.virtual_screens[self.current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.insert(*window, Rc::downgrade(&client));
|
||||||
|
info!("[switch_stack_for_client] moved to master stack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn refresh_screen(&mut self) {
|
||||||
|
let current_vscreen = self.current_vscreen;
|
||||||
|
|
||||||
|
self.virtual_screens
|
||||||
|
.get_mut(current_vscreen)
|
||||||
|
.and_then(|vs| {
|
||||||
|
vs.master_stack.retain(|_, c| {
|
||||||
|
c.upgrade().is_some() && !c.upgrade().unwrap().borrow().floating
|
||||||
|
});
|
||||||
|
vs.aux_stack.retain(|_, c| {
|
||||||
|
c.upgrade().is_some() && !c.upgrade().unwrap().borrow().floating
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
});
|
||||||
|
|
||||||
|
self.stack_unstacked_clients();
|
||||||
|
|
||||||
|
if self.virtual_screens[current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.is_empty()
|
||||||
|
{
|
||||||
|
info!("[refresh_screen] master stack was empty, pushing first client if exists:");
|
||||||
|
|
||||||
|
self.virtual_screens[current_vscreen]
|
||||||
|
.aux_stack
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, c)| !c.upgrade().unwrap().borrow().floating)
|
||||||
|
.next()
|
||||||
|
.map(|(w, c)| (w.clone(), c.clone()))
|
||||||
|
.and_then(|(w, c)| {
|
||||||
|
info!("[arrange_clients] Window({:#?})", w);
|
||||||
|
|
||||||
|
self.virtual_screens[current_vscreen]
|
||||||
|
.master_stack
|
||||||
|
.insert(w, c);
|
||||||
|
self.virtual_screens[current_vscreen].aux_stack.remove(&w)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue