changed rustfmt to actually work hopefully (70 char limit)
also more abstraction stuff
This commit is contained in:
parent
98459d620c
commit
1b2e2d848c
|
@ -1,2 +1,2 @@
|
||||||
#wrap_comments = true
|
wrap_comments = true
|
||||||
max_width = 80
|
max_width = 70
|
209
src/backends/keycodes.rs
Normal file
209
src/backends/keycodes.rs
Normal 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,
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod keycodes;
|
||||||
|
mod window_event;
|
||||||
mod xcb;
|
mod xcb;
|
||||||
mod xlib;
|
mod xlib;
|
||||||
|
|
||||||
|
|
220
src/backends/window_event.rs
Normal file
220
src/backends/window_event.rs
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
#![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,
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
//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 {
|
||||||
|
window: Window,
|
||||||
|
position: [i32; 2],
|
||||||
|
size: [i32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigureEvent {
|
||||||
|
pub fn new(
|
||||||
|
window: Window,
|
||||||
|
position: [i32; 2],
|
||||||
|
size: [i32; 2],
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
window,
|
||||||
|
position,
|
||||||
|
size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,8 +12,8 @@ use x11rb::{
|
||||||
errors::ReplyError,
|
errors::ReplyError,
|
||||||
errors::ReplyOrIdError,
|
errors::ReplyOrIdError,
|
||||||
protocol::xproto::{
|
protocol::xproto::{
|
||||||
Atom, ChangeWindowAttributesAux, ConnectionExt, EventMask, Screen,
|
Atom, ChangeWindowAttributesAux, ConnectionExt, EventMask,
|
||||||
Setup,
|
Screen, Setup,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,12 +41,37 @@ mod tests {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
println!(
|
println!(
|
||||||
"keycode: {:#x?}\tkeysyms: {:0x?}",
|
"keycode: {:#?}\tkeysyms: {:0x?}",
|
||||||
xcb.setup().min_keycode as usize + i,
|
xcb.setup().min_keycode as usize + i,
|
||||||
keysyms
|
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)]
|
#[repr(u8)]
|
||||||
|
@ -205,24 +230,29 @@ impl Atoms {
|
||||||
where
|
where
|
||||||
C: Connection,
|
C: Connection,
|
||||||
{
|
{
|
||||||
let wm_protocols = connection.intern_atom(false, b"WM_PROTOCOLS")?;
|
let wm_protocols =
|
||||||
|
connection.intern_atom(false, b"WM_PROTOCOLS")?;
|
||||||
let wm_state = connection.intern_atom(false, b"WM_STATE")?;
|
let wm_state = connection.intern_atom(false, b"WM_STATE")?;
|
||||||
let wm_delete_window =
|
let wm_delete_window =
|
||||||
connection.intern_atom(false, b"WM_DELETE_WINDOW")?;
|
connection.intern_atom(false, b"WM_DELETE_WINDOW")?;
|
||||||
let wm_take_focus = connection.intern_atom(false, b"WM_TAKE_FOCUS")?;
|
let wm_take_focus =
|
||||||
let net_supported = connection.intern_atom(false, b"_NET_SUPPORTED")?;
|
connection.intern_atom(false, b"WM_TAKE_FOCUS")?;
|
||||||
|
let net_supported =
|
||||||
|
connection.intern_atom(false, b"_NET_SUPPORTED")?;
|
||||||
let net_active_window =
|
let net_active_window =
|
||||||
connection.intern_atom(false, b"_NET_ACTIVE_WINDOW")?;
|
connection.intern_atom(false, b"_NET_ACTIVE_WINDOW")?;
|
||||||
let net_client_list =
|
let net_client_list =
|
||||||
connection.intern_atom(false, b"_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_name =
|
||||||
let net_wm_state = connection.intern_atom(false, b"_NET_WM_STATE")?;
|
connection.intern_atom(false, b"_NET_WM_NAME")?;
|
||||||
let net_wm_state_fullscreen =
|
let net_wm_state =
|
||||||
connection.intern_atom(false, b"_NET_WM_STATE_FULLSCREEN")?;
|
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 =
|
let net_wm_window_type =
|
||||||
connection.intern_atom(false, b"_NET_WM_WINDOW_TYPE")?;
|
connection.intern_atom(false, b"_NET_WM_WINDOW_TYPE")?;
|
||||||
let net_wm_window_type_dialog =
|
let net_wm_window_type_dialog = connection
|
||||||
connection.intern_atom(false, b"_NET_WM_WINDOW_TYPE_DIALOG")?;
|
.intern_atom(false, b"_NET_WM_WINDOW_TYPE_DIALOG")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
wm_protocols: wm_protocols.reply()?.atom,
|
wm_protocols: wm_protocols.reply()?.atom,
|
||||||
|
@ -234,9 +264,13 @@ impl Atoms {
|
||||||
net_client_list: net_client_list.reply()?.atom,
|
net_client_list: net_client_list.reply()?.atom,
|
||||||
net_wm_name: net_wm_name.reply()?.atom,
|
net_wm_name: net_wm_name.reply()?.atom,
|
||||||
net_wm_state: net_wm_state.reply()?.atom,
|
net_wm_state: net_wm_state.reply()?.atom,
|
||||||
net_wm_state_fullscreen: net_wm_state_fullscreen.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: net_wm_window_type.reply()?.atom,
|
||||||
net_wm_window_type_dialog: net_wm_window_type_dialog.reply()?.atom,
|
net_wm_window_type_dialog: net_wm_window_type_dialog
|
||||||
|
.reply()?
|
||||||
|
.atom,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,9 +284,10 @@ where
|
||||||
atoms: Atoms,
|
atoms: Atoms,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_backend(
|
pub fn create_backend() -> Result<
|
||||||
) -> Result<X11Backend<impl Connection + Send + Sync>, Box<dyn std::error::Error>>
|
X11Backend<impl Connection + Send + Sync>,
|
||||||
{
|
Box<dyn std::error::Error>,
|
||||||
|
> {
|
||||||
let (connection, screen) = connect(None)?;
|
let (connection, screen) = connect(None)?;
|
||||||
|
|
||||||
Ok(X11Backend::new(Arc::new(connection), screen)?)
|
Ok(X11Backend::new(Arc::new(connection), screen)?)
|
||||||
|
@ -338,10 +373,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_substructure_events(&self) -> Result<(), ReplyError> {
|
pub fn request_substructure_events(
|
||||||
let attributes = ChangeWindowAttributesAux::default().event_mask(
|
&self,
|
||||||
EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY,
|
) -> Result<(), ReplyError> {
|
||||||
);
|
let attributes = ChangeWindowAttributesAux::default()
|
||||||
|
.event_mask(
|
||||||
|
EventMask::SUBSTRUCTURE_REDIRECT
|
||||||
|
| EventMask::SUBSTRUCTURE_NOTIFY,
|
||||||
|
);
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.connection
|
.connection
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
use std::ptr::null;
|
|
||||||
|
|
||||||
use x11::xlib::{Window, XRootWindow};
|
|
||||||
|
|
||||||
// xlib backend
|
|
||||||
|
|
||||||
pub struct XLib {
|
|
||||||
display: *mut x11::xlib::Display,
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn root_window(&self) -> Window {
|
|
||||||
unsafe { XRootWindow(self.display, self.screen) }
|
|
||||||
}
|
|
||||||
}
|
|
1028
src/backends/xlib/keysym.rs
Normal file
1028
src/backends/xlib/keysym.rs
Normal file
File diff suppressed because it is too large
Load diff
250
src/backends/xlib/mod.rs
Normal file
250
src/backends/xlib/mod.rs
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
pub mod keysym;
|
||||||
|
|
||||||
|
use std::ptr::null;
|
||||||
|
|
||||||
|
use x11::xlib::{
|
||||||
|
ButtonPress, ButtonRelease, ConfigureRequest, CreateNotify,
|
||||||
|
DestroyNotify, EnterNotify, KeyPress, KeyRelease, MapRequest,
|
||||||
|
MotionNotify, UnmapNotify, Window, XAnyEvent, XButtonEvent,
|
||||||
|
XConfigureRequestEvent, XCreateWindowEvent, XDestroyWindowEvent,
|
||||||
|
XEvent, XKeyEvent, XLookupKeysym, XMapRequestEvent, XMotionEvent,
|
||||||
|
XNextEvent, XRootWindow, XUnmapEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::backends::window_event::{
|
||||||
|
ButtonEvent, KeyEvent, KeyState, ModifierKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
use self::keysym::{keysym_to_virtual_keycode, xev_to_mouse_button};
|
||||||
|
|
||||||
|
use super::window_event::{
|
||||||
|
ConfigureEvent, CreateEvent, DestroyEvent, MapEvent,
|
||||||
|
ModifierState, MotionEvent, UnmapEvent, WindowEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
// xlib backend
|
||||||
|
pub struct XLib {
|
||||||
|
display: *mut x11::xlib::Display,
|
||||||
|
modifier_state: ModifierState,
|
||||||
|
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,
|
||||||
|
modifier_state: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn root_window(&self) -> Window {
|
||||||
|
unsafe { XRootWindow(self.display, self.screen) }
|
||||||
|
}
|
||||||
|
|
||||||
|
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.set_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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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],
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
//#[test]
|
||||||
|
// fn window_events() {
|
||||||
|
// let mut xlib = XLib::new();
|
||||||
|
|
||||||
|
// loop {
|
||||||
|
// if let Some(event) =
|
||||||
|
// xlib.xevent_to_window_event(xlib.next_event())
|
||||||
|
// {
|
||||||
|
// println!("{:#?}", event);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
|
@ -185,7 +185,9 @@ where
|
||||||
.map(move |&i| &self.workspaces[i])
|
.map(move |&i| &self.workspaces[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_current_mut(&mut self) -> impl Iterator<Item = &mut Workspace<T>> {
|
fn get_current_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> impl Iterator<Item = &mut Workspace<T>> {
|
||||||
let current_indices = &self.current_indices;
|
let current_indices = &self.current_indices;
|
||||||
|
|
||||||
self.workspaces
|
self.workspaces
|
||||||
|
@ -217,7 +219,9 @@ where
|
||||||
.flat_map(|w| w.aux.iter())
|
.flat_map(|w| w.aux.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_mut_current_master(&mut self) -> impl Iterator<Item = &mut T> {
|
fn iter_mut_current_master(
|
||||||
|
&mut self,
|
||||||
|
) -> impl Iterator<Item = &mut T> {
|
||||||
let current_indices = &self.current_indices;
|
let current_indices = &self.current_indices;
|
||||||
|
|
||||||
self.workspaces
|
self.workspaces
|
||||||
|
@ -228,7 +232,9 @@ where
|
||||||
.flat_map(|w| w.master.iter_mut())
|
.flat_map(|w| w.master.iter_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_mut_current_aux(&mut self) -> impl Iterator<Item = &mut T> {
|
fn iter_mut_current_aux(
|
||||||
|
&mut self,
|
||||||
|
) -> impl Iterator<Item = &mut T> {
|
||||||
let current_indices = &self.current_indices;
|
let current_indices = &self.current_indices;
|
||||||
|
|
||||||
self.workspaces
|
self.workspaces
|
||||||
|
@ -243,7 +249,9 @@ where
|
||||||
self.workspaces.iter()
|
self.workspaces.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_mut(&mut self) -> impl Iterator<Item = &mut Workspace<T>> {
|
fn iter_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> impl Iterator<Item = &mut Workspace<T>> {
|
||||||
self.workspaces.iter_mut()
|
self.workspaces.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,13 +278,18 @@ where
|
||||||
where
|
where
|
||||||
Vec<usize>: From<I>,
|
Vec<usize>: From<I>,
|
||||||
{
|
{
|
||||||
self.previous_indices =
|
self.previous_indices = Some(std::mem::replace(
|
||||||
Some(std::mem::replace(&mut self.current_indices, idx.into()));
|
&mut self.current_indices,
|
||||||
|
idx.into(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_previous_workspaces(&mut self) {
|
fn select_previous_workspaces(&mut self) {
|
||||||
if let Some(previous_indices) = &mut self.previous_indices {
|
if let Some(previous_indices) = &mut self.previous_indices {
|
||||||
std::mem::swap(previous_indices, &mut self.current_indices);
|
std::mem::swap(
|
||||||
|
previous_indices,
|
||||||
|
&mut self.current_indices,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +407,8 @@ where
|
||||||
(dimensions.0 - gap * 2, dimensions.1 - gap * 2)
|
(dimensions.0 - gap * 2, dimensions.1 - gap * 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
let len_master = self.workspaces.iter_current_master().count();
|
let len_master =
|
||||||
|
self.workspaces.iter_current_master().count();
|
||||||
let len_aux = self.workspaces.iter_current_aux().count();
|
let len_aux = self.workspaces.iter_current_aux().count();
|
||||||
|
|
||||||
let width_master = match len_aux {
|
let width_master = match len_aux {
|
||||||
|
@ -412,18 +426,23 @@ where
|
||||||
n => height / n as i32,
|
n => height / n as i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, id) in self.workspaces.iter_mut_current_master().enumerate() {
|
for (i, id) in
|
||||||
|
self.workspaces.iter_mut_current_master().enumerate()
|
||||||
|
{
|
||||||
let size = (
|
let size = (
|
||||||
width_master - gap * 2 - border * 2,
|
width_master - gap * 2 - border * 2,
|
||||||
height_master - gap * 2 - border * 2,
|
height_master - gap * 2 - border * 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let position = (gap * 2, height_master * i as i32 + gap * 2);
|
let position =
|
||||||
|
(gap * 2, height_master * i as i32 + gap * 2);
|
||||||
|
|
||||||
if let Some(client) =
|
if let Some(client) =
|
||||||
Option::<&mut Client<T>>::from(self.store.get_mut(id))
|
Option::<&mut Client<T>>::from(self.store.get_mut(id))
|
||||||
{
|
{
|
||||||
if *client.position() != position || *client.size() != size {
|
if *client.position() != position
|
||||||
|
|| *client.size() != size
|
||||||
|
{
|
||||||
*client.position_mut() = position;
|
*client.position_mut() = position;
|
||||||
*client.size_mut() = size;
|
*client.size_mut() = size;
|
||||||
|
|
||||||
|
@ -432,19 +451,25 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, id) in self.workspaces.iter_mut_current_aux().enumerate() {
|
for (i, id) in
|
||||||
|
self.workspaces.iter_mut_current_aux().enumerate()
|
||||||
|
{
|
||||||
let size = (
|
let size = (
|
||||||
width_aux - gap * 2 - border * 2,
|
width_aux - gap * 2 - border * 2,
|
||||||
height_aux - gap * 2 - border * 2,
|
height_aux - gap * 2 - border * 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let position =
|
let position = (
|
||||||
(width_master + gap * 2, height_aux * i as i32 + gap * 2);
|
width_master + gap * 2,
|
||||||
|
height_aux * i as i32 + gap * 2,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(client) =
|
if let Some(client) =
|
||||||
Option::<&mut Client<T>>::from(self.store.get_mut(id))
|
Option::<&mut Client<T>>::from(self.store.get_mut(id))
|
||||||
{
|
{
|
||||||
if *client.position() != position || *client.size() != size {
|
if *client.position() != position
|
||||||
|
|| *client.size() != size
|
||||||
|
{
|
||||||
*client.position_mut() = position;
|
*client.position_mut() = position;
|
||||||
*client.size_mut() = size;
|
*client.size_mut() = size;
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,8 @@ impl ClientState {
|
||||||
if client.is_transient()
|
if client.is_transient()
|
||||||
&& self.contains(&client.transient_for.unwrap())
|
&& 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 = {
|
client.position = {
|
||||||
(
|
(
|
||||||
|
@ -271,7 +272,9 @@ impl ClientState {
|
||||||
|| self.floating_clients.contains_key(&key)
|
|| 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()
|
self.floating_clients.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,32 +286,44 @@ impl ClientState {
|
||||||
.filter(move |&(k, _)| self.is_client_visible(k))
|
.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())
|
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()
|
self.iter_all_clients()
|
||||||
.filter(move |&(k, _)| !self.is_client_visible(k))
|
.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())
|
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()
|
self.iter_all_clients()
|
||||||
.filter(move |&(k, _)| self.is_client_visible(k))
|
.filter(move |&(k, _)| self.is_client_visible(k))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[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.clients.iter().filter(move |&(k, _)| {
|
||||||
self.virtual_screens.get_current().contains(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
|
self.virtual_screens
|
||||||
.get_current()
|
.get_current()
|
||||||
.master
|
.master
|
||||||
|
@ -316,7 +331,9 @@ impl ClientState {
|
||||||
.map(move |k| (k, self.get(k).unwrap()))
|
.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
|
self.virtual_screens
|
||||||
.get_current()
|
.get_current()
|
||||||
.aux
|
.aux
|
||||||
|
@ -441,12 +458,15 @@ impl ClientState {
|
||||||
// transient clients cannot be tiled
|
// transient clients cannot be tiled
|
||||||
match floating_client.is_transient() {
|
match floating_client.is_transient() {
|
||||||
true => {
|
true => {
|
||||||
self.floating_clients.insert(key, floating_client);
|
self.floating_clients
|
||||||
|
.insert(key, floating_client);
|
||||||
}
|
}
|
||||||
|
|
||||||
false => {
|
false => {
|
||||||
self.clients.insert(key, floating_client);
|
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,
|
K: ClientKey,
|
||||||
{
|
{
|
||||||
if self.contains(key) {
|
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);
|
vs.remove(key);
|
||||||
|
|
||||||
// we removed a client so the layout changed, rearrange
|
// 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
|
where
|
||||||
K: ClientKey,
|
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
|
where
|
||||||
K: ClientKey,
|
K: ClientKey,
|
||||||
{
|
{
|
||||||
|
@ -637,7 +665,8 @@ impl ClientState {
|
||||||
self.master_size / 2.0
|
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;
|
let aux_width = effective_width - master_width;
|
||||||
|
|
||||||
(master_width, aux_width)
|
(master_width, aux_width)
|
||||||
|
@ -665,7 +694,8 @@ impl ClientState {
|
||||||
master_height - gap * 2 - self.border_size * 2,
|
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) {
|
if let Some(client) = self.clients.get_mut(key) {
|
||||||
*client = Client {
|
*client = Client {
|
||||||
|
@ -683,8 +713,10 @@ impl ClientState {
|
||||||
aux_height - gap * 2 - self.border_size * 2,
|
aux_height - gap * 2 - self.border_size * 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let position =
|
let position = (
|
||||||
(master_width + gap * 2, aux_height * i as i32 + gap * 2);
|
master_width + gap * 2,
|
||||||
|
aux_height * i as i32 + gap * 2,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(client) = self.clients.get_mut(key) {
|
if let Some(client) = self.clients.get_mut(key) {
|
||||||
*client = Client {
|
*client = Client {
|
||||||
|
@ -720,7 +752,8 @@ impl VirtualScreen {
|
||||||
where
|
where
|
||||||
K: ClientKey,
|
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
|
fn is_in_master<K>(&self, key: &K) -> bool
|
||||||
|
@ -766,8 +799,11 @@ impl VirtualScreen {
|
||||||
self.aux.extend(self.master.drain(index..=index));
|
self.aux.extend(self.master.drain(index..=index));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let index =
|
let index = self
|
||||||
self.aux.iter().position(|&k| k == key.key()).unwrap();
|
.aux
|
||||||
|
.iter()
|
||||||
|
.position(|&k| k == key.key())
|
||||||
|
.unwrap();
|
||||||
self.master.extend(self.aux.drain(index..=index));
|
self.master.extend(self.aux.drain(index..=index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -814,7 +850,9 @@ impl VirtualScreenStore {
|
||||||
self.screens.iter()
|
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()
|
self.screens.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -861,7 +899,9 @@ impl<T> Into<Option<T>> for ClientEntry<T> {
|
||||||
fn into(self) -> Option<T> {
|
fn into(self) -> Option<T> {
|
||||||
match self {
|
match self {
|
||||||
Self::Vacant => None,
|
Self::Vacant => None,
|
||||||
Self::Tiled(client) | Self::Floating(client) => Some(client),
|
Self::Tiled(client) | Self::Floating(client) => {
|
||||||
|
Some(client)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,10 @@ impl<T> PartialOrd for Client<T>
|
||||||
where
|
where
|
||||||
T: PartialOrd,
|
T: PartialOrd,
|
||||||
{
|
{
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
) -> Option<std::cmp::Ordering> {
|
||||||
self.window_id.partial_cmp(&other.window_id)
|
self.window_id.partial_cmp(&other.window_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,7 +232,10 @@ where
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, entry: Entry<Client<T>>) -> Entry<&Client<T>> {
|
pub fn insert(
|
||||||
|
&mut self,
|
||||||
|
entry: Entry<Client<T>>,
|
||||||
|
) -> Entry<&Client<T>> {
|
||||||
if let Some(key) =
|
if let Some(key) =
|
||||||
Option::<&Client<T>>::from(&entry).map(|c| c.window_id())
|
Option::<&Client<T>>::from(&entry).map(|c| c.window_id())
|
||||||
{
|
{
|
||||||
|
@ -258,11 +264,16 @@ where
|
||||||
pub fn remove(&mut self, key: &T) -> Entry<Client<T>> {
|
pub fn remove(&mut self, key: &T) -> Entry<Client<T>> {
|
||||||
if let Some(client) = self.tiled_clients.remove(key) {
|
if let Some(client) = self.tiled_clients.remove(key) {
|
||||||
Entry::Tiled(client)
|
Entry::Tiled(client)
|
||||||
} else if let Some(client) = self.floating_clients.remove(key) {
|
} else if let Some(client) = self.floating_clients.remove(key)
|
||||||
|
{
|
||||||
Entry::Floating(client)
|
Entry::Floating(client)
|
||||||
} else if let Some(client) = self.transient_clients.remove(key) {
|
} else if let Some(client) =
|
||||||
|
self.transient_clients.remove(key)
|
||||||
|
{
|
||||||
Entry::Transient(client)
|
Entry::Transient(client)
|
||||||
} else if let Some(client) = self.fullscreen_clients.remove(key) {
|
} else if let Some(client) =
|
||||||
|
self.fullscreen_clients.remove(key)
|
||||||
|
{
|
||||||
Entry::Fullscreen(client)
|
Entry::Fullscreen(client)
|
||||||
} else {
|
} else {
|
||||||
Entry::Vacant
|
Entry::Vacant
|
||||||
|
@ -276,7 +287,8 @@ where
|
||||||
Entry::Floating(client)
|
Entry::Floating(client)
|
||||||
} else if let Some(client) = self.transient_clients.get(key) {
|
} else if let Some(client) = self.transient_clients.get(key) {
|
||||||
Entry::Transient(client)
|
Entry::Transient(client)
|
||||||
} else if let Some(client) = self.fullscreen_clients.get(key) {
|
} else if let Some(client) = self.fullscreen_clients.get(key)
|
||||||
|
{
|
||||||
Entry::Fullscreen(client)
|
Entry::Fullscreen(client)
|
||||||
} else {
|
} else {
|
||||||
Entry::Vacant
|
Entry::Vacant
|
||||||
|
@ -286,11 +298,17 @@ where
|
||||||
pub fn get_mut(&mut self, key: &T) -> Entry<&mut Client<T>> {
|
pub fn get_mut(&mut self, key: &T) -> Entry<&mut Client<T>> {
|
||||||
if let Some(client) = self.tiled_clients.get_mut(key) {
|
if let Some(client) = self.tiled_clients.get_mut(key) {
|
||||||
Entry::Tiled(client)
|
Entry::Tiled(client)
|
||||||
} else if let Some(client) = self.floating_clients.get_mut(key) {
|
} else if let Some(client) =
|
||||||
|
self.floating_clients.get_mut(key)
|
||||||
|
{
|
||||||
Entry::Floating(client)
|
Entry::Floating(client)
|
||||||
} else if let Some(client) = self.transient_clients.get_mut(key) {
|
} else if let Some(client) =
|
||||||
|
self.transient_clients.get_mut(key)
|
||||||
|
{
|
||||||
Entry::Transient(client)
|
Entry::Transient(client)
|
||||||
} else if let Some(client) = self.fullscreen_clients.get_mut(key) {
|
} else if let Some(client) =
|
||||||
|
self.fullscreen_clients.get_mut(key)
|
||||||
|
{
|
||||||
Entry::Fullscreen(client)
|
Entry::Fullscreen(client)
|
||||||
} else {
|
} else {
|
||||||
Entry::Vacant
|
Entry::Vacant
|
||||||
|
@ -304,7 +322,9 @@ where
|
||||||
|| self.fullscreen_clients.contains_key(key)
|
|| self.fullscreen_clients.contains_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_tiled(&self) -> impl Iterator<Item = (&T, &Client<T>)> {
|
pub fn iter_tiled(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = (&T, &Client<T>)> {
|
||||||
self.tiled_clients.iter()
|
self.tiled_clients.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +334,9 @@ where
|
||||||
self.tiled_clients.iter_mut()
|
self.tiled_clients.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_floating(&self) -> impl Iterator<Item = (&T, &Client<T>)> {
|
pub fn iter_floating(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = (&T, &Client<T>)> {
|
||||||
self.floating_clients.iter()
|
self.floating_clients.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +346,9 @@ where
|
||||||
self.floating_clients.iter_mut()
|
self.floating_clients.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_transient(&self) -> impl Iterator<Item = (&T, &Client<T>)> {
|
pub fn iter_transient(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = (&T, &Client<T>)> {
|
||||||
self.transient_clients.iter()
|
self.transient_clients.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +358,9 @@ where
|
||||||
self.transient_clients.iter_mut()
|
self.transient_clients.iter_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_fullscreen(&self) -> impl Iterator<Item = (&T, &Client<T>)> {
|
pub fn iter_fullscreen(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = (&T, &Client<T>)> {
|
||||||
self.fullscreen_clients.iter()
|
self.fullscreen_clients.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,7 +398,10 @@ mod tests {
|
||||||
Entry::Tiled(client.clone()),
|
Entry::Tiled(client.clone()),
|
||||||
client_store.remove(&client.borrow())
|
client_store.remove(&client.borrow())
|
||||||
);
|
);
|
||||||
assert_eq!(Entry::Vacant, client_store.remove(&client.borrow()));
|
assert_eq!(
|
||||||
|
Entry::Vacant,
|
||||||
|
client_store.remove(&client.borrow())
|
||||||
|
);
|
||||||
assert_eq!(Entry::Vacant, client_store.remove(&1));
|
assert_eq!(Entry::Vacant, client_store.remove(&1));
|
||||||
|
|
||||||
assert!(client_store.contains(&client2.borrow()));
|
assert!(client_store.contains(&client2.borrow()));
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -23,9 +23,11 @@ fn init_logger() {
|
||||||
"{d(%Y-%m-%d %H:%M:%S %Z)(utc)} │ {({M}::{f}:{L}):>25} │ {h({l:>5})} │ {m}{n}",
|
"{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()
|
let _logfile = FileAppender::builder()
|
||||||
.encoder(encoder)
|
.encoder(encoder)
|
||||||
|
@ -33,7 +35,9 @@ fn init_logger() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let config = Config::builder()
|
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)))
|
//.appender(Appender::builder().build("logfile", Box::new(logfile)))
|
||||||
.build(
|
.build(
|
||||||
Root::builder()
|
Root::builder()
|
||||||
|
|
134
src/state.rs
134
src/state.rs
|
@ -151,7 +151,9 @@ impl WindowManager {
|
||||||
.get_focused()
|
.get_focused()
|
||||||
.into_option()
|
.into_option()
|
||||||
.map(|c| c.key())
|
.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();
|
wm.arrange_clients();
|
||||||
},
|
},
|
||||||
|
@ -224,15 +226,24 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_vs_switch_keybinds(&mut self) {
|
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));
|
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));
|
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)
|
wm.go_to_nth_virtual_screen(N)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,13 +344,23 @@ impl WindowManager {
|
||||||
match event.get_type() {
|
match event.get_type() {
|
||||||
xlib::MapRequest => self.map_request(&event),
|
xlib::MapRequest => self.map_request(&event),
|
||||||
xlib::UnmapNotify => self.unmap_notify(&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::EnterNotify => self.enter_notify(&event),
|
||||||
xlib::DestroyNotify => self.destroy_notify(&event),
|
xlib::DestroyNotify => self.destroy_notify(&event),
|
||||||
xlib::ButtonPress => self.button_press(event.as_ref()),
|
xlib::ButtonPress => {
|
||||||
xlib::ButtonRelease => self.button_release(event.as_ref()),
|
self.button_press(event.as_ref())
|
||||||
xlib::MotionNotify => self.motion_notify(event.as_ref()),
|
}
|
||||||
xlib::KeyPress => self.handle_keybinds(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) {
|
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);
|
self.xlib.kill_client(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,7 +387,8 @@ impl WindowManager {
|
||||||
for kb in self.keybinds.clone().into_iter() {
|
for kb in self.keybinds.clone().into_iter() {
|
||||||
if let KeyOrButton::Key(keycode, modmask) = kb.key {
|
if let KeyOrButton::Key(keycode, modmask) = kb.key {
|
||||||
if keycode as u32 == event.keycode
|
if keycode as u32 == event.keycode
|
||||||
&& modmask & clean_mask == event.state & clean_mask
|
&& modmask & clean_mask
|
||||||
|
== event.state & clean_mask
|
||||||
{
|
{
|
||||||
(kb.closure)(self, event);
|
(kb.closure)(self, event);
|
||||||
}
|
}
|
||||||
|
@ -409,8 +432,12 @@ impl WindowManager {
|
||||||
|
|
||||||
fn focus_any(&mut self) {
|
fn focus_any(&mut self) {
|
||||||
// focus first client in all visible clients
|
// focus first client in all visible clients
|
||||||
let to_focus =
|
let to_focus = self
|
||||||
self.clients.iter_visible().next().map(|(k, _)| k).cloned();
|
.clients
|
||||||
|
.iter_visible()
|
||||||
|
.next()
|
||||||
|
.map(|(k, _)| k)
|
||||||
|
.cloned();
|
||||||
|
|
||||||
if let Some(key) = to_focus {
|
if let Some(key) = to_focus {
|
||||||
self.focus_client(&key, false);
|
self.focus_client(&key, false);
|
||||||
|
@ -418,7 +445,8 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_master_stack(&mut self) {
|
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
|
let k = self
|
||||||
.clients
|
.clients
|
||||||
|
@ -436,7 +464,8 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_aux_stack(&mut self) {
|
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
|
let k = self
|
||||||
.clients
|
.clients
|
||||||
|
@ -454,12 +483,12 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_up(&mut self) {
|
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| {
|
let k = focused.and_then(|focused| {
|
||||||
self.clients
|
self.clients.get_stack_for_client(&focused).and_then(
|
||||||
.get_stack_for_client(&focused)
|
|stack| {
|
||||||
.and_then(|stack| {
|
|
||||||
stack
|
stack
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
|
@ -467,7 +496,8 @@ impl WindowManager {
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned()
|
||||||
})
|
},
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(k) = k {
|
if let Some(k) = k {
|
||||||
|
@ -476,19 +506,20 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_down(&mut self) {
|
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| {
|
let k = focused.and_then(|focused| {
|
||||||
self.clients
|
self.clients.get_stack_for_client(&focused).and_then(
|
||||||
.get_stack_for_client(&focused)
|
|stack| {
|
||||||
.and_then(|stack| {
|
|
||||||
stack
|
stack
|
||||||
.iter()
|
.iter()
|
||||||
.skip_while(|&&k| k != focused)
|
.skip_while(|&&k| k != focused)
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned()
|
||||||
})
|
},
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(k) = k {
|
if let Some(k) = k {
|
||||||
|
@ -573,7 +604,9 @@ impl WindowManager {
|
||||||
{
|
{
|
||||||
Client::new_transient(
|
Client::new_transient(
|
||||||
window,
|
window,
|
||||||
self.xlib.get_window_size(window).unwrap_or((100, 100)),
|
self.xlib
|
||||||
|
.get_window_size(window)
|
||||||
|
.unwrap_or((100, 100)),
|
||||||
transient_window,
|
transient_window,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -632,7 +665,10 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ensure event.subwindow refers to a valid client.
|
/// 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;
|
let window = event.subwindow;
|
||||||
|
|
||||||
match event.button {
|
match event.button {
|
||||||
|
@ -641,15 +677,16 @@ impl WindowManager {
|
||||||
self.arrange_clients();
|
self.arrange_clients();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.move_resize_window = MoveResizeInfo::Move(MoveInfoInner {
|
self.move_resize_window =
|
||||||
window,
|
MoveResizeInfo::Move(MoveInfoInner {
|
||||||
starting_cursor_pos: (event.x, event.y),
|
window,
|
||||||
starting_window_pos: self
|
starting_cursor_pos: (event.x, event.y),
|
||||||
.clients
|
starting_window_pos: self
|
||||||
.get(&window)
|
.clients
|
||||||
.unwrap()
|
.get(&window)
|
||||||
.position,
|
.unwrap()
|
||||||
});
|
.position,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
if self.clients.set_floating(&window) {
|
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 {
|
if event.button == 1 || event.button == 3 {
|
||||||
self.move_resize_window = MoveResizeInfo::None;
|
self.move_resize_window = MoveResizeInfo::None;
|
||||||
}
|
}
|
||||||
|
@ -718,8 +758,14 @@ impl WindowManager {
|
||||||
{
|
{
|
||||||
let size = &mut client.size;
|
let size = &mut client.size;
|
||||||
|
|
||||||
size.0 = std::cmp::max(1, info.starting_window_size.0 + x);
|
size.0 = std::cmp::max(
|
||||||
size.1 = std::cmp::max(1, info.starting_window_size.1 + y);
|
1,
|
||||||
|
info.starting_window_size.0 + x,
|
||||||
|
);
|
||||||
|
size.1 = std::cmp::max(
|
||||||
|
1,
|
||||||
|
info.starting_window_size.1 + y,
|
||||||
|
);
|
||||||
|
|
||||||
self.xlib.resize_client(client);
|
self.xlib.resize_client(client);
|
||||||
}
|
}
|
||||||
|
@ -734,10 +780,12 @@ impl WindowManager {
|
||||||
match event.button {
|
match event.button {
|
||||||
1 | 3 => match self.move_resize_window {
|
1 | 3 => match self.move_resize_window {
|
||||||
MoveResizeInfo::None
|
MoveResizeInfo::None
|
||||||
if self
|
if self.xlib.are_masks_equal(
|
||||||
.xlib
|
event.state,
|
||||||
.are_masks_equal(event.state, self.config.mod_key)
|
self.config.mod_key,
|
||||||
&& self.clients.contains(&event.subwindow) =>
|
) && self
|
||||||
|
.clients
|
||||||
|
.contains(&event.subwindow) =>
|
||||||
{
|
{
|
||||||
self.start_move_resize_window(event)
|
self.start_move_resize_window(event)
|
||||||
}
|
}
|
||||||
|
|
162
src/xlib.rs
162
src/xlib.rs
|
@ -4,14 +4,16 @@ use std::{ffi::CString, rc::Rc};
|
||||||
|
|
||||||
use x11::xlib::{
|
use x11::xlib::{
|
||||||
self, AnyButton, AnyKey, AnyModifier, Atom, ButtonPressMask,
|
self, AnyButton, AnyKey, AnyModifier, Atom, ButtonPressMask,
|
||||||
ButtonReleaseMask, CWEventMask, ControlMask, CurrentTime, EnterWindowMask,
|
ButtonReleaseMask, CWEventMask, ControlMask, CurrentTime,
|
||||||
FocusChangeMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask,
|
EnterWindowMask, FocusChangeMask, LockMask, Mod1Mask, Mod2Mask,
|
||||||
Mod5Mask, PointerMotionMask, PropertyChangeMask, ShiftMask,
|
Mod3Mask, Mod4Mask, Mod5Mask, PointerMotionMask,
|
||||||
StructureNotifyMask, SubstructureNotifyMask, SubstructureRedirectMask,
|
PropertyChangeMask, ShiftMask, StructureNotifyMask,
|
||||||
Window, XCloseDisplay, XConfigureRequestEvent, XDefaultScreen, XEvent,
|
SubstructureNotifyMask, SubstructureRedirectMask, Window,
|
||||||
XGetTransientForHint, XGrabPointer, XInternAtom, XKillClient, XMapWindow,
|
XCloseDisplay, XConfigureRequestEvent, XDefaultScreen, XEvent,
|
||||||
XOpenDisplay, XRaiseWindow, XRootWindow, XSetErrorHandler, XSync,
|
XGetTransientForHint, XGrabPointer, XInternAtom, XKillClient,
|
||||||
XUngrabButton, XUngrabKey, XUngrabPointer, XWarpPointer, XWindowAttributes,
|
XMapWindow, XOpenDisplay, XRaiseWindow, XRootWindow,
|
||||||
|
XSetErrorHandler, XSync, XUngrabButton, XUngrabKey,
|
||||||
|
XUngrabPointer, XWarpPointer, XWindowAttributes,
|
||||||
};
|
};
|
||||||
use xlib::GrabModeAsync;
|
use xlib::GrabModeAsync;
|
||||||
|
|
||||||
|
@ -45,7 +47,11 @@ impl KeyOrButton {
|
||||||
pub fn key(keycode: i32, modmask: u32) -> Self {
|
pub fn key(keycode: i32, modmask: u32) -> Self {
|
||||||
Self::Key(keycode, modmask)
|
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)
|
Self::Button(button, modmask, buttonmask as u64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,9 +84,10 @@ impl XLib {
|
||||||
|
|
||||||
pub fn init(&mut self) {
|
pub fn init(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut window_attributes =
|
let mut window_attributes = std::mem::MaybeUninit::<
|
||||||
std::mem::MaybeUninit::<xlib::XSetWindowAttributes>::zeroed()
|
xlib::XSetWindowAttributes,
|
||||||
.assume_init();
|
>::zeroed()
|
||||||
|
.assume_init();
|
||||||
|
|
||||||
window_attributes.event_mask = SubstructureRedirectMask
|
window_attributes.event_mask = SubstructureRedirectMask
|
||||||
| StructureNotifyMask
|
| StructureNotifyMask
|
||||||
|
@ -117,7 +124,12 @@ impl XLib {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn ungrab_global_keybings(&self, window: Window) {
|
fn ungrab_global_keybings(&self, window: Window) {
|
||||||
unsafe {
|
unsafe {
|
||||||
XUngrabButton(self.dpy(), AnyButton as u32, AnyModifier, window);
|
XUngrabButton(
|
||||||
|
self.dpy(),
|
||||||
|
AnyButton as u32,
|
||||||
|
AnyModifier,
|
||||||
|
window,
|
||||||
|
);
|
||||||
XUngrabKey(self.dpy(), AnyKey, AnyModifier, window);
|
XUngrabKey(self.dpy(), AnyKey, AnyModifier, window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,10 +155,14 @@ impl XLib {
|
||||||
pub fn squash_event(&self, event_type: i32) -> XEvent {
|
pub fn squash_event(&self, event_type: i32) -> XEvent {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut event =
|
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)
|
while xlib::XCheckTypedEvent(
|
||||||
!= 0
|
self.dpy(),
|
||||||
|
event_type,
|
||||||
|
&mut event,
|
||||||
|
) != 0
|
||||||
{}
|
{}
|
||||||
|
|
||||||
event
|
event
|
||||||
|
@ -156,14 +172,19 @@ impl XLib {
|
||||||
pub fn next_event(&self) -> XEvent {
|
pub fn next_event(&self) -> XEvent {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut event =
|
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);
|
xlib::XNextEvent(self.dpy(), &mut event);
|
||||||
|
|
||||||
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 numlock_mask = self.get_numlock_mask();
|
||||||
let modifiers =
|
let modifiers =
|
||||||
vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
|
vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
|
||||||
|
@ -212,7 +233,8 @@ impl XLib {
|
||||||
xlib::CurrentTime,
|
xlib::CurrentTime,
|
||||||
);
|
);
|
||||||
|
|
||||||
let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
|
let screen =
|
||||||
|
xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
|
||||||
|
|
||||||
if let Some(screen) = screen {
|
if let Some(screen) = screen {
|
||||||
xlib::XSetWindowBorder(
|
xlib::XSetWindowBorder(
|
||||||
|
@ -248,7 +270,8 @@ impl XLib {
|
||||||
xlib::CurrentTime,
|
xlib::CurrentTime,
|
||||||
);
|
);
|
||||||
|
|
||||||
let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
|
let screen =
|
||||||
|
xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
|
||||||
|
|
||||||
if let Some(screen) = screen {
|
if let Some(screen) = screen {
|
||||||
xlib::XSetWindowBorder(
|
xlib::XSetWindowBorder(
|
||||||
|
@ -284,8 +307,10 @@ impl XLib {
|
||||||
xlib::XConfigureWindow(
|
xlib::XConfigureWindow(
|
||||||
self.dpy(),
|
self.dpy(),
|
||||||
client.window,
|
client.window,
|
||||||
(xlib::CWY | xlib::CWX | xlib::CWHeight | xlib::CWWidth)
|
(xlib::CWY
|
||||||
as u32,
|
| xlib::CWX
|
||||||
|
| xlib::CWHeight
|
||||||
|
| xlib::CWWidth) as u32,
|
||||||
&mut windowchanges,
|
&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 {
|
let mut wa = unsafe {
|
||||||
std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed()
|
std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed()
|
||||||
.assume_init()
|
.assume_init()
|
||||||
};
|
};
|
||||||
|
|
||||||
if unsafe {
|
if unsafe {
|
||||||
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0
|
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa)
|
||||||
|
!= 0
|
||||||
} {
|
} {
|
||||||
Some((wa.width, wa.height))
|
Some((wa.width, wa.height))
|
||||||
} else {
|
} else {
|
||||||
|
@ -401,7 +430,8 @@ impl XLib {
|
||||||
};
|
};
|
||||||
|
|
||||||
if unsafe {
|
if unsafe {
|
||||||
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0
|
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa)
|
||||||
|
!= 0
|
||||||
} {
|
} {
|
||||||
Some(wa)
|
Some(wa)
|
||||||
} else {
|
} 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;
|
let mut transient_for: Window = 0;
|
||||||
|
|
||||||
if unsafe {
|
if unsafe {
|
||||||
XGetTransientForHint(self.dpy(), window, &mut transient_for) != 0
|
XGetTransientForHint(
|
||||||
|
self.dpy(),
|
||||||
|
window,
|
||||||
|
&mut transient_for,
|
||||||
|
) != 0
|
||||||
} {
|
} {
|
||||||
Some(transient_for)
|
Some(transient_for)
|
||||||
} else {
|
} else {
|
||||||
|
@ -515,13 +552,21 @@ impl XLib {
|
||||||
|
|
||||||
pub fn dimensions(&self) -> (i32, i32) {
|
pub fn dimensions(&self) -> (i32, i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut wa =
|
let mut wa = std::mem::MaybeUninit::<
|
||||||
std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed()
|
xlib::XWindowAttributes,
|
||||||
.assume_init();
|
>::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)
|
(wa.width, wa.height)
|
||||||
}
|
}
|
||||||
|
@ -547,8 +592,9 @@ impl XLib {
|
||||||
self.dpy(),
|
self.dpy(),
|
||||||
self.root,
|
self.root,
|
||||||
0,
|
0,
|
||||||
(ButtonPressMask | ButtonReleaseMask | PointerMotionMask)
|
(ButtonPressMask
|
||||||
as u32,
|
| ButtonReleaseMask
|
||||||
|
| PointerMotionMask) as u32,
|
||||||
GrabModeAsync,
|
GrabModeAsync,
|
||||||
GrabModeAsync,
|
GrabModeAsync,
|
||||||
0,
|
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 {
|
unsafe {
|
||||||
XWarpPointer(
|
XWarpPointer(
|
||||||
self.dpy(),
|
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 protos: *mut xlib::Atom = null_mut();
|
||||||
let mut num_protos: i32 = 0;
|
let mut num_protos: i32 = 0;
|
||||||
|
|
||||||
|
@ -603,7 +657,11 @@ impl XLib {
|
||||||
return false;
|
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) {
|
if self.check_for_protocol(client, proto) {
|
||||||
let mut data = xlib::ClientMessageData::default();
|
let mut data = xlib::ClientMessageData::default();
|
||||||
data.set_long(0, proto as i64);
|
data.set_long(0, proto as i64);
|
||||||
|
@ -723,19 +781,37 @@ impl Atoms {
|
||||||
Self {
|
Self {
|
||||||
protocols: {
|
protocols: {
|
||||||
let name = CString::new("WM_PROTOCOLS").unwrap();
|
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: {
|
delete_window: {
|
||||||
let name = CString::new("WM_DELETE_WINDOW").unwrap();
|
let name =
|
||||||
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0)
|
CString::new("WM_DELETE_WINDOW").unwrap();
|
||||||
|
XInternAtom(
|
||||||
|
display.get(),
|
||||||
|
name.as_c_str().as_ptr(),
|
||||||
|
0,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
active_window: {
|
active_window: {
|
||||||
let name = CString::new("WM_ACTIVE_WINDOW").unwrap();
|
let name =
|
||||||
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0)
|
CString::new("WM_ACTIVE_WINDOW").unwrap();
|
||||||
|
XInternAtom(
|
||||||
|
display.get(),
|
||||||
|
name.as_c_str().as_ptr(),
|
||||||
|
0,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
take_focus: {
|
take_focus: {
|
||||||
let name = CString::new("WM_TAKE_FOCUS").unwrap();
|
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,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue