started with a backend using x11rb
This commit is contained in:
parent
507bc75ccc
commit
98459d620c
|
@ -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"
|
||||
|
|
4
src/backends/mod.rs
Normal file
4
src/backends/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
mod xcb;
|
||||
mod xlib;
|
||||
|
||||
pub trait WindowServerBackend {}
|
363
src/backends/xcb.rs
Normal file
363
src/backends/xcb.rs
Normal file
|
@ -0,0 +1,363 @@
|
|||
//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: {:#x?}\tkeysyms: {:0x?}",
|
||||
xcb.setup().min_keycode as usize + i,
|
||||
keysyms
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
src/backends/xlib.rs
Normal file
34
src/backends/xlib.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
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) }
|
||||
}
|
||||
}
|
|
@ -7,6 +7,10 @@ use log4rs::{
|
|||
};
|
||||
use state::WMConfig;
|
||||
|
||||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
|
||||
mod backends;
|
||||
mod client_logic;
|
||||
mod clients;
|
||||
mod clients2;
|
||||
|
|
Loading…
Reference in a new issue