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"
|
||||
x11 = {version = "2.18.2", features = ["xlib"] }
|
||||
log = "0.4.13"
|
||||
weak-table = {path = "/mnt/storage/rust/weak-table-rs"}
|
||||
weak-table = "0.3.0"
|
||||
simple_logger = "1.11.0"
|
463
src/clients.rs
463
src/clients.rs
|
@ -1,15 +1,9 @@
|
|||
use std::{
|
||||
borrow::{Borrow, BorrowMut},
|
||||
collections::HashSet,
|
||||
ops::{Deref, DerefMut},
|
||||
rc::Rc,
|
||||
};
|
||||
use std::{borrow::Borrow, cell::RefCell, collections::HashMap, rc::Rc};
|
||||
use std::{
|
||||
hash::{Hash, Hasher},
|
||||
rc::Weak,
|
||||
};
|
||||
|
||||
use weak_table::WeakHashSet;
|
||||
use x11::xlib::Window;
|
||||
|
||||
use crate::util::BuildIdentityHasher;
|
||||
|
@ -36,6 +30,12 @@ impl PartialEq for Client {
|
|||
|
||||
impl Eq for Client {}
|
||||
|
||||
impl Borrow<Window> for Client {
|
||||
fn borrow(&self) -> &Window {
|
||||
&self.window
|
||||
}
|
||||
}
|
||||
|
||||
trait ClientKey {
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn client_lists_test() {
|
||||
let mut clients: Clients = Default::default();
|
||||
fn client_lists_test() {}
|
||||
}
|
||||
|
||||
clients.insert(Rc::new(Client {
|
||||
window: 1,
|
||||
floating: false,
|
||||
position: (1, 1),
|
||||
size: (1, 1),
|
||||
}));
|
||||
mod no_refcell {
|
||||
use std::{collections::VecDeque, iter::repeat};
|
||||
|
||||
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