lots of changes, added XLib (state struct for interfacing with xlib)
This commit is contained in:
parent
6d53483578
commit
a42dfcb962
201
src/clients.rs
201
src/clients.rs
|
@ -12,21 +12,36 @@ mod client {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
pub(super) window: Window,
|
pub(crate) window: Window,
|
||||||
pub(super) floating: bool,
|
pub(crate) size: (i32, i32),
|
||||||
pub(super) size: (i32, i32),
|
pub(crate) position: (i32, i32),
|
||||||
pub(super) position: (i32, i32),
|
}
|
||||||
|
|
||||||
|
impl Default for Client {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
window: 0,
|
||||||
|
size: (100, 100),
|
||||||
|
position: (0, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new(window: Window, floating: bool, size: (i32, i32), position: (i32, i32)) -> Self {
|
pub fn new(window: Window, size: (i32, i32), position: (i32, i32)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
window,
|
window,
|
||||||
floating,
|
|
||||||
size,
|
size,
|
||||||
position,
|
position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_default(window: Window) -> Self {
|
||||||
|
Self {
|
||||||
|
window,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Client {
|
impl Hash for Client {
|
||||||
|
@ -99,7 +114,7 @@ mod client {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
use client::*;
|
pub use client::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -113,23 +128,25 @@ mod tests {
|
||||||
window: 1,
|
window: 1,
|
||||||
size: (1, 1),
|
size: (1, 1),
|
||||||
position: (1, 1),
|
position: (1, 1),
|
||||||
floating: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
clients.insert(Client {
|
clients.insert(Client {
|
||||||
window: 2,
|
window: 2,
|
||||||
size: (1, 1),
|
size: (1, 1),
|
||||||
position: (1, 1),
|
position: (1, 1),
|
||||||
floating: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
clients.arange_virtual_screen(600, 400, None);
|
clients.arrange_virtual_screen(600, 400, None);
|
||||||
|
|
||||||
println!("{:#?}", clients);
|
println!("{:#?}", clients);
|
||||||
|
|
||||||
|
clients
|
||||||
|
.iter_current_screen()
|
||||||
|
.for_each(|c| println!("{:?}", c));
|
||||||
|
|
||||||
clients.remove(&1u64);
|
clients.remove(&1u64);
|
||||||
|
|
||||||
clients.arange_virtual_screen(600, 400, None);
|
clients.arrange_virtual_screen(600, 400, None);
|
||||||
|
|
||||||
println!("{:#?}", clients);
|
println!("{:#?}", clients);
|
||||||
|
|
||||||
|
@ -139,10 +156,9 @@ mod tests {
|
||||||
window: 3,
|
window: 3,
|
||||||
size: (1, 1),
|
size: (1, 1),
|
||||||
position: (1, 1),
|
position: (1, 1),
|
||||||
floating: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
clients.arange_virtual_screen(600, 400, None);
|
clients.arrange_virtual_screen(600, 400, None);
|
||||||
|
|
||||||
println!("{:#?}", clients);
|
println!("{:#?}", clients);
|
||||||
|
|
||||||
|
@ -150,7 +166,7 @@ mod tests {
|
||||||
|
|
||||||
clients.rotate_left();
|
clients.rotate_left();
|
||||||
|
|
||||||
clients.arange_virtual_screen(600, 400, None);
|
clients.arrange_virtual_screen(600, 400, None);
|
||||||
|
|
||||||
println!("{:#?}", clients);
|
println!("{:#?}", clients);
|
||||||
}
|
}
|
||||||
|
@ -173,18 +189,48 @@ pub enum ClientEntry<T> {
|
||||||
Vacant,
|
Vacant,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Into<Option<T>> for ClientEntry<T> {
|
||||||
|
fn into(self) -> Option<T> {
|
||||||
|
match self {
|
||||||
|
Self::Vacant => None,
|
||||||
|
Self::Tiled(client) | Self::Floating(client) => Some(client),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ClientEntry<T> {
|
||||||
|
pub fn into_option(self) -> Option<T> {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap(self) -> T {
|
||||||
|
self.into_option().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_vacant(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ClientEntry::Vacant => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_occupied(&self) -> bool {
|
||||||
|
!self.is_vacant()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
clients: Clients,
|
pub(self) clients: Clients,
|
||||||
floating_clients: Clients,
|
pub(self) floating_clients: Clients,
|
||||||
virtual_screens: VecDeque<VirtualScreen>,
|
focused: Option<ClientRef>,
|
||||||
|
pub(self) virtual_screens: VecDeque<VirtualScreen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct VirtualScreen {
|
struct VirtualScreen {
|
||||||
master: ClientRefs,
|
master: ClientRefs,
|
||||||
aux: ClientRefs,
|
aux: ClientRefs,
|
||||||
focused: Option<ClientRef>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ClientState {
|
impl Default for ClientState {
|
||||||
|
@ -195,6 +241,7 @@ impl Default for ClientState {
|
||||||
Self {
|
Self {
|
||||||
clients: Default::default(),
|
clients: Default::default(),
|
||||||
floating_clients: Default::default(),
|
floating_clients: Default::default(),
|
||||||
|
focused: None,
|
||||||
virtual_screens: vss,
|
virtual_screens: vss,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +262,7 @@ impl ClientState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, client: Client) {
|
pub fn insert(&mut self, client: Client) -> Option<&Client> {
|
||||||
let key = client.key();
|
let key = client.key();
|
||||||
|
|
||||||
self.clients.insert(key, client);
|
self.clients.insert(key, client);
|
||||||
|
@ -223,6 +270,10 @@ impl ClientState {
|
||||||
if let Some(vs) = self.virtual_screens.front_mut() {
|
if let Some(vs) = self.virtual_screens.front_mut() {
|
||||||
vs.aux.push(key);
|
vs.aux.push(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.focus_client(&key);
|
||||||
|
|
||||||
|
self.clients.get(&key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove<K>(&mut self, key: &K)
|
pub fn remove<K>(&mut self, key: &K)
|
||||||
|
@ -235,6 +286,35 @@ impl ClientState {
|
||||||
self.floating_clients.remove(&key.key());
|
self.floating_clients.remove(&key.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn contains<K>(&self, key: &K) -> bool
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
let key = key.key();
|
||||||
|
|
||||||
|
self.clients.contains_key(&key) || self.floating_clients.contains_key(&key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_floating(&self) -> impl Iterator<Item = (&u64, &Client)> {
|
||||||
|
self.floating_clients.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_hidden(&self) -> impl Iterator<Item = (&u64, &Client)> {
|
||||||
|
self.clients
|
||||||
|
.iter()
|
||||||
|
.filter(move |&(k, _)| !self.virtual_screens.front().unwrap().contains(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_visible(&self) -> impl Iterator<Item = (&u64, &Client)> {
|
||||||
|
self.iter_floating().chain(self.iter_current_screen())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_current_screen(&self) -> impl Iterator<Item = (&u64, &Client)> {
|
||||||
|
self.clients
|
||||||
|
.iter()
|
||||||
|
.filter(move |&(k, _)| self.virtual_screens.front().unwrap().contains(k))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get<K>(&self, key: &K) -> ClientEntry<&Client>
|
pub fn get<K>(&self, key: &K) -> ClientEntry<&Client>
|
||||||
where
|
where
|
||||||
K: ClientKey,
|
K: ClientKey,
|
||||||
|
@ -248,16 +328,11 @@ impl ClientState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut<K>(&mut self, key: &K) -> ClientEntry<&mut Client>
|
pub fn get_focused(&self) -> ClientEntry<&Client> {
|
||||||
where
|
if let Some(focused) = self.focused {
|
||||||
K: ClientKey,
|
self.get(&focused)
|
||||||
{
|
} else {
|
||||||
match self.clients.get_mut(&key.key()) {
|
ClientEntry::Vacant
|
||||||
Some(client) => ClientEntry::Tiled(client),
|
|
||||||
None => match self.floating_clients.get_mut(&key.key()) {
|
|
||||||
Some(client) => ClientEntry::Floating(client),
|
|
||||||
None => ClientEntry::Vacant,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,14 +400,56 @@ impl ClientState {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// focuses client `key` on current virtual screen
|
/**
|
||||||
pub fn focus_client<K>(&mut self, key: &K)
|
focuses client `key` if it contains `key` and returns a reference to the newly and the previously
|
||||||
|
focused clients if any.
|
||||||
|
*/
|
||||||
|
pub fn focus_client<K>(&mut self, key: &K) -> (ClientEntry<&Client>, ClientEntry<&Client>)
|
||||||
where
|
where
|
||||||
K: ClientKey,
|
K: ClientKey,
|
||||||
{
|
{
|
||||||
match self.virtual_screens.front_mut() {
|
if self.contains(key) {
|
||||||
Some(vs) => vs.focus(key),
|
match self.focused {
|
||||||
None => {}
|
// focus the new client and return reference to it and the previously focused client.
|
||||||
|
Some(focused) => {
|
||||||
|
self.focused = Some(key.key());
|
||||||
|
(self.get(key), self.get(&focused))
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
not currently focusing any client
|
||||||
|
focus the new client and return reference to it.
|
||||||
|
*/
|
||||||
|
None => {
|
||||||
|
self.focused = Some(key.key());
|
||||||
|
(self.get(key), ClientEntry::Vacant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// key is not a reference to a valid client
|
||||||
|
(ClientEntry::Vacant, ClientEntry::Vacant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
sets `self.focused` to `None` and returns a reference to the previously focused Client if any.
|
||||||
|
*/
|
||||||
|
pub fn unfocus(&mut self) -> ClientEntry<&Client> {
|
||||||
|
match self.focused {
|
||||||
|
Some(focused) => {
|
||||||
|
self.focused = None;
|
||||||
|
self.get(&focused)
|
||||||
|
}
|
||||||
|
None => ClientEntry::Vacant,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_focused<K>(&self, key: &K) -> bool
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
|
{
|
||||||
|
match self.focused {
|
||||||
|
Some(focused) => focused == key.key(),
|
||||||
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +504,7 @@ impl ClientState {
|
||||||
screen width and screen height.
|
screen width and screen height.
|
||||||
Optionally adds a gap between windows `gap.unwrap_or(0)` pixels wide.
|
Optionally adds a gap between windows `gap.unwrap_or(0)` pixels wide.
|
||||||
*/
|
*/
|
||||||
pub fn arange_virtual_screen(&mut self, width: i32, height: i32, gap: Option<i32>) {
|
pub fn arrange_virtual_screen(&mut self, width: i32, height: i32, gap: Option<i32>) {
|
||||||
let gap = gap.unwrap_or(0);
|
let gap = gap.unwrap_or(0);
|
||||||
|
|
||||||
// should be fine to unwrap since we will always have at least 1 virtual screen
|
// should be fine to unwrap since we will always have at least 1 virtual screen
|
||||||
|
@ -444,7 +561,6 @@ impl Default for VirtualScreen {
|
||||||
Self {
|
Self {
|
||||||
master: Default::default(),
|
master: Default::default(),
|
||||||
aux: Default::default(),
|
aux: Default::default(),
|
||||||
focused: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -465,12 +581,6 @@ impl VirtualScreen {
|
||||||
self.master.retain(|k| *k != key);
|
self.master.retain(|k| *k != key);
|
||||||
self.aux.retain(|k| *k != key);
|
self.aux.retain(|k| *k != key);
|
||||||
|
|
||||||
if let Some(k) = self.focused {
|
|
||||||
if k == key {
|
|
||||||
self.focused = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.refresh();
|
self.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,11 +593,4 @@ impl VirtualScreen {
|
||||||
self.master.extend(self.aux.drain(..1));
|
self.master.extend(self.aux.drain(..1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus<K>(&mut self, key: &K)
|
|
||||||
where
|
|
||||||
K: ClientKey,
|
|
||||||
{
|
|
||||||
self.focused = Some(key.key());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
|
|
||||||
//mod state;
|
|
||||||
mod clients;
|
mod clients;
|
||||||
|
mod state;
|
||||||
mod util;
|
mod util;
|
||||||
mod wm;
|
mod wm;
|
||||||
|
mod xlib;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
unsafe extern "C" fn xlib_error_handler(
|
unsafe extern "C" fn xlib_error_handler(
|
||||||
|
@ -33,6 +34,5 @@ fn main() -> Result<()> {
|
||||||
info!("Hello, World!");
|
info!("Hello, World!");
|
||||||
|
|
||||||
//wm::WMState::init().run();
|
//wm::WMState::init().run();
|
||||||
|
state::WindowManager::new().run();
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
522
src/state.rs
522
src/state.rs
|
@ -1,417 +1,161 @@
|
||||||
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 log::info;
|
||||||
|
|
||||||
use crate::util::BuildIdentityHasher;
|
use x11::xlib::{self, Window, XEvent};
|
||||||
|
|
||||||
#[derive(Clone)]
|
use crate::{
|
||||||
pub struct Display(Rc<*mut x11::xlib::Display>);
|
clients::{Client, ClientKey, ClientState},
|
||||||
|
xlib::XLib,
|
||||||
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 {
|
pub struct WindowManager {
|
||||||
atoms: XLibAtoms::init(display.clone()),
|
clients: ClientState,
|
||||||
display,
|
xlib: XLib,
|
||||||
root,
|
|
||||||
screen,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dpy(&self) -> *mut x11::xlib::Display {
|
pub enum Direction {
|
||||||
self.display.get()
|
Left,
|
||||||
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root(&self) -> Window {
|
impl WindowManager {
|
||||||
self.root
|
pub fn new() -> Self {
|
||||||
|
let clients = ClientState::with_virtualscreens(3);
|
||||||
|
let xlib = XLib::new().init();
|
||||||
|
|
||||||
|
Self { clients, xlib }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen(&self) -> i32 {
|
pub fn run(mut self) -> ! {
|
||||||
self.screen
|
loop {
|
||||||
}
|
let event = self.xlib.next_event();
|
||||||
|
|
||||||
pub fn grab_key(&self, window: xlib::Window, keycode: i32, mod_mask: u32) {
|
match event.get_type() {
|
||||||
let numlock_mask = self.get_numlock_mask();
|
xlib::MapRequest => self.map_request(&event),
|
||||||
let modifiers = vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
|
xlib::UnmapNotify => self.unmap_notify(&event),
|
||||||
for &modifier in modifiers.iter() {
|
xlib::ConfigureRequest => self.configure_request(&event),
|
||||||
unsafe {
|
xlib::EnterNotify => self.enter_notify(&event),
|
||||||
xlib::XGrabKey(
|
xlib::DestroyNotify => self.destroy_notify(&event),
|
||||||
self.dpy(),
|
xlib::ButtonPress => self.destroy_notify(&event),
|
||||||
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) {
|
fn rotate_virtual_screen(&mut self, dir: Direction) {
|
||||||
let numlock_mask = self.get_numlock_mask();
|
match dir {
|
||||||
let modifiers = vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
|
Direction::Left => self.clients.rotate_left(),
|
||||||
|
Direction::Right => self.clients.rotate_right(),
|
||||||
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
|
self.clients
|
||||||
.iter()
|
.iter_current_screen()
|
||||||
.filter(|(w, c)| !c.borrow().floating && !self.is_client_stacked(w))
|
.for_each(|(_, c)| self.xlib.move_resize_client(c));
|
||||||
.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
|
self.clients
|
||||||
.iter()
|
.iter_hidden()
|
||||||
.filter(|&(w, _)| *w == *window)
|
.for_each(|(_, c)| self.xlib.hide_client(c));
|
||||||
.next()
|
|
||||||
.map(|(_, c)| c.clone())
|
// focus first client in all visible clients
|
||||||
|
let to_focus = self.clients.iter_visible().next().map(|(k, _)| k).cloned();
|
||||||
|
|
||||||
|
if let Some(key) = to_focus {
|
||||||
|
self.focus_client(&key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn switch_stack_for_client(&mut self, window: &Window) {
|
fn arrange_clients(&mut self) {
|
||||||
if let Some(client) = self.client_for_window(window) {
|
let (width, height) = self.xlib.dimensions();
|
||||||
info!("[switch_stack_for_client] client: {:#?}", client.borrow());
|
self.clients.arrange_virtual_screen(width, height, None);
|
||||||
client.borrow_mut().floating = false;
|
|
||||||
|
|
||||||
if self.virtual_screens[self.current_vscreen]
|
self.clients
|
||||||
.master_stack
|
.iter_current_screen()
|
||||||
.contains_key(window)
|
.for_each(|(_, c)| self.xlib.move_resize_client(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focus_client<K>(&mut self, key: &K)
|
||||||
|
where
|
||||||
|
K: ClientKey,
|
||||||
{
|
{
|
||||||
self.virtual_screens[self.current_vscreen]
|
let (new, old) = self.clients.focus_client(key);
|
||||||
.master_stack
|
|
||||||
.remove(window);
|
if let Some(new) = new.into_option() {
|
||||||
self.virtual_screens[self.current_vscreen]
|
self.xlib.focus_client(new);
|
||||||
.aux_stack
|
}
|
||||||
.insert(*window, Rc::downgrade(&client));
|
|
||||||
info!("[switch_stack_for_client] moved to aux stack");
|
if let Some(old) = old.into_option() {
|
||||||
} else {
|
self.xlib.unfocus_client(old);
|
||||||
self.virtual_screens[self.current_vscreen]
|
}
|
||||||
.aux_stack
|
}
|
||||||
.remove(window);
|
|
||||||
self.virtual_screens[self.current_vscreen]
|
fn unfocus_client(&mut self) {
|
||||||
.master_stack
|
if let Some(client) = self.clients.unfocus().into_option() {
|
||||||
.insert(*window, Rc::downgrade(&client));
|
self.xlib.unfocus_client(client);
|
||||||
info!("[switch_stack_for_client] moved to master stack");
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
fn new_client(&mut self, window: Window) {
|
||||||
|
self.clients.insert(Client::new_default(window)).unwrap();
|
||||||
fn refresh_screen(&mut self) {
|
self.xlib.map_window(window);
|
||||||
let current_vscreen = self.current_vscreen;
|
|
||||||
|
self.focus_client(&window);
|
||||||
self.virtual_screens
|
|
||||||
.get_mut(current_vscreen)
|
self.arrange_clients();
|
||||||
.and_then(|vs| {
|
}
|
||||||
vs.master_stack.retain(|_, c| {
|
|
||||||
c.upgrade().is_some() && !c.upgrade().unwrap().borrow().floating
|
fn map_request(&mut self, event: &XEvent) {
|
||||||
});
|
let event = unsafe { &event.map_request };
|
||||||
vs.aux_stack.retain(|_, c| {
|
|
||||||
c.upgrade().is_some() && !c.upgrade().unwrap().borrow().floating
|
info!("MapRequest: {:?}", event);
|
||||||
});
|
|
||||||
|
if !self.clients.contains(&event.window) {
|
||||||
Some(())
|
info!("MapRequest: new client");
|
||||||
});
|
|
||||||
|
self.new_client(event.window);
|
||||||
self.stack_unstacked_clients();
|
}
|
||||||
|
}
|
||||||
if self.virtual_screens[current_vscreen]
|
|
||||||
.master_stack
|
fn unmap_notify(&mut self, event: &XEvent) {
|
||||||
.is_empty()
|
let event = unsafe { &event.unmap };
|
||||||
{
|
info!("UnmapNotify: {:?}", event);
|
||||||
info!("[refresh_screen] master stack was empty, pushing first client if exists:");
|
|
||||||
|
self.clients.remove(&event.window);
|
||||||
self.virtual_screens[current_vscreen]
|
|
||||||
.aux_stack
|
self.arrange_clients();
|
||||||
.iter()
|
}
|
||||||
.filter(|(_, c)| !c.upgrade().unwrap().borrow().floating)
|
|
||||||
.next()
|
fn destroy_notify(&mut self, event: &XEvent) {
|
||||||
.map(|(w, c)| (w.clone(), c.clone()))
|
let event = unsafe { &event.destroy_window };
|
||||||
.and_then(|(w, c)| {
|
info!("DestroyNotify: {:?}", event);
|
||||||
info!("[arrange_clients] Window({:#?})", w);
|
|
||||||
|
self.clients.remove(&event.window);
|
||||||
self.virtual_screens[current_vscreen]
|
|
||||||
.master_stack
|
self.arrange_clients();
|
||||||
.insert(w, c);
|
}
|
||||||
self.virtual_screens[current_vscreen].aux_stack.remove(&w)
|
|
||||||
});
|
fn configure_request(&mut self, event: &XEvent) {
|
||||||
|
let event = unsafe { &event.configure_request };
|
||||||
|
info!("ConfigureRequest: {:?}", event);
|
||||||
|
|
||||||
|
match self.clients.get(&event.window).into_option() {
|
||||||
|
Some(client) => self.xlib.configure_client(client),
|
||||||
|
None => self.xlib.configure_window(event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter_notify(&mut self, event: &XEvent) {
|
||||||
|
let event = unsafe { &event.crossing };
|
||||||
|
info!("EnterNotify: {:?}", event);
|
||||||
|
|
||||||
|
self.focus_client(&event.window);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button_notify(&mut self, event: &XEvent) {
|
||||||
|
let event = unsafe { &event.button };
|
||||||
|
info!("EnterNotify: {:?}", event);
|
||||||
|
|
||||||
|
self.focus_client(&event.subwindow);
|
||||||
|
if let Some(client) = self.clients.get(&event.subwindow).into_option() {
|
||||||
|
self.xlib.raise_client(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
468
src/xlib.rs
Normal file
468
src/xlib.rs
Normal file
|
@ -0,0 +1,468 @@
|
||||||
|
use std::ptr::{null, null_mut};
|
||||||
|
use std::{ffi::CString, rc::Rc};
|
||||||
|
|
||||||
|
use x11::xlib::{
|
||||||
|
self, Atom, ButtonPressMask, CWEventMask, ControlMask, EnterWindowMask, FocusChangeMask,
|
||||||
|
LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, PointerMotionMask,
|
||||||
|
PropertyChangeMask, ShiftMask, StructureNotifyMask, SubstructureNotifyMask,
|
||||||
|
SubstructureRedirectMask, Window, XConfigureRequestEvent, XDefaultScreen, XEvent, XInternAtom,
|
||||||
|
XMapWindow, XOpenDisplay, XRaiseWindow, XRootWindow, XSync,
|
||||||
|
};
|
||||||
|
use xlib::GrabModeAsync;
|
||||||
|
|
||||||
|
use crate::clients::Client;
|
||||||
|
|
||||||
|
pub struct XLib {
|
||||||
|
display: Display,
|
||||||
|
root: Window,
|
||||||
|
screen: i32,
|
||||||
|
atoms: Atoms,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Atoms {
|
||||||
|
protocols: Atom,
|
||||||
|
delete_window: Atom,
|
||||||
|
active_window: Atom,
|
||||||
|
take_focus: Atom,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum KeyOrButton {
|
||||||
|
Key(i32, u32),
|
||||||
|
Button(u32, u32, u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyOrButton {
|
||||||
|
pub fn key(keycode: i32, modmask: u32) -> Self {
|
||||||
|
Self::Key(keycode, modmask)
|
||||||
|
}
|
||||||
|
pub fn button(button: u32, modmask: u32, buttonmask: u64) -> Self {
|
||||||
|
Self::Button(button, modmask, buttonmask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Display(Rc<*mut xlib::Display>);
|
||||||
|
|
||||||
|
impl XLib {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let (display, screen, root) = unsafe {
|
||||||
|
let display = XOpenDisplay(null());
|
||||||
|
|
||||||
|
assert_ne!(display, null_mut());
|
||||||
|
|
||||||
|
let display = Display::new(display);
|
||||||
|
let screen = XDefaultScreen(display.get());
|
||||||
|
let root = XRootWindow(display.get(), screen);
|
||||||
|
|
||||||
|
(display, screen, root)
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
atoms: Atoms::init(display.clone()),
|
||||||
|
root,
|
||||||
|
screen,
|
||||||
|
display,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(self) -> Self {
|
||||||
|
unsafe {
|
||||||
|
let mut window_attributes =
|
||||||
|
std::mem::MaybeUninit::<xlib::XSetWindowAttributes>::zeroed().assume_init();
|
||||||
|
|
||||||
|
window_attributes.event_mask = SubstructureRedirectMask
|
||||||
|
| StructureNotifyMask
|
||||||
|
| SubstructureNotifyMask
|
||||||
|
| EnterWindowMask
|
||||||
|
| PointerMotionMask
|
||||||
|
| ButtonPressMask;
|
||||||
|
|
||||||
|
xlib::XChangeWindowAttributes(
|
||||||
|
self.dpy(),
|
||||||
|
self.root,
|
||||||
|
CWEventMask,
|
||||||
|
&mut window_attributes,
|
||||||
|
);
|
||||||
|
|
||||||
|
xlib::XSelectInput(self.dpy(), self.root, window_attributes.event_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dpy(&self) -> *mut xlib::Display {
|
||||||
|
self.display.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_event(&self) -> XEvent {
|
||||||
|
unsafe {
|
||||||
|
let mut event = std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init();
|
||||||
|
xlib::XNextEvent(self.dpy(), &mut event);
|
||||||
|
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grab_key_or_button(&self, window: Window, key: &KeyOrButton) {
|
||||||
|
let numlock_mask = self.get_numlock_mask();
|
||||||
|
let modifiers = vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
|
||||||
|
|
||||||
|
for modifier in modifiers.iter() {
|
||||||
|
match key {
|
||||||
|
&KeyOrButton::Key(keycode, modmask) => {
|
||||||
|
unsafe {
|
||||||
|
xlib::XGrabKey(
|
||||||
|
self.dpy(),
|
||||||
|
keycode,
|
||||||
|
modmask | modifier,
|
||||||
|
window,
|
||||||
|
1, /* true */
|
||||||
|
GrabModeAsync,
|
||||||
|
GrabModeAsync,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&KeyOrButton::Button(button, modmask, buttonmask) => {
|
||||||
|
unsafe {
|
||||||
|
xlib::XGrabButton(
|
||||||
|
self.dpy(),
|
||||||
|
button,
|
||||||
|
modmask | modifier,
|
||||||
|
window,
|
||||||
|
1, /*true */
|
||||||
|
buttonmask as u32,
|
||||||
|
GrabModeAsync,
|
||||||
|
GrabModeAsync,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focus_client(&self, client: &Client) {
|
||||||
|
unsafe {
|
||||||
|
xlib::XSetInputFocus(
|
||||||
|
self.dpy(),
|
||||||
|
client.window,
|
||||||
|
xlib::RevertToPointerRoot,
|
||||||
|
xlib::CurrentTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
xlib::XChangeProperty(
|
||||||
|
self.dpy(),
|
||||||
|
self.root,
|
||||||
|
self.atoms.active_window,
|
||||||
|
xlib::XA_WINDOW,
|
||||||
|
32,
|
||||||
|
xlib::PropModeReplace,
|
||||||
|
&client.window as *const u64 as *const _,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.send_event(client, self.atoms.take_focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unfocus_client(&self, client: &Client) {
|
||||||
|
unsafe {
|
||||||
|
xlib::XSetInputFocus(
|
||||||
|
self.dpy(),
|
||||||
|
client.window,
|
||||||
|
xlib::RevertToPointerRoot,
|
||||||
|
xlib::CurrentTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
xlib::XDeleteProperty(self.dpy(), self.root, self.atoms.active_window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_resize_client(&self, client: &Client) {
|
||||||
|
let mut windowchanges = xlib::XWindowChanges {
|
||||||
|
x: client.position.0,
|
||||||
|
y: client.position.1,
|
||||||
|
width: client.size.0,
|
||||||
|
height: client.size.1,
|
||||||
|
border_width: 0,
|
||||||
|
sibling: 0,
|
||||||
|
stack_mode: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XConfigureWindow(
|
||||||
|
self.dpy(),
|
||||||
|
client.window,
|
||||||
|
(xlib::CWY | xlib::CWX | xlib::CWHeight | xlib::CWWidth) as u32,
|
||||||
|
&mut windowchanges,
|
||||||
|
);
|
||||||
|
|
||||||
|
// I don't think I have to call this ~
|
||||||
|
//self.configure(client);
|
||||||
|
|
||||||
|
xlib::XSync(self.dpy(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_client(&self, client: &Client) {
|
||||||
|
let mut wc = xlib::XWindowChanges {
|
||||||
|
x: client.position.0,
|
||||||
|
y: client.position.1,
|
||||||
|
width: client.size.0,
|
||||||
|
height: client.size.1,
|
||||||
|
border_width: 0,
|
||||||
|
sibling: 0,
|
||||||
|
stack_mode: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XConfigureWindow(
|
||||||
|
self.dpy(),
|
||||||
|
client.window,
|
||||||
|
(xlib::CWWidth | xlib::CWHeight) as u32,
|
||||||
|
&mut wc,
|
||||||
|
);
|
||||||
|
|
||||||
|
xlib::XSync(self.dpy(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize_client(&self, client: &Client) {
|
||||||
|
let mut wc = xlib::XWindowChanges {
|
||||||
|
x: client.position.0,
|
||||||
|
y: client.position.1,
|
||||||
|
width: client.size.0,
|
||||||
|
height: client.size.1,
|
||||||
|
border_width: 0,
|
||||||
|
sibling: 0,
|
||||||
|
stack_mode: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XConfigureWindow(
|
||||||
|
self.dpy(),
|
||||||
|
client.window,
|
||||||
|
(xlib::CWX | xlib::CWY) as u32,
|
||||||
|
&mut wc,
|
||||||
|
);
|
||||||
|
|
||||||
|
xlib::XSync(self.dpy(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hide_client(&self, client: &Client) {
|
||||||
|
let mut wc = xlib::XWindowChanges {
|
||||||
|
x: client.size.0 * -2,
|
||||||
|
y: client.position.1,
|
||||||
|
width: client.size.0,
|
||||||
|
height: client.size.1,
|
||||||
|
border_width: 0,
|
||||||
|
sibling: 0,
|
||||||
|
stack_mode: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XConfigureWindow(
|
||||||
|
self.dpy(),
|
||||||
|
client.window,
|
||||||
|
(xlib::CWWidth | xlib::CWHeight) as u32,
|
||||||
|
&mut wc,
|
||||||
|
);
|
||||||
|
|
||||||
|
xlib::XSync(self.dpy(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raise_client(&self, client: &Client) {
|
||||||
|
unsafe {
|
||||||
|
XRaiseWindow(self.dpy(), client.window);
|
||||||
|
XSync(self.dpy(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure_window(&self, event: &XConfigureRequestEvent) {
|
||||||
|
let mut wc = xlib::XWindowChanges {
|
||||||
|
x: event.x,
|
||||||
|
y: event.y,
|
||||||
|
width: event.width,
|
||||||
|
height: event.height,
|
||||||
|
border_width: event.border_width,
|
||||||
|
sibling: event.above,
|
||||||
|
stack_mode: event.detail,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XConfigureWindow(self.dpy(), event.window, event.value_mask as u32, &mut wc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure_client(&self, client: &Client) {
|
||||||
|
let mut event = xlib::XConfigureEvent {
|
||||||
|
type_: xlib::ConfigureNotify,
|
||||||
|
display: self.dpy(),
|
||||||
|
event: client.window,
|
||||||
|
window: client.window,
|
||||||
|
x: client.position.0,
|
||||||
|
y: client.position.1,
|
||||||
|
width: client.size.0,
|
||||||
|
height: client.size.1,
|
||||||
|
border_width: 0,
|
||||||
|
override_redirect: 0,
|
||||||
|
send_event: 0,
|
||||||
|
serial: 0,
|
||||||
|
above: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XSendEvent(
|
||||||
|
self.dpy(),
|
||||||
|
event.window,
|
||||||
|
0,
|
||||||
|
StructureNotifyMask,
|
||||||
|
&mut event as *mut _ as *mut XEvent,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_window(&self, window: Window) {
|
||||||
|
unsafe {
|
||||||
|
XMapWindow(self.dpy(), window);
|
||||||
|
|
||||||
|
xlib::XSelectInput(
|
||||||
|
self.dpy(),
|
||||||
|
window,
|
||||||
|
EnterWindowMask | FocusChangeMask | PropertyChangeMask | StructureNotifyMask,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dimensions(&self) -> (i32, i32) {
|
||||||
|
unsafe {
|
||||||
|
(
|
||||||
|
xlib::XDisplayWidth(self.dpy(), self.screen),
|
||||||
|
xlib::XDisplayHeight(self.dpy(), self.screen),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_for_protocol(&self, client: &Client, proto: xlib::Atom) -> bool {
|
||||||
|
let mut protos: *mut xlib::Atom = null_mut();
|
||||||
|
let mut num_protos: i32 = 0;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if xlib::XGetWMProtocols(self.dpy(), client.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, client: &Client, proto: xlib::Atom) -> bool {
|
||||||
|
if self.check_for_protocol(client, proto) {
|
||||||
|
let mut data = xlib::ClientMessageData::default();
|
||||||
|
data.set_long(0, proto as i64);
|
||||||
|
|
||||||
|
let mut event = XEvent {
|
||||||
|
client_message: xlib::XClientMessageEvent {
|
||||||
|
type_: xlib::ClientMessage,
|
||||||
|
serial: 0,
|
||||||
|
display: self.dpy(),
|
||||||
|
send_event: 0,
|
||||||
|
window: client.window,
|
||||||
|
format: 32,
|
||||||
|
message_type: self.atoms.protocols,
|
||||||
|
data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XSendEvent(self.dpy(), client.window, 0, xlib::NoEventMask, &mut event);
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn keycode<S>(&self, string: S) -> i32
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
let c_string = CString::new(string.as_ref()).unwrap();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let keysym = xlib::XStringToKeysym(c_string.as_ptr());
|
||||||
|
xlib::XKeysymToKeycode(self.dpy(), keysym) as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 get_clean_mask(&self) -> u32 {
|
||||||
|
!(self.get_numlock_mask() | LockMask)
|
||||||
|
& (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Atoms {
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue