Compare commits

...

5 commits

Author SHA1 Message Date
NoOneBtw adc71e517f idek what i added today. 2021-05-23 02:26:21 +02:00
NoOneBtw 1b2e2d848c changed rustfmt to actually work hopefully (70 char limit)
also more abstraction stuff
2021-05-15 02:48:23 +02:00
NoOneBtw 98459d620c started with a backend using x11rb 2021-05-13 23:43:02 +02:00
NoOneBtw 507bc75ccc started with Client Manager logic 2021-05-13 00:16:14 +02:00
NoOneBtw db94c82185 added new Client, Entry, ClientStore structs and related logic 2021-05-12 18:28:44 +02:00
15 changed files with 5857 additions and 114 deletions

View file

@ -8,6 +8,9 @@ edition = "2018"
[dependencies]
x11 = {version = "2.18.2", features = ["xlib"] }
x11rb = "0.8.1"
num-derive = "0.3.3"
num-traits = "0.2.14"
log = "0.4.13"
simple_logger = "1.11.0"
dirs = "3.0.2"

View file

@ -1,2 +1,2 @@
#wrap_comments = true
max_width = 80
wrap_comments = true
max_width = 70

209
src/backends/keycodes.rs Normal file
View file

@ -0,0 +1,209 @@
#![allow(dead_code)]
#[derive(
Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy,
)]
pub enum MouseButton {
Left,
Middle,
Right,
ScrollUp,
ScrollDown,
ScrollLeft,
ScrollRight,
Forward,
Backward,
}
/// from winit
#[derive(
Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy,
)]
#[repr(u32)]
pub enum VirtualKeyCode {
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
/// The Escape key, next to F1.
Escape,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
/// Print Screen/SysRq.
Snapshot,
/// Scroll Lock.
Scroll,
/// Pause/Break key, next to Scroll lock.
Pause,
/// `Insert`, next to Backspace.
Insert,
Home,
Delete,
End,
PageDown,
PageUp,
Left,
Up,
Right,
Down,
/// The Backspace key, right over Enter.
// TODO: rename
Back,
/// The Enter key.
Return,
/// The space bar.
Space,
/// The "Compose" key on Linux.
Compose,
Caret,
Numlock,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
NumpadAdd,
NumpadDivide,
NumpadDecimal,
NumpadComma,
NumpadEnter,
NumpadEquals,
NumpadMultiply,
NumpadSubtract,
AbntC1,
AbntC2,
Apostrophe,
Apps,
Asterisk,
At,
Ax,
Backslash,
Calculator,
Capital,
Colon,
Comma,
Convert,
Equals,
Grave,
Kana,
Kanji,
LAlt,
LBracket,
LControl,
LShift,
LWin,
Mail,
MediaSelect,
MediaStop,
Minus,
Mute,
MyComputer,
// also called "Next"
NavigateForward,
// also called "Prior"
NavigateBackward,
NextTrack,
NoConvert,
OEM102,
Period,
PlayPause,
Plus,
Power,
PrevTrack,
RAlt,
RBracket,
RControl,
RShift,
RWin,
Semicolon,
Slash,
Sleep,
Stop,
Sysrq,
Tab,
Underline,
Unlabeled,
VolumeDown,
VolumeUp,
Wake,
WebBack,
WebFavorites,
WebForward,
WebHome,
WebRefresh,
WebSearch,
WebStop,
Yen,
Copy,
Paste,
Cut,
}

6
src/backends/mod.rs Normal file
View file

@ -0,0 +1,6 @@
mod keycodes;
mod window_event;
mod xcb;
mod xlib;
pub trait WindowServerBackend {}

View file

@ -0,0 +1,238 @@
#![allow(dead_code)]
use x11::xlib::Window;
use super::keycodes::{MouseButton, VirtualKeyCode};
#[derive(Debug)]
pub enum WindowEvent {
KeyEvent {
window: Window,
event: KeyEvent,
},
ButtonEvent {
window: Window,
event: ButtonEvent,
},
MotionEvent {
window: Window,
event: MotionEvent,
},
MapRequestEvent {
window: Window,
event: MapEvent,
},
MapEvent {
window: Window,
event: MapEvent,
},
UnmapEvent {
window: Window,
event: UnmapEvent,
},
CreateEvent {
window: Window,
event: CreateEvent,
},
DestroyEvent {
window: Window,
event: DestroyEvent,
},
EnterEvent {
window: Window,
event: EnterEvent,
},
ConfigureEvent {
window: Window,
event: ConfigureEvent,
},
FullscreenEvent {
window: Window,
event: FullscreenEvent,
}, //1 { window: Window, event: 1 },
}
#[derive(Debug)]
pub enum KeyState {
Pressed,
Released,
}
#[derive(
Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy,
)]
#[repr(u8)]
pub enum ModifierKey {
Shift,
ShiftLock,
Control,
Alt,
AltGr,
/// Windows key on most keyboards
Super,
NumLock,
}
#[derive(Default, Debug, Clone)]
pub struct ModifierState {
modifiers: std::collections::HashSet<ModifierKey>,
}
impl ModifierState {
pub fn new() -> Self {
Self::default()
}
pub fn set_modifier(&mut self, modifier: ModifierKey) {
self.modifiers.insert(modifier);
}
pub fn unset_modifier(&mut self, modifier: ModifierKey) {
self.modifiers.remove(&modifier);
}
pub fn get_modifier(&mut self, modifier: ModifierKey) -> bool {
self.modifiers.contains(&modifier)
}
}
#[derive(Debug)]
pub struct KeyEvent {
state: KeyState,
keycode: VirtualKeyCode,
modifierstate: ModifierState,
}
impl KeyEvent {
pub fn new(
state: KeyState,
keycode: VirtualKeyCode,
modifierstate: ModifierState,
) -> Self {
Self {
state,
keycode,
modifierstate,
}
}
}
#[derive(Debug)]
pub struct ButtonEvent {
state: KeyState,
keycode: MouseButton,
modifierstate: ModifierState,
}
impl ButtonEvent {
pub fn new(
state: KeyState,
keycode: MouseButton,
modifierstate: ModifierState,
) -> Self {
Self {
state,
keycode,
modifierstate,
}
}
}
#[derive(Debug)]
pub struct MotionEvent {
position: [i32; 2],
}
impl MotionEvent {
pub fn new(position: [i32; 2]) -> Self {
Self { position }
}
}
#[derive(Debug)]
pub struct MapEvent {
window: Window,
}
impl MapEvent {
pub fn new(window: Window) -> Self {
Self { window }
}
}
#[derive(Debug)]
pub struct UnmapEvent {
window: Window,
}
impl UnmapEvent {
pub fn new(window: Window) -> Self {
Self { window }
}
}
#[derive(Debug)]
pub struct EnterEvent {}
#[derive(Debug)]
pub struct DestroyEvent {
window: Window,
}
impl DestroyEvent {
pub fn new(window: Window) -> Self {
Self { window }
}
}
#[derive(Debug)]
pub struct CreateEvent {
window: Window,
position: [i32; 2],
size: [i32; 2],
}
impl CreateEvent {
pub fn new(
window: Window,
position: [i32; 2],
size: [i32; 2],
) -> Self {
Self {
window,
position,
size,
}
}
}
#[derive(Debug)]
pub struct ConfigureEvent {
pub window: Window,
pub position: [i32; 2],
pub size: [i32; 2],
}
impl ConfigureEvent {
pub fn new(
window: Window,
position: [i32; 2],
size: [i32; 2],
) -> Self {
Self {
window,
position,
size,
}
}
}
#[derive(Debug)]
pub struct FullscreenEvent {
new_fullscreen: bool,
}
impl FullscreenEvent {
pub fn new(new_fullscreen: bool) -> Self {
Self { new_fullscreen }
}
}

402
src/backends/xcb.rs Normal file
View file

@ -0,0 +1,402 @@
//x11 backend
#![allow(dead_code)]
use log::error;
use num_traits::FromPrimitive;
use num_traits::ToPrimitive;
use std::sync::Arc;
use x11rb::{
connect,
connection::Connection,
errors::ReplyError,
errors::ReplyOrIdError,
protocol::xproto::{
Atom, ChangeWindowAttributesAux, ConnectionExt, EventMask,
Screen, Setup,
},
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn keysyms() {
let xcb = create_backend().unwrap();
let mapping = xcb
.connection
.get_keyboard_mapping(
xcb.setup().min_keycode,
xcb.setup().max_keycode - xcb.setup().min_keycode + 1,
)
.unwrap();
let mapping = mapping.reply().unwrap();
for (i, keysyms) in mapping
.keysyms
.chunks(mapping.keysyms_per_keycode as usize)
.enumerate()
{
println!(
"keycode: {:#?}\tkeysyms: {:0x?}",
xcb.setup().min_keycode as usize + i,
keysyms
);
}
}
#[test]
fn modifier_masks() {
let xcb = create_backend().unwrap();
let mapping = xcb
.connection
.get_modifier_mapping()
.unwrap()
.reply()
.unwrap();
for (modifier_index, keycodes) in mapping
.keycodes
.chunks(mapping.keycodes_per_modifier() as usize)
.enumerate()
{
println!(
"Mod: {}[{:#x?}] keycodes: {:?}",
modifier_index,
1 << modifier_index,
keycodes
);
}
}
}
#[repr(u8)]
#[derive(FromPrimitive, ToPrimitive)]
pub enum MouseButton {
Left = 1,
Middle,
Right,
ScrollUp,
ScrollDown,
ScrollLeft,
ScrollRight,
Backwards,
Forwards,
}
#[derive(FromPrimitive, ToPrimitive)]
pub enum Key {
BackSpace = 0xff08,
Tab = 0xff09,
Linefeed = 0xff0a,
Clear = 0xff0b,
Return = 0xff0d,
Pause = 0xff13,
ScrollLock = 0xff14,
SysReq = 0xff15,
Escape = 0xff1b,
Delete = 0xffff,
Home = 0xff50,
Left = 0xff51,
Up = 0xff52,
Right = 0xff53,
Down = 0xff54,
PageUp = 0xff55,
PageDown = 0xff56,
End = 0xff57,
Begin = 0xff58,
Space = 0x0020,
Exclam = 0x0021,
Quotedbl = 0x0022,
Numbersign = 0x0023,
Dollar = 0x0024,
Percent = 0x0025,
Ampersand = 0x0026,
Apostrophe = 0x0027,
ParenLeft = 0x0028,
ParenRight = 0x0029,
Asterisk = 0x002a,
Plus = 0x002b,
Comma = 0x002c,
Minus = 0x002d,
Period = 0x002e,
Slash = 0x002f,
Zero = 0x0030,
One = 0x0031,
Two = 0x0032,
Three = 0x0033,
Four = 0x0034,
Five = 0x0035,
Six = 0x0036,
Seven = 0x0037,
Eight = 0x0038,
Nine = 0x0039,
Colon = 0x003a,
Semicolon = 0x003b,
Less = 0x003c,
Equal = 0x003d,
Greater = 0x003e,
Question = 0x003f,
At = 0x0040,
UppercaseA = 0x0041,
UppercaseB = 0x0042,
UppercaseC = 0x0043,
UppercaseD = 0x0044,
UppercaseE = 0x0045,
UppercaseF = 0x0046,
UppercaseG = 0x0047,
UppercaseH = 0x0048,
UppercaseI = 0x0049,
UppercaseJ = 0x004a,
UppercaseK = 0x004b,
UppercaseL = 0x004c,
UppercaseM = 0x004d,
UppercaseN = 0x004e,
UppercaseO = 0x004f,
UppercaseP = 0x0050,
UppercaseQ = 0x0051,
UppercaseR = 0x0052,
UppercaseS = 0x0053,
UppercaseT = 0x0054,
UppercaseU = 0x0055,
UppercaseV = 0x0056,
UppercaseW = 0x0057,
UppercaseX = 0x0058,
UppercaseY = 0x0059,
UppercaseZ = 0x005a,
BracketLeft = 0x005b,
Backslash = 0x005c,
BracketRight = 0x005d,
AsciiCircum = 0x005e,
Underscore = 0x005f,
Grave = 0x0060,
LowercaseA = 0x0061,
LowercaseB = 0x0062,
LowercaseC = 0x0063,
LowercaseD = 0x0064,
LowercaseE = 0x0065,
LowercaseF = 0x0066,
LowercaseG = 0x0067,
LowercaseH = 0x0068,
LowercaseI = 0x0069,
LowercaseJ = 0x006a,
LowercaseK = 0x006b,
LowercaseL = 0x006c,
LowercaseM = 0x006d,
LowercaseN = 0x006e,
LowercaseO = 0x006f,
LowercaseP = 0x0070,
LowercaseQ = 0x0071,
LowercaseR = 0x0072,
LowercaseS = 0x0073,
LowercaseT = 0x0074,
LowercaseU = 0x0075,
LowercaseV = 0x0076,
LowercaseW = 0x0077,
LowercaseX = 0x0078,
LowercaseY = 0x0079,
LowercaseZ = 0x007a,
BraceLeft = 0x007b,
Bar = 0x007c,
BraceRight = 0x007d,
AsciiTilde = 0x007e,
}
impl Key {}
// '<,'>s/.* XK_\([A-z,_]*\)[ ]*\(0x[a-f,0-9]*\).*/\1 = \2,/
struct Atoms {
wm_protocols: Atom,
wm_state: Atom,
wm_delete_window: Atom,
wm_take_focus: Atom,
net_supported: Atom,
net_active_window: Atom,
net_client_list: Atom,
net_wm_name: Atom,
net_wm_state: Atom,
net_wm_state_fullscreen: Atom,
net_wm_window_type: Atom,
net_wm_window_type_dialog: Atom,
}
impl Atoms {
fn new<C>(connection: Arc<C>) -> Result<Self, ReplyOrIdError>
where
C: Connection,
{
let wm_protocols =
connection.intern_atom(false, b"WM_PROTOCOLS")?;
let wm_state = connection.intern_atom(false, b"WM_STATE")?;
let wm_delete_window =
connection.intern_atom(false, b"WM_DELETE_WINDOW")?;
let wm_take_focus =
connection.intern_atom(false, b"WM_TAKE_FOCUS")?;
let net_supported =
connection.intern_atom(false, b"_NET_SUPPORTED")?;
let net_active_window =
connection.intern_atom(false, b"_NET_ACTIVE_WINDOW")?;
let net_client_list =
connection.intern_atom(false, b"_NET_CLIENT_LIST")?;
let net_wm_name =
connection.intern_atom(false, b"_NET_WM_NAME")?;
let net_wm_state =
connection.intern_atom(false, b"_NET_WM_STATE")?;
let net_wm_state_fullscreen = connection
.intern_atom(false, b"_NET_WM_STATE_FULLSCREEN")?;
let net_wm_window_type =
connection.intern_atom(false, b"_NET_WM_WINDOW_TYPE")?;
let net_wm_window_type_dialog = connection
.intern_atom(false, b"_NET_WM_WINDOW_TYPE_DIALOG")?;
Ok(Self {
wm_protocols: wm_protocols.reply()?.atom,
wm_state: wm_state.reply()?.atom,
wm_delete_window: wm_delete_window.reply()?.atom,
wm_take_focus: wm_take_focus.reply()?.atom,
net_supported: net_supported.reply()?.atom,
net_active_window: net_active_window.reply()?.atom,
net_client_list: net_client_list.reply()?.atom,
net_wm_name: net_wm_name.reply()?.atom,
net_wm_state: net_wm_state.reply()?.atom,
net_wm_state_fullscreen: net_wm_state_fullscreen
.reply()?
.atom,
net_wm_window_type: net_wm_window_type.reply()?.atom,
net_wm_window_type_dialog: net_wm_window_type_dialog
.reply()?
.atom,
})
}
}
pub struct X11Backend<C>
where
C: Connection,
{
connection: Arc<C>,
screen: usize,
atoms: Atoms,
}
pub fn create_backend() -> Result<
X11Backend<impl Connection + Send + Sync>,
Box<dyn std::error::Error>,
> {
let (connection, screen) = connect(None)?;
Ok(X11Backend::new(Arc::new(connection), screen)?)
}
impl<C> X11Backend<C>
where
C: Connection,
{
pub fn new(
connection: Arc<C>,
screen: usize,
) -> Result<Self, ReplyOrIdError> {
let atoms = Atoms::new(connection.clone())?;
Ok(Self {
connection,
screen,
atoms,
})
}
fn setup(&self) -> &Setup {
self.connection.setup()
}
fn screen(&self) -> &Screen {
&self.connection.setup().roots[self.screen]
}
fn root(&self) -> u32 {
self.screen().root
}
// this needs the mask aswell to determine the keysym
fn keysym_for_keycode(&self, keycode: u8) -> Option<Key> {
let setup = self.setup();
let mapping = self
.connection
.get_keyboard_mapping(
setup.min_keycode,
setup.max_keycode - setup.min_keycode + 1,
)
.ok()?;
let mapping = mapping.reply().ok()?;
mapping
.keysyms
.chunks(mapping.keysyms_per_keycode as usize)
.nth(keycode as usize)
.and_then(|keysyms| Key::from_u32(keysyms[0]))
}
fn keycode_for_keysym<K>(&self, keysym: &K) -> Option<u8>
where
K: num_traits::ToPrimitive,
{
if let Some(keysym) = keysym.to_u32() {
let setup = self.setup();
let mapping = self
.connection
.get_keyboard_mapping(
setup.min_keycode,
setup.max_keycode - setup.min_keycode + 1,
)
.ok()?;
let mapping = mapping.reply().ok()?;
mapping
.keysyms
.chunks(mapping.keysyms_per_keycode as usize)
.enumerate()
.find_map(|(i, keysyms)| {
if keysyms.contains(&keysym) {
Some(setup.min_keycode + i as u8)
} else {
None
}
})
} else {
None
}
}
pub fn request_substructure_events(
&self,
) -> Result<(), ReplyError> {
let attributes = ChangeWindowAttributesAux::default()
.event_mask(
EventMask::SUBSTRUCTURE_REDIRECT
| EventMask::SUBSTRUCTURE_NOTIFY,
);
match self
.connection
.change_window_attributes(self.root(), &attributes)?
.check()
{
Ok(_) => Ok(()),
Err(err) => {
error!(
"Failed to request substructure redirect/notify: another \
window manager is running. {:#?}",
err
);
Err(err)
}
}
}
}

1233
src/backends/xlib.rs.old Normal file

File diff suppressed because it is too large Load diff

2054
src/backends/xlib/keysym.rs Normal file

File diff suppressed because it is too large Load diff

535
src/backends/xlib/mod.rs Normal file
View file

@ -0,0 +1,535 @@
#![allow(non_upper_case_globals)]
pub mod keysym;
use std::ptr::null;
use x11::xlib::{
AnyModifier, Atom, ButtonPress, ButtonPressMask, ButtonRelease,
ButtonReleaseMask, ClientMessage, ConfigureRequest, CreateNotify,
DestroyNotify, EnterWindowMask, FocusChangeMask, GrabModeAsync,
KeyPress, KeyPressMask, KeyRelease, KeyReleaseMask, MapNotify,
MapRequest, MotionNotify, PropertyChangeMask, PropertyNewValue,
PropertyNotify, StructureNotifyMask, UnmapNotify, Window,
XButtonEvent, XClientMessageEvent, XConfigureRequestEvent,
XConfigureWindow, XCreateWindowEvent, XDestroyWindowEvent,
XEvent, XGrabButton, XGrabKey, XInternAtom, XKeyEvent,
XKeysymToKeycode, XLookupKeysym, XMapRequestEvent, XMapWindow,
XMotionEvent, XNextEvent, XPropertyEvent, XRootWindow,
XSelectInput, XUnmapEvent, XWindowChanges,
};
use crate::backends::window_event::{
ButtonEvent, KeyEvent, KeyState, ModifierKey,
};
use self::keysym::{
keysym_to_virtual_keycode, mouse_button_to_xbutton,
virtual_keycode_to_keysym, xev_to_mouse_button,
};
use super::{
keycodes::{MouseButton, VirtualKeyCode},
window_event::{
ConfigureEvent, CreateEvent, DestroyEvent, FullscreenEvent,
MapEvent, ModifierState, MotionEvent, UnmapEvent,
WindowEvent,
},
};
struct Atoms {
wm_protocols: Atom,
wm_state: Atom,
wm_delete_window: Atom,
wm_take_focus: Atom,
net_supported: Atom,
net_active_window: Atom,
net_client_list: Atom,
net_wm_name: Atom,
net_wm_state: Atom,
net_wm_state_fullscreen: Atom,
net_wm_window_type: Atom,
net_wm_window_type_dialog: Atom,
}
// xlib backend
pub struct XLib {
display: *mut x11::xlib::Display,
modifier_state: ModifierState,
atoms: Atoms,
screen: i32,
}
impl Drop for XLib {
fn drop(&mut self) {
unsafe {
x11::xlib::XCloseDisplay(self.display);
}
}
}
impl XLib {
pub fn new() -> Self {
let (display, screen) = unsafe {
let display = x11::xlib::XOpenDisplay(null());
let screen = x11::xlib::XDefaultScreen(display);
(display, screen)
};
Self {
display,
screen,
atoms: Self::init_atoms(display),
modifier_state: Default::default(),
}
}
fn root_window(&self) -> Window {
unsafe { XRootWindow(self.display, self.screen) }
}
fn init_atoms(display: *mut x11::xlib::Display) -> Atoms {
unsafe {
let wm_protocols = XInternAtom(
display,
b"WM_PROTOCOLS\0".as_ptr() as *const _,
0,
);
let wm_state = XInternAtom(
display,
b"WM_STATE\0".as_ptr() as *const _,
0,
);
let wm_delete_window = XInternAtom(
display,
b"WM_DELETE_WINDOW\0".as_ptr() as *const _,
0,
);
let wm_take_focus = XInternAtom(
display,
b"WM_TAKE_FOCUS\0".as_ptr() as *const _,
0,
);
let net_supported = XInternAtom(
display,
b"_NET_SUPPORTED\0".as_ptr() as *const _,
0,
);
let net_active_window = XInternAtom(
display,
b"_NET_ACTIVE_WINDOW\0".as_ptr() as *const _,
0,
);
let net_client_list = XInternAtom(
display,
b"_NET_CLIENT_LIST\0".as_ptr() as *const _,
0,
);
let net_wm_name = XInternAtom(
display,
b"_NET_WM_NAME\0".as_ptr() as *const _,
0,
);
let net_wm_state = XInternAtom(
display,
b"_NET_WM_STATE\0".as_ptr() as *const _,
0,
);
let net_wm_state_fullscreen = XInternAtom(
display,
b"_NET_WM_STATE_FULLSCREEN\0".as_ptr() as *const _,
0,
);
let net_wm_window_type = XInternAtom(
display,
b"_NET_WM_WINDOW_TYPE\0".as_ptr() as *const _,
0,
);
let net_wm_window_type_dialog = XInternAtom(
display,
b"_NET_WM_WINDOW_TYPE_DIALOG\0".as_ptr() as *const _,
0,
);
Atoms {
wm_protocols,
wm_state,
wm_delete_window,
wm_take_focus,
net_supported,
net_active_window,
net_client_list,
net_wm_name,
net_wm_state,
net_wm_state_fullscreen,
net_wm_window_type,
net_wm_window_type_dialog,
}
}
}
fn update_modifier_state(
&mut self,
keyevent: &x11::xlib::XKeyEvent,
) {
//keyevent.keycode
let keysym = self.keyev_to_keysym(keyevent);
use x11::keysym::*;
let modifier = match keysym as u32 {
XK_Shift_L | XK_Shift_R => Some(ModifierKey::Shift),
XK_Control_L | XK_Control_R => Some(ModifierKey::Control),
XK_Alt_L | XK_Alt_R => Some(ModifierKey::Alt),
XK_ISO_Level3_Shift => Some(ModifierKey::AltGr),
XK_Caps_Lock => Some(ModifierKey::ShiftLock),
XK_Num_Lock => Some(ModifierKey::NumLock),
XK_Win_L | XK_Win_R => Some(ModifierKey::Super),
XK_Super_L | XK_Super_R => Some(ModifierKey::Super),
_ => None,
};
if let Some(modifier) = modifier {
match keyevent.type_ {
KeyPress => {
self.modifier_state.set_modifier(modifier)
}
KeyRelease => {
self.modifier_state.unset_modifier(modifier)
}
_ => unreachable!(
"keyyevent != (KeyPress | KeyRelease)"
),
}
}
}
fn keyev_to_keysym(&self, keyev: &XKeyEvent) -> u32 {
unsafe {
XLookupKeysym(keyev as *const _ as *mut _, 0) as u32
}
}
pub fn next_event(&self) -> XEvent {
unsafe {
let mut event = std::mem::MaybeUninit::zeroed();
XNextEvent(self.display, event.as_mut_ptr());
event.assume_init()
}
}
/// should probabbly make this use some variable that the user can chose for selected events.
fn map_window(&self, window: Window) {
unsafe {
XMapWindow(self.display, window);
XSelectInput(
self.display,
window,
EnterWindowMask
| FocusChangeMask
| PropertyChangeMask
| StructureNotifyMask,
);
}
}
fn select_input(&self, window: Window) {
unsafe {
XSelectInput(
self.display,
window,
EnterWindowMask
| FocusChangeMask
| PropertyChangeMask
| StructureNotifyMask
| ButtonPressMask
| ButtonReleaseMask
| KeyPressMask
| KeyReleaseMask,
);
}
}
fn configure_window(
&self,
window: Window,
event: &ConfigureEvent,
) {
unsafe {
let mut wc =
std::mem::MaybeUninit::<XWindowChanges>::zeroed()
.assume_init();
wc.x = event.position[0];
wc.y = event.position[1];
wc.width = event.size[0];
wc.height = event.size[1];
XConfigureWindow(
self.display,
window,
(1 << 4) - 1,
&mut wc,
);
}
}
fn handle_window_event(&mut self, event: WindowEvent) {
match event {
WindowEvent::MapEvent { window, .. } => {
self.map_window(window);
}
WindowEvent::ConfigureEvent { window, event } => {
self.configure_window(window, &event);
}
_ => {}
}
}
fn grab_key(&self, keycode: VirtualKeyCode) {
unsafe {
XGrabKey(
self.display,
XKeysymToKeycode(
self.display,
virtual_keycode_to_keysym(keycode).unwrap()
as u64,
) as i32,
AnyModifier,
self.root_window(),
1,
GrabModeAsync,
GrabModeAsync,
);
}
}
fn grab_button(&self, button: MouseButton) {
unsafe {
XGrabButton(
self.display,
mouse_button_to_xbutton(button) as u32,
AnyModifier,
self.root_window(),
1,
(ButtonPressMask | ButtonReleaseMask) as u32,
GrabModeAsync,
GrabModeAsync,
0,
0,
);
}
}
fn next_window_event(&mut self) -> WindowEvent {
loop {
let event = self.next_event();
match event.get_type() {
KeyPress | KeyRelease => {
let key_ev: &XKeyEvent = event.as_ref();
self.update_modifier_state(key_ev);
let keycode = keysym_to_virtual_keycode(
self.keyev_to_keysym(event.as_ref()),
);
if let Some(keycode) = keycode {
return WindowEvent::KeyEvent {
window: key_ev.subwindow,
event: KeyEvent::new(
match event.get_type() {
KeyPress => KeyState::Pressed,
KeyRelease => KeyState::Released,
_ => unreachable!(),
},
keycode,
self.modifier_state.clone(),
),
};
}
}
ButtonPress | ButtonRelease => {
let button_ev: &XButtonEvent = event.as_ref();
let button = xev_to_mouse_button(button_ev);
if let Some(button) = button {
return WindowEvent::ButtonEvent {
window: button_ev.subwindow,
event: ButtonEvent::new(
match event.get_type() {
ButtonPress => KeyState::Pressed,
ButtonRelease => {
KeyState::Released
}
_ => unreachable!(),
},
button,
self.modifier_state.clone(),
),
};
}
}
MotionNotify => {
let motion_ev: &XMotionEvent = event.as_ref();
return WindowEvent::MotionEvent {
window: motion_ev.subwindow,
event: MotionEvent::new([
motion_ev.x_root,
motion_ev.y_root,
]),
};
}
MapRequest => {
// MapEvent
let map_ev: &XMapRequestEvent = event.as_ref();
return WindowEvent::MapEvent {
window: map_ev.window,
event: MapEvent::new(map_ev.window),
};
}
MapNotify => {
// MapEvent
let map_ev: &XMapRequestEvent = event.as_ref();
return WindowEvent::MapEvent {
window: map_ev.window,
event: MapEvent::new(map_ev.window),
};
}
UnmapNotify => {
// UnmapEvent
let unmap_ev: &XUnmapEvent = event.as_ref();
return WindowEvent::UnmapEvent {
window: unmap_ev.window,
event: UnmapEvent::new(unmap_ev.window),
};
}
CreateNotify => {
// CreateEvent
let create_ev: &XCreateWindowEvent =
event.as_ref();
return WindowEvent::CreateEvent {
window: create_ev.window,
event: CreateEvent::new(
create_ev.window,
[create_ev.x, create_ev.y],
[create_ev.width, create_ev.height],
),
};
}
DestroyNotify => {
// DestroyEvent
let destroy_ev: &XDestroyWindowEvent =
event.as_ref();
return WindowEvent::DestroyEvent {
window: destroy_ev.window,
event: DestroyEvent::new(destroy_ev.window),
};
}
ConfigureRequest => {
// ConfigureEvent
let configure_ev: &XConfigureRequestEvent =
event.as_ref();
return WindowEvent::ConfigureEvent {
window: configure_ev.window,
event: ConfigureEvent::new(
configure_ev.window,
[configure_ev.x, configure_ev.y],
[configure_ev.width, configure_ev.height],
),
};
}
ClientMessage => {
let msg_ev: &XClientMessageEvent = event.as_ref();
// not sure?
}
PropertyNotify => {
let property_ev: &XPropertyEvent = event.as_ref();
if property_ev.atom
== self.atoms.net_wm_state_fullscreen
{
return WindowEvent::FullscreenEvent {
window: property_ev.window,
event: FullscreenEvent::new(
property_ev.state == PropertyNewValue,
),
};
}
}
_ => {}
}
}
}
}
#[cfg(test)]
mod tests {
use x11::xlib::{
XBlackPixel, XCreateSimpleWindow, XCreateWindow,
XDefaultScreen,
};
use super::*;
#[test]
fn window_events() {
let mut xlib = XLib::new();
//xlib.grab_key(VirtualKeyCode::A);
let window = unsafe {
//XCreateWindow(xlib.display, , 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
let black_pixel = XBlackPixel(
xlib.display,
XDefaultScreen(xlib.display),
);
let window = XCreateSimpleWindow(
xlib.display,
xlib.root_window(),
10,
10,
100,
100,
1,
black_pixel,
black_pixel,
);
XMapWindow(xlib.display, window);
xlib.select_input(window);
window
};
loop {
let event = xlib.next_window_event();
println!("{:#?}", event);
}
}
//#[test]
// fn window_events() {
// let mut xlib = XLib::new();
// loop {
// if let Some(event) =
// xlib.xevent_to_window_event(xlib.next_event())
// {
// println!("{:#?}", event);
// }
// }
// }
}

481
src/client_logic.rs Normal file
View file

@ -0,0 +1,481 @@
#![allow(dead_code)]
use crate::clients2::*;
use std::hash::Hash;
pub struct Size<T> {
width: T,
height: T,
}
impl<T> Size<T> {
pub fn new(width: T, height: T) -> Self {
Self { width, height }
}
/// Get a reference to the size's width.
pub fn width(&self) -> &T {
&self.width
}
/// Get a reference to the size's height.
pub fn height(&self) -> &T {
&self.height
}
/// Get a mutable reference to the size's width.
pub fn width_mut(&mut self) -> &mut T {
&mut self.width
}
/// Get a mutable reference to the size's height.
pub fn height_mut(&mut self) -> &mut T {
&mut self.height
}
}
impl<T> Size<T>
where
T: Copy,
{
pub fn dimensions(&self) -> (T, T) {
(self.width, self.height)
}
}
pub struct Workspace<T>
where
T: Eq,
{
master: Vec<T>,
aux: Vec<T>,
}
pub struct WorkspaceStore<T>
where
T: Eq,
{
workspaces: Vec<Workspace<T>>,
current_indices: Vec<usize>,
previous_indices: Option<Vec<usize>>,
}
pub struct ClientManager<T>
where
T: Hash + Eq + Copy,
{
store: ClientStore<T>,
focused: Option<T>,
workspaces: WorkspaceStore<T>,
// config
gap: i32,
border_size: i32,
master_size: f32,
screen_size: Size<i32>,
// experimental
invalidated: std::collections::HashSet<T>,
}
impl<T> Default for Workspace<T>
where
T: Eq,
{
fn default() -> Self {
Self {
master: vec![],
aux: vec![],
}
}
}
impl<T> Default for WorkspaceStore<T>
where
T: Eq,
{
fn default() -> Self {
Self {
workspaces: vec![Default::default()],
current_indices: vec![0],
previous_indices: None,
}
}
}
impl<T> Default for ClientManager<T>
where
T: Hash + Eq + Copy,
{
fn default() -> Self {
Self {
store: Default::default(),
focused: None,
workspaces: Default::default(),
gap: 0,
border_size: 0,
master_size: 1.0,
screen_size: Size::new(1, 1),
invalidated: Default::default(),
}
}
}
enum WorkspaceEntry<T> {
Master(T),
Aux(T),
Vacant,
}
impl<T> Workspace<T>
where
T: Eq,
{
pub fn contains(&self, key: &T) -> bool {
self.aux.contains(key) || self.master.contains(key)
}
pub fn is_master(&self, key: &T) -> bool {
self.master.contains(key)
}
pub fn is_aux(&self, key: &T) -> bool {
self.aux.contains(key)
}
pub fn push(&mut self, key: T) {
self.aux.push(key);
}
pub fn remove(&mut self, key: &T) {
self.master.retain(|k| k != key);
self.aux.retain(|k| k != key);
}
pub fn entry(&self, key: &T) -> Workspace<&T> {
todo!()
}
}
impl<T> WorkspaceStore<T>
where
T: Eq,
{
pub fn new(num: usize) -> Self {
let mut workspaces = Vec::with_capacity(num);
workspaces.resize_with(num, Default::default);
Self {
workspaces,
..Default::default()
}
}
pub fn remove(&mut self, key: &T) {
self.iter_mut().for_each(|w| w.remove(key));
}
fn len(&self) -> usize {
self.workspaces.len()
}
fn get_current(&self) -> impl Iterator<Item = &Workspace<T>> {
self.current_indices
.iter()
.map(move |&i| &self.workspaces[i])
}
fn get_current_mut(
&mut self,
) -> impl Iterator<Item = &mut Workspace<T>> {
let current_indices = &self.current_indices;
self.workspaces
.iter_mut()
.enumerate()
.filter(move |(i, _)| current_indices.contains(i))
.map(|(_, w)| w)
}
fn iter_current_master(&self) -> impl Iterator<Item = &T> {
let current_indices = &self.current_indices;
self.workspaces
.iter()
.enumerate()
.filter(move |(i, _)| current_indices.contains(i))
.map(|(_, w)| w)
.flat_map(|w| w.master.iter())
}
fn iter_current_aux(&self) -> impl Iterator<Item = &T> {
let current_indices = &self.current_indices;
self.workspaces
.iter()
.enumerate()
.filter(move |(i, _)| current_indices.contains(i))
.map(|(_, w)| w)
.flat_map(|w| w.aux.iter())
}
fn iter_mut_current_master(
&mut self,
) -> impl Iterator<Item = &mut T> {
let current_indices = &self.current_indices;
self.workspaces
.iter_mut()
.enumerate()
.filter(move |(i, _)| current_indices.contains(i))
.map(|(_, w)| w)
.flat_map(|w| w.master.iter_mut())
}
fn iter_mut_current_aux(
&mut self,
) -> impl Iterator<Item = &mut T> {
let current_indices = &self.current_indices;
self.workspaces
.iter_mut()
.enumerate()
.filter(move |(i, _)| current_indices.contains(i))
.map(|(_, w)| w)
.flat_map(|w| w.aux.iter_mut())
}
fn iter(&self) -> impl Iterator<Item = &Workspace<T>> {
self.workspaces.iter()
}
fn iter_mut(
&mut self,
) -> impl Iterator<Item = &mut Workspace<T>> {
self.workspaces.iter_mut()
}
fn select_workspace(&mut self, idx: usize) {
let len = self.len();
self.previous_indices = Some(std::mem::replace(
&mut self.current_indices,
vec![idx % len],
));
}
fn toggle_additional_workspace(&mut self, idx: usize) {
let idx = idx % self.len();
if self.current_indices.contains(&idx) {
self.current_indices.retain(|&i| i != idx);
} else {
self.current_indices.push(idx);
}
}
fn select_workspaces<I>(&mut self, idx: I)
where
Vec<usize>: From<I>,
{
self.previous_indices = Some(std::mem::replace(
&mut self.current_indices,
idx.into(),
));
}
fn select_previous_workspaces(&mut self) {
if let Some(previous_indices) = &mut self.previous_indices {
std::mem::swap(
previous_indices,
&mut self.current_indices,
);
}
}
/// Rotate n times left
fn rotate_left(&mut self, n: usize) {
let len = self.len();
let rotate_index = |i| -> usize {
let a = n % len;
let b = i & len;
((b + len) - a) % len
};
self.select_workspaces(
self.current_indices
.iter()
.map(rotate_index)
.collect::<Vec<_>>(),
);
}
/// Rotate n times left
fn rotate_right(&mut self, n: usize) {
let len = self.len();
let rotate_index = |i| -> usize {
let a = n % len;
let b = i & len;
((b + len) + a) % len
};
self.select_workspaces(
self.current_indices
.iter()
.map(rotate_index)
.collect::<Vec<_>>(),
);
}
}
impl<T> ClientManager<T>
where
T: Hash + Eq + Copy,
{
pub fn new() -> Self {
Self::default()
}
pub fn with_gap(self, gap: i32) -> Self {
Self { gap, ..self }
}
pub fn with_border(self, border_size: i32) -> Self {
Self {
border_size,
..self
}
}
pub fn with_screen_size(self, screen_size: Size<i32>) -> Self {
Self {
screen_size,
..self
}
}
pub fn with_workspaces(self, num: usize) -> Self {
Self {
workspaces: WorkspaceStore::new(num),
..self
}
}
pub fn new_client(&mut self, client: Client<T>) {
let entry = self.store.insert(Entry::Tiled(client));
match entry {
Entry::Tiled(client) => {
self.workspaces
.get_current_mut()
.next()
.unwrap()
.push(client.window_id());
self.tile_clients()
}
_ => {}
}
}
pub fn remove_client(&mut self, key: &T) {
if let Some(id) = self.focused {
if id == *key {
self.focused = None;
}
}
match self.store.remove(key) {
// if the window was tiled, remove it from all workspaces and retile all clients
Entry::Tiled(_) => {
self.workspaces.remove(key);
self.tile_clients();
}
_ => {}
};
}
pub fn tile_clients(&mut self) {
let gap = self.gap;
let border = self.border_size;
let (width, height) = {
let dimensions = self.screen_size.dimensions();
(dimensions.0 - gap * 2, dimensions.1 - gap * 2)
};
let len_master =
self.workspaces.iter_current_master().count();
let len_aux = self.workspaces.iter_current_aux().count();
let width_master = match len_aux {
0 => width,
_ => width * (self.master_size / 2.0) as i32,
};
let width_aux = width - width_master;
let height_master = match len_master {
0 | 1 => height,
n => height / n as i32,
};
let height_aux = match len_aux {
0 | 1 => height,
n => height / n as i32,
};
for (i, id) in
self.workspaces.iter_mut_current_master().enumerate()
{
let size = (
width_master - gap * 2 - border * 2,
height_master - gap * 2 - border * 2,
);
let position =
(gap * 2, height_master * i as i32 + gap * 2);
if let Some(client) =
Option::<&mut Client<T>>::from(self.store.get_mut(id))
{
if *client.position() != position
|| *client.size() != size
{
*client.position_mut() = position;
*client.size_mut() = size;
self.invalidated.insert(*id);
}
}
}
for (i, id) in
self.workspaces.iter_mut_current_aux().enumerate()
{
let size = (
width_aux - gap * 2 - border * 2,
height_aux - gap * 2 - border * 2,
);
let position = (
width_master + gap * 2,
height_aux * i as i32 + gap * 2,
);
if let Some(client) =
Option::<&mut Client<T>>::from(self.store.get_mut(id))
{
if *client.position() != position
|| *client.size() != size
{
*client.position_mut() = position;
*client.size_mut() = size;
self.invalidated.insert(*id);
}
}
}
}
}

View file

@ -217,7 +217,8 @@ impl ClientState {
if client.is_transient()
&& self.contains(&client.transient_for.unwrap())
{
let transient = self.get(&client.transient_for.unwrap()).unwrap();
let transient =
self.get(&client.transient_for.unwrap()).unwrap();
client.position = {
(
@ -271,7 +272,9 @@ impl ClientState {
|| self.floating_clients.contains_key(&key)
}
pub fn iter_floating(&self) -> impl Iterator<Item = (&u64, &Client)> {
pub fn iter_floating(
&self,
) -> impl Iterator<Item = (&u64, &Client)> {
self.floating_clients.iter()
}
@ -283,32 +286,44 @@ impl ClientState {
.filter(move |&(k, _)| self.is_client_visible(k))
}
fn iter_all_clients(&self) -> impl Iterator<Item = (&u64, &Client)> {
fn iter_all_clients(
&self,
) -> impl Iterator<Item = (&u64, &Client)> {
self.floating_clients.iter().chain(self.clients.iter())
}
pub fn iter_hidden(&self) -> impl Iterator<Item = (&u64, &Client)> {
pub fn iter_hidden(
&self,
) -> impl Iterator<Item = (&u64, &Client)> {
self.iter_all_clients()
.filter(move |&(k, _)| !self.is_client_visible(k))
}
pub fn iter_transient(&self) -> impl Iterator<Item = (&u64, &Client)> {
pub fn iter_transient(
&self,
) -> impl Iterator<Item = (&u64, &Client)> {
self.iter_floating().filter(|&(_, c)| c.is_transient())
}
pub fn iter_visible(&self) -> impl Iterator<Item = (&u64, &Client)> {
pub fn iter_visible(
&self,
) -> impl Iterator<Item = (&u64, &Client)> {
self.iter_all_clients()
.filter(move |&(k, _)| self.is_client_visible(k))
}
#[allow(dead_code)]
pub fn iter_current_screen(&self) -> impl Iterator<Item = (&u64, &Client)> {
pub fn iter_current_screen(
&self,
) -> impl Iterator<Item = (&u64, &Client)> {
self.clients.iter().filter(move |&(k, _)| {
self.virtual_screens.get_current().contains(k)
})
}
pub fn iter_master_stack(&self) -> impl Iterator<Item = (&u64, &Client)> {
pub fn iter_master_stack(
&self,
) -> impl Iterator<Item = (&u64, &Client)> {
self.virtual_screens
.get_current()
.master
@ -316,7 +331,9 @@ impl ClientState {
.map(move |k| (k, self.get(k).unwrap()))
}
pub fn iter_aux_stack(&self) -> impl Iterator<Item = (&u64, &Client)> {
pub fn iter_aux_stack(
&self,
) -> impl Iterator<Item = (&u64, &Client)> {
self.virtual_screens
.get_current()
.aux
@ -441,12 +458,15 @@ impl ClientState {
// transient clients cannot be tiled
match floating_client.is_transient() {
true => {
self.floating_clients.insert(key, floating_client);
self.floating_clients
.insert(key, floating_client);
}
false => {
self.clients.insert(key, floating_client);
self.virtual_screens.get_mut_current().insert(&key);
self.virtual_screens
.get_mut_current()
.insert(&key);
}
}
}
@ -464,7 +484,9 @@ impl ClientState {
K: ClientKey,
{
if self.contains(key) {
if let Some(vs) = self.get_mut_virtualscreen_for_client(key) {
if let Some(vs) =
self.get_mut_virtualscreen_for_client(key)
{
vs.remove(key);
// we removed a client so the layout changed, rearrange
@ -473,7 +495,10 @@ impl ClientState {
}
}
fn get_virtualscreen_for_client<K>(&self, key: &K) -> Option<&VirtualScreen>
fn get_virtualscreen_for_client<K>(
&self,
key: &K,
) -> Option<&VirtualScreen>
where
K: ClientKey,
{
@ -502,7 +527,10 @@ impl ClientState {
})
}
pub fn get_stack_for_client<K>(&self, key: &K) -> Option<&Vec<u64>>
pub fn get_stack_for_client<K>(
&self,
key: &K,
) -> Option<&Vec<u64>>
where
K: ClientKey,
{
@ -637,7 +665,8 @@ impl ClientState {
self.master_size / 2.0
};
let master_width = (effective_width as f32 * master_size) as i32;
let master_width =
(effective_width as f32 * master_size) as i32;
let aux_width = effective_width - master_width;
(master_width, aux_width)
@ -665,7 +694,8 @@ impl ClientState {
master_height - gap * 2 - self.border_size * 2,
);
let position = (gap * 2, master_height * i as i32 + gap * 2);
let position =
(gap * 2, master_height * i as i32 + gap * 2);
if let Some(client) = self.clients.get_mut(key) {
*client = Client {
@ -683,8 +713,10 @@ impl ClientState {
aux_height - gap * 2 - self.border_size * 2,
);
let position =
(master_width + gap * 2, aux_height * i as i32 + gap * 2);
let position = (
master_width + gap * 2,
aux_height * i as i32 + gap * 2,
);
if let Some(client) = self.clients.get_mut(key) {
*client = Client {
@ -720,7 +752,8 @@ impl VirtualScreen {
where
K: ClientKey,
{
self.master.contains(&key.key()) || self.aux.contains(&key.key())
self.master.contains(&key.key())
|| self.aux.contains(&key.key())
}
fn is_in_master<K>(&self, key: &K) -> bool
@ -766,8 +799,11 @@ impl VirtualScreen {
self.aux.extend(self.master.drain(index..=index));
}
None => {
let index =
self.aux.iter().position(|&k| k == key.key()).unwrap();
let index = self
.aux
.iter()
.position(|&k| k == key.key())
.unwrap();
self.master.extend(self.aux.drain(index..=index));
}
}
@ -814,7 +850,9 @@ impl VirtualScreenStore {
self.screens.iter()
}
fn iter_mut(&mut self) -> impl Iterator<Item = &mut VirtualScreen> {
fn iter_mut(
&mut self,
) -> impl Iterator<Item = &mut VirtualScreen> {
self.screens.iter_mut()
}
@ -861,7 +899,9 @@ 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),
Self::Tiled(client) | Self::Floating(client) => {
Some(client)
}
}
}
}

409
src/clients2.rs Normal file
View file

@ -0,0 +1,409 @@
#![allow(dead_code)]
use std::{borrow::Borrow, hash::Hash};
/// Client structure.
#[derive(Clone, Debug)]
pub struct Client<T> {
window_id: T,
size: (i32, i32),
position: (i32, i32),
transient_for: Option<T>,
}
#[derive(Debug, PartialEq, Eq)]
pub enum Entry<T> {
Tiled(T),
Floating(T),
Transient(T),
Fullscreen(T),
Vacant,
}
type ClientSet<T> = indexmap::IndexMap<T, Client<T>>;
//type ClientSet<T> = std::collections::HashMap<T, Client<T>>;
pub struct ClientStore<T>
where
T: Hash + Eq,
{
tiled_clients: ClientSet<T>,
floating_clients: ClientSet<T>,
transient_clients: ClientSet<T>,
fullscreen_clients: ClientSet<T>,
}
impl<T> PartialEq for Client<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.window_id == other.window_id
}
}
impl<T> Eq for Client<T> where T: Eq {}
impl<T> PartialOrd for Client<T>
where
T: PartialOrd,
{
fn partial_cmp(
&self,
other: &Self,
) -> Option<std::cmp::Ordering> {
self.window_id.partial_cmp(&other.window_id)
}
}
impl<T> Ord for Client<T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.window_id.cmp(&other.window_id)
}
}
impl<T> Hash for Client<T>
where
T: Hash,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.window_id.hash(state)
}
}
impl<T> Borrow<T> for Client<T> {
fn borrow(&self) -> &T {
&self.window_id
}
}
impl<T> Client<T> {
pub fn new(window_id: T) -> Self {
Self {
window_id,
size: (100, 100),
position: (0, 0),
transient_for: None,
}
}
pub fn window_id_ref(&self) -> &T {
&self.window_id
}
/// Get a mutable reference to the client's size.
pub fn size_mut(&mut self) -> &mut (i32, i32) {
&mut self.size
}
/// Get a mutable reference to the client's position.
pub fn position_mut(&mut self) -> &mut (i32, i32) {
&mut self.position
}
/// Get a reference to the client's size.
pub fn size(&self) -> &(i32, i32) {
&self.size
}
/// Get a reference to the client's position.
pub fn position(&self) -> &(i32, i32) {
&self.position
}
}
impl<T> Client<T>
where
T: Copy,
{
pub fn window_id(&self) -> T {
self.window_id
}
}
impl<T> From<Entry<T>> for Option<T> {
fn from(entry: Entry<T>) -> Self {
match entry {
Entry::Floating(c)
| Entry::Tiled(c)
| Entry::Fullscreen(c)
| Entry::Transient(c) => Some(c),
_ => None,
}
}
}
impl<'a, T> From<&'a Entry<T>> for Option<&'a T> {
fn from(entry: &'a Entry<T>) -> Self {
match entry {
Entry::Floating(c)
| Entry::Tiled(c)
| Entry::Fullscreen(c)
| Entry::Transient(c) => Some(c),
_ => None,
}
}
}
impl<'a, T> From<&'a mut Entry<T>> for Option<&'a mut T> {
fn from(entry: &'a mut Entry<T>) -> Self {
match entry {
Entry::Floating(c)
| Entry::Tiled(c)
| Entry::Fullscreen(c)
| Entry::Transient(c) => Some(c),
_ => None,
}
}
}
impl<T> From<Option<Entry<T>>> for Entry<T> {
fn from(opt: Option<Entry<T>>) -> Self {
match opt {
Some(entry) => entry,
None => Entry::Vacant,
}
}
}
impl<T> Entry<T> {
pub fn unwrap(self) -> T {
Option::<T>::from(self).unwrap()
}
pub fn unwrap_ref(&self) -> &T {
Option::<&T>::from(self).unwrap()
}
pub fn unwrap_mut(&mut self) -> &mut T {
Option::<&mut T>::from(self).unwrap()
}
pub fn is_floating(&self) -> bool {
match self {
Self::Floating(_) => true,
_ => false,
}
}
pub fn is_tiled(&self) -> bool {
match self {
Self::Tiled(_) => true,
_ => false,
}
}
pub fn is_transient(&self) -> bool {
match self {
Self::Transient(_) => true,
_ => false,
}
}
pub fn is_fullscreen(&self) -> bool {
match self {
Self::Fullscreen(_) => true,
_ => false,
}
}
}
impl<T> Default for ClientStore<T>
where
T: Hash + Eq,
{
fn default() -> Self {
Self {
tiled_clients: Default::default(),
floating_clients: Default::default(),
transient_clients: Default::default(),
fullscreen_clients: Default::default(),
}
}
}
impl<T> ClientStore<T>
where
T: Hash + Eq + Copy,
{
pub fn new() -> Self {
Self::default()
}
pub fn insert(
&mut self,
entry: Entry<Client<T>>,
) -> Entry<&Client<T>> {
if let Some(key) =
Option::<&Client<T>>::from(&entry).map(|c| c.window_id())
{
match entry {
Entry::Floating(client) => {
self.floating_clients.insert(key, client);
}
Entry::Tiled(client) => {
self.tiled_clients.insert(key, client);
}
Entry::Transient(client) => {
self.transient_clients.insert(key, client);
}
Entry::Fullscreen(client) => {
self.fullscreen_clients.insert(key, client);
}
_ => unreachable!(),
}
self.get(&key).into()
} else {
Entry::Vacant
}
}
pub fn remove(&mut self, key: &T) -> Entry<Client<T>> {
if let Some(client) = self.tiled_clients.remove(key) {
Entry::Tiled(client)
} else if let Some(client) = self.floating_clients.remove(key)
{
Entry::Floating(client)
} else if let Some(client) =
self.transient_clients.remove(key)
{
Entry::Transient(client)
} else if let Some(client) =
self.fullscreen_clients.remove(key)
{
Entry::Fullscreen(client)
} else {
Entry::Vacant
}
}
pub fn get(&self, key: &T) -> Entry<&Client<T>> {
if let Some(client) = self.tiled_clients.get(key) {
Entry::Tiled(client)
} else if let Some(client) = self.floating_clients.get(key) {
Entry::Floating(client)
} else if let Some(client) = self.transient_clients.get(key) {
Entry::Transient(client)
} else if let Some(client) = self.fullscreen_clients.get(key)
{
Entry::Fullscreen(client)
} else {
Entry::Vacant
}
}
pub fn get_mut(&mut self, key: &T) -> Entry<&mut Client<T>> {
if let Some(client) = self.tiled_clients.get_mut(key) {
Entry::Tiled(client)
} else if let Some(client) =
self.floating_clients.get_mut(key)
{
Entry::Floating(client)
} else if let Some(client) =
self.transient_clients.get_mut(key)
{
Entry::Transient(client)
} else if let Some(client) =
self.fullscreen_clients.get_mut(key)
{
Entry::Fullscreen(client)
} else {
Entry::Vacant
}
}
pub fn contains(&self, key: &T) -> bool {
self.tiled_clients.contains_key(key)
|| self.floating_clients.contains_key(key)
|| self.transient_clients.contains_key(key)
|| self.fullscreen_clients.contains_key(key)
}
pub fn iter_tiled(
&self,
) -> impl Iterator<Item = (&T, &Client<T>)> {
self.tiled_clients.iter()
}
pub fn iter_mut_tiled(
&mut self,
) -> impl Iterator<Item = (&T, &mut Client<T>)> {
self.tiled_clients.iter_mut()
}
pub fn iter_floating(
&self,
) -> impl Iterator<Item = (&T, &Client<T>)> {
self.floating_clients.iter()
}
pub fn iter_mut_floating(
&mut self,
) -> impl Iterator<Item = (&T, &mut Client<T>)> {
self.floating_clients.iter_mut()
}
pub fn iter_transient(
&self,
) -> impl Iterator<Item = (&T, &Client<T>)> {
self.transient_clients.iter()
}
pub fn iter_mut_transient(
&mut self,
) -> impl Iterator<Item = (&T, &mut Client<T>)> {
self.transient_clients.iter_mut()
}
pub fn iter_fullscreen(
&self,
) -> impl Iterator<Item = (&T, &Client<T>)> {
self.fullscreen_clients.iter()
}
pub fn iter_mut_fullscreen(
&mut self,
) -> impl Iterator<Item = (&T, &mut Client<T>)> {
self.fullscreen_clients.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clientstore_insert_contain() {
let client = Client::new(1u64);
let mut client_store = ClientStore::new();
client_store.insert(Entry::Tiled(client.clone()));
assert!(client_store.contains(client.borrow()));
assert!(client_store.contains(&1));
let client2 = Client::new(3u64);
client_store.insert(Entry::Floating(client2.clone()));
assert!(client_store.contains(&client.borrow()));
assert!(client_store.contains(&1));
assert!(client_store.contains(&client2.borrow()));
assert!(client_store.contains(&3));
assert_eq!(
Entry::Tiled(client.clone()),
client_store.remove(&client.borrow())
);
assert_eq!(
Entry::Vacant,
client_store.remove(&client.borrow())
);
assert_eq!(Entry::Vacant, client_store.remove(&1));
assert!(client_store.contains(&client2.borrow()));
}
}

View file

@ -7,6 +7,11 @@ use log4rs::{
};
use state::WMConfig;
#[macro_use]
extern crate num_derive;
mod backends;
mod client_logic;
mod clients;
mod clients2;
mod state;
@ -18,9 +23,11 @@ fn init_logger() {
"{d(%Y-%m-%d %H:%M:%S %Z)(utc)} │ {({M}::{f}:{L}):>25} │ {h({l:>5})} │ {m}{n}",
));
let stdout = ConsoleAppender::builder().encoder(encoder.clone()).build();
let stdout =
ConsoleAppender::builder().encoder(encoder.clone()).build();
let home = dirs::home_dir().expect("Failed to get $HOME env var.");
let home =
dirs::home_dir().expect("Failed to get $HOME env var.");
let _logfile = FileAppender::builder()
.encoder(encoder)
@ -28,7 +35,9 @@ fn init_logger() {
.unwrap();
let config = Config::builder()
.appender(Appender::builder().build("stdout", Box::new(stdout)))
.appender(
Appender::builder().build("stdout", Box::new(stdout)),
)
//.appender(Appender::builder().build("logfile", Box::new(logfile)))
.build(
Root::builder()

View file

@ -151,7 +151,9 @@ impl WindowManager {
.get_focused()
.into_option()
.map(|c| c.key())
.and_then(|k| Some(wm.clients.toggle_floating(&k)));
.and_then(|k| {
Some(wm.clients.toggle_floating(&k))
});
wm.arrange_clients();
},
@ -224,15 +226,24 @@ impl WindowManager {
}
fn add_vs_switch_keybinds(&mut self) {
fn rotate_west<const N: usize>(wm: &mut WindowManager, _: &XKeyEvent) {
fn rotate_west<const N: usize>(
wm: &mut WindowManager,
_: &XKeyEvent,
) {
wm.rotate_virtual_screen(Direction::West(N));
}
fn rotate_east<const N: usize>(wm: &mut WindowManager, _: &XKeyEvent) {
fn rotate_east<const N: usize>(
wm: &mut WindowManager,
_: &XKeyEvent,
) {
wm.rotate_virtual_screen(Direction::East(N));
}
fn goto_nth<const N: usize>(wm: &mut WindowManager, _: &XKeyEvent) {
fn goto_nth<const N: usize>(
wm: &mut WindowManager,
_: &XKeyEvent,
) {
wm.go_to_nth_virtual_screen(N)
}
@ -333,13 +344,23 @@ impl WindowManager {
match event.get_type() {
xlib::MapRequest => self.map_request(&event),
xlib::UnmapNotify => self.unmap_notify(&event),
xlib::ConfigureRequest => self.configure_request(&event),
xlib::ConfigureRequest => {
self.configure_request(&event)
}
xlib::EnterNotify => self.enter_notify(&event),
xlib::DestroyNotify => self.destroy_notify(&event),
xlib::ButtonPress => self.button_press(event.as_ref()),
xlib::ButtonRelease => self.button_release(event.as_ref()),
xlib::MotionNotify => self.motion_notify(event.as_ref()),
xlib::KeyPress => self.handle_keybinds(event.as_ref()),
xlib::ButtonPress => {
self.button_press(event.as_ref())
}
xlib::ButtonRelease => {
self.button_release(event.as_ref())
}
xlib::MotionNotify => {
self.motion_notify(event.as_ref())
}
xlib::KeyPress => {
self.handle_keybinds(event.as_ref())
}
_ => {}
}
}
@ -354,7 +375,8 @@ impl WindowManager {
}
fn kill_client(&mut self, _event: &XKeyEvent) {
if let Some(client) = self.clients.get_focused().into_option() {
if let Some(client) = self.clients.get_focused().into_option()
{
self.xlib.kill_client(client);
}
}
@ -365,7 +387,8 @@ impl WindowManager {
for kb in self.keybinds.clone().into_iter() {
if let KeyOrButton::Key(keycode, modmask) = kb.key {
if keycode as u32 == event.keycode
&& modmask & clean_mask == event.state & clean_mask
&& modmask & clean_mask
== event.state & clean_mask
{
(kb.closure)(self, event);
}
@ -409,8 +432,12 @@ impl WindowManager {
fn focus_any(&mut self) {
// focus first client in all visible clients
let to_focus =
self.clients.iter_visible().next().map(|(k, _)| k).cloned();
let to_focus = self
.clients
.iter_visible()
.next()
.map(|(k, _)| k)
.cloned();
if let Some(key) = to_focus {
self.focus_client(&key, false);
@ -418,7 +445,8 @@ impl WindowManager {
}
fn focus_master_stack(&mut self) {
let focused = self.clients.get_focused().into_option().map(|c| c.key());
let focused =
self.clients.get_focused().into_option().map(|c| c.key());
let k = self
.clients
@ -436,7 +464,8 @@ impl WindowManager {
}
fn focus_aux_stack(&mut self) {
let focused = self.clients.get_focused().into_option().map(|c| c.key());
let focused =
self.clients.get_focused().into_option().map(|c| c.key());
let k = self
.clients
@ -454,12 +483,12 @@ impl WindowManager {
}
fn focus_up(&mut self) {
let focused = self.clients.get_focused().into_option().map(|c| c.key());
let focused =
self.clients.get_focused().into_option().map(|c| c.key());
let k = focused.and_then(|focused| {
self.clients
.get_stack_for_client(&focused)
.and_then(|stack| {
self.clients.get_stack_for_client(&focused).and_then(
|stack| {
stack
.iter()
.rev()
@ -467,7 +496,8 @@ impl WindowManager {
.skip(1)
.next()
.cloned()
})
},
)
});
if let Some(k) = k {
@ -476,19 +506,20 @@ impl WindowManager {
}
fn focus_down(&mut self) {
let focused = self.clients.get_focused().into_option().map(|c| c.key());
let focused =
self.clients.get_focused().into_option().map(|c| c.key());
let k = focused.and_then(|focused| {
self.clients
.get_stack_for_client(&focused)
.and_then(|stack| {
self.clients.get_stack_for_client(&focused).and_then(
|stack| {
stack
.iter()
.skip_while(|&&k| k != focused)
.skip(1)
.next()
.cloned()
})
},
)
});
if let Some(k) = k {
@ -573,7 +604,9 @@ impl WindowManager {
{
Client::new_transient(
window,
self.xlib.get_window_size(window).unwrap_or((100, 100)),
self.xlib
.get_window_size(window)
.unwrap_or((100, 100)),
transient_window,
)
} else {
@ -632,7 +665,10 @@ impl WindowManager {
}
/// ensure event.subwindow refers to a valid client.
fn start_move_resize_window(&mut self, event: &XButtonPressedEvent) {
fn start_move_resize_window(
&mut self,
event: &XButtonPressedEvent,
) {
let window = event.subwindow;
match event.button {
@ -641,15 +677,16 @@ impl WindowManager {
self.arrange_clients();
}
self.move_resize_window = MoveResizeInfo::Move(MoveInfoInner {
window,
starting_cursor_pos: (event.x, event.y),
starting_window_pos: self
.clients
.get(&window)
.unwrap()
.position,
});
self.move_resize_window =
MoveResizeInfo::Move(MoveInfoInner {
window,
starting_cursor_pos: (event.x, event.y),
starting_window_pos: self
.clients
.get(&window)
.unwrap()
.position,
});
}
3 => {
if self.clients.set_floating(&window) {
@ -679,7 +716,10 @@ impl WindowManager {
}
}
fn end_move_resize_window(&mut self, event: &XButtonReleasedEvent) {
fn end_move_resize_window(
&mut self,
event: &XButtonReleasedEvent,
) {
if event.button == 1 || event.button == 3 {
self.move_resize_window = MoveResizeInfo::None;
}
@ -718,8 +758,14 @@ impl WindowManager {
{
let size = &mut client.size;
size.0 = std::cmp::max(1, info.starting_window_size.0 + x);
size.1 = std::cmp::max(1, info.starting_window_size.1 + y);
size.0 = std::cmp::max(
1,
info.starting_window_size.0 + x,
);
size.1 = std::cmp::max(
1,
info.starting_window_size.1 + y,
);
self.xlib.resize_client(client);
}
@ -734,10 +780,12 @@ impl WindowManager {
match event.button {
1 | 3 => match self.move_resize_window {
MoveResizeInfo::None
if self
.xlib
.are_masks_equal(event.state, self.config.mod_key)
&& self.clients.contains(&event.subwindow) =>
if self.xlib.are_masks_equal(
event.state,
self.config.mod_key,
) && self
.clients
.contains(&event.subwindow) =>
{
self.start_move_resize_window(event)
}

View file

@ -4,14 +4,16 @@ use std::{ffi::CString, rc::Rc};
use x11::xlib::{
self, AnyButton, AnyKey, AnyModifier, Atom, ButtonPressMask,
ButtonReleaseMask, CWEventMask, ControlMask, CurrentTime, EnterWindowMask,
FocusChangeMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask,
Mod5Mask, PointerMotionMask, PropertyChangeMask, ShiftMask,
StructureNotifyMask, SubstructureNotifyMask, SubstructureRedirectMask,
Window, XCloseDisplay, XConfigureRequestEvent, XDefaultScreen, XEvent,
XGetTransientForHint, XGrabPointer, XInternAtom, XKillClient, XMapWindow,
XOpenDisplay, XRaiseWindow, XRootWindow, XSetErrorHandler, XSync,
XUngrabButton, XUngrabKey, XUngrabPointer, XWarpPointer, XWindowAttributes,
ButtonReleaseMask, CWEventMask, ControlMask, CurrentTime,
EnterWindowMask, FocusChangeMask, LockMask, Mod1Mask, Mod2Mask,
Mod3Mask, Mod4Mask, Mod5Mask, PointerMotionMask,
PropertyChangeMask, ShiftMask, StructureNotifyMask,
SubstructureNotifyMask, SubstructureRedirectMask, Window,
XCloseDisplay, XConfigureRequestEvent, XDefaultScreen, XEvent,
XGetTransientForHint, XGrabPointer, XInternAtom, XKillClient,
XMapWindow, XOpenDisplay, XRaiseWindow, XRootWindow,
XSetErrorHandler, XSync, XUngrabButton, XUngrabKey,
XUngrabPointer, XWarpPointer, XWindowAttributes,
};
use xlib::GrabModeAsync;
@ -45,7 +47,11 @@ impl KeyOrButton {
pub fn key(keycode: i32, modmask: u32) -> Self {
Self::Key(keycode, modmask)
}
pub fn button(button: u32, modmask: u32, buttonmask: i64) -> Self {
pub fn button(
button: u32,
modmask: u32,
buttonmask: i64,
) -> Self {
Self::Button(button, modmask, buttonmask as u64)
}
}
@ -78,9 +84,10 @@ impl XLib {
pub fn init(&mut self) {
unsafe {
let mut window_attributes =
std::mem::MaybeUninit::<xlib::XSetWindowAttributes>::zeroed()
.assume_init();
let mut window_attributes = std::mem::MaybeUninit::<
xlib::XSetWindowAttributes,
>::zeroed()
.assume_init();
window_attributes.event_mask = SubstructureRedirectMask
| StructureNotifyMask
@ -117,7 +124,12 @@ impl XLib {
#[allow(dead_code)]
fn ungrab_global_keybings(&self, window: Window) {
unsafe {
XUngrabButton(self.dpy(), AnyButton as u32, AnyModifier, window);
XUngrabButton(
self.dpy(),
AnyButton as u32,
AnyModifier,
window,
);
XUngrabKey(self.dpy(), AnyKey, AnyModifier, window);
}
}
@ -143,10 +155,14 @@ impl XLib {
pub fn squash_event(&self, event_type: i32) -> XEvent {
unsafe {
let mut event =
std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init();
std::mem::MaybeUninit::<xlib::XEvent>::zeroed()
.assume_init();
while xlib::XCheckTypedEvent(self.dpy(), event_type, &mut event)
!= 0
while xlib::XCheckTypedEvent(
self.dpy(),
event_type,
&mut event,
) != 0
{}
event
@ -156,14 +172,19 @@ impl XLib {
pub fn next_event(&self) -> XEvent {
unsafe {
let mut event =
std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init();
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) {
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];
@ -212,7 +233,8 @@ impl XLib {
xlib::CurrentTime,
);
let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
let screen =
xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
if let Some(screen) = screen {
xlib::XSetWindowBorder(
@ -248,7 +270,8 @@ impl XLib {
xlib::CurrentTime,
);
let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
let screen =
xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
if let Some(screen) = screen {
xlib::XSetWindowBorder(
@ -284,8 +307,10 @@ impl XLib {
xlib::XConfigureWindow(
self.dpy(),
client.window,
(xlib::CWY | xlib::CWX | xlib::CWHeight | xlib::CWWidth)
as u32,
(xlib::CWY
| xlib::CWX
| xlib::CWHeight
| xlib::CWWidth) as u32,
&mut windowchanges,
);
@ -376,14 +401,18 @@ impl XLib {
}
}
pub fn get_window_size(&self, window: Window) -> Option<(i32, i32)> {
pub fn get_window_size(
&self,
window: Window,
) -> Option<(i32, i32)> {
let mut wa = unsafe {
std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed()
.assume_init()
};
if unsafe {
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa)
!= 0
} {
Some((wa.width, wa.height))
} else {
@ -401,7 +430,8 @@ impl XLib {
};
if unsafe {
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa)
!= 0
} {
Some(wa)
} else {
@ -409,11 +439,18 @@ impl XLib {
}
}
pub fn get_transient_for_window(&self, window: Window) -> Option<Window> {
pub fn get_transient_for_window(
&self,
window: Window,
) -> Option<Window> {
let mut transient_for: Window = 0;
if unsafe {
XGetTransientForHint(self.dpy(), window, &mut transient_for) != 0
XGetTransientForHint(
self.dpy(),
window,
&mut transient_for,
) != 0
} {
Some(transient_for)
} else {
@ -515,13 +552,21 @@ impl XLib {
pub fn dimensions(&self) -> (i32, i32) {
unsafe {
let mut wa =
std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed()
.assume_init();
let mut wa = std::mem::MaybeUninit::<
xlib::XWindowAttributes,
>::zeroed()
.assume_init();
xlib::XGetWindowAttributes(self.dpy(), self.root, &mut wa);
xlib::XGetWindowAttributes(
self.dpy(),
self.root,
&mut wa,
);
info!("Root window dimensions: {}, {}", wa.width, wa.height);
info!(
"Root window dimensions: {}, {}",
wa.width, wa.height
);
(wa.width, wa.height)
}
@ -547,8 +592,9 @@ impl XLib {
self.dpy(),
self.root,
0,
(ButtonPressMask | ButtonReleaseMask | PointerMotionMask)
as u32,
(ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask) as u32,
GrabModeAsync,
GrabModeAsync,
0,
@ -564,7 +610,11 @@ impl XLib {
}
}
pub fn move_cursor(&self, window: Option<Window>, position: (i32, i32)) {
pub fn move_cursor(
&self,
window: Option<Window>,
position: (i32, i32),
) {
unsafe {
XWarpPointer(
self.dpy(),
@ -580,7 +630,11 @@ impl XLib {
}
}
fn check_for_protocol(&self, client: &Client, proto: xlib::Atom) -> bool {
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;
@ -603,7 +657,11 @@ impl XLib {
return false;
}
fn send_protocol(&self, client: &Client, proto: xlib::Atom) -> bool {
fn send_protocol(
&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);
@ -723,19 +781,37 @@ impl Atoms {
Self {
protocols: {
let name = CString::new("WM_PROTOCOLS").unwrap();
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0)
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)
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)
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)
XInternAtom(
display.get(),
name.as_c_str().as_ptr(),
0,
)
},
}
}