more work on XLib backend

This commit is contained in:
Janis 2021-11-24 22:57:17 +01:00
parent 57863e2eb7
commit db17c9dbfe
4 changed files with 231 additions and 46 deletions

View file

@ -9,7 +9,7 @@ pub trait WindowServerBackend {
fn new() -> Self; fn new() -> Self;
fn next_event(&self) -> window_event::WindowEvent<Self::Window>; fn next_event(&mut self) -> window_event::WindowEvent<Self::Window>;
fn add_keybind(&mut self, keybind: KeyBind, window: Option<Self::Window>); fn add_keybind(&mut self, keybind: KeyBind, window: Option<Self::Window>);
fn remove_keybind( fn remove_keybind(
&mut self, &mut self,

View file

@ -38,21 +38,31 @@ pub fn mouse_button_to_xbutton(button: MouseButton) -> i32 {
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub struct XKeysym(u32); pub struct XKeySym(pub u32);
impl Borrow<u32> for XKeysym { impl XKeySym {
pub fn new(value: u32) -> Self {
Self(value)
}
pub fn get(&self) -> u32 {
self.0
}
}
impl Borrow<u32> for XKeySym {
fn borrow(&self) -> &u32 { fn borrow(&self) -> &u32 {
&self.0 &self.0
} }
} }
impl AsRef<u32> for XKeysym { impl AsRef<u32> for XKeySym {
fn as_ref(&self) -> &u32 { fn as_ref(&self) -> &u32 {
&self.0 &self.0
} }
} }
impl Deref for XKeysym { impl Deref for XKeySym {
type Target = u32; type Target = u32;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -60,12 +70,12 @@ impl Deref for XKeysym {
} }
} }
impl From<XKeysym> for VirtualKeyCode { impl From<XKeySym> for VirtualKeyCode {
fn from(value: XKeysym) -> Self { fn from(value: XKeySym) -> Self {
keysym_to_virtual_keycode(*value).unwrap() keysym_to_virtual_keycode(*value).unwrap()
} }
} }
impl From<VirtualKeyCode> for XKeysym { impl From<VirtualKeyCode> for XKeySym {
fn from(value: VirtualKeyCode) -> Self { fn from(value: VirtualKeyCode) -> Self {
Self(virtual_keycode_to_keysym(value).unwrap()) Self(virtual_keycode_to_keysym(value).unwrap())
} }
@ -2092,12 +2102,12 @@ mod tests {
#[test] #[test]
fn test_keysym_to_vkc() { fn test_keysym_to_vkc() {
let keysym: XKeysym = VirtualKeyCode::W.into(); let keysym: XKeySym = VirtualKeyCode::W.into();
let keycode: VirtualKeyCode = keysym.into(); let keycode: VirtualKeyCode = keysym.into();
assert_eq!(keycode, VirtualKeyCode::W); assert_eq!(keycode, VirtualKeyCode::W);
let keysym2: XKeysym = keycode.into(); let keysym2: XKeySym = keycode.into();
assert_eq!(keysym2, keysym); assert_eq!(keysym2, keysym);
assert_eq!(&x11::keysym::XK_W, keysym.as_ref()); assert_eq!(&x11::keysym::XK_W, keysym.as_ref());

View file

@ -8,11 +8,16 @@ use std::{
use thiserror::Error; use thiserror::Error;
use x11::xlib::{self, Atom, Window, XEvent, XInternAtom}; use x11::xlib::{
self, Atom, KeyPress, KeyRelease, Window, XEvent, XInternAtom, XKeyEvent,
};
use self::keysym::xev_to_mouse_button; use crate::backends::window_event::ModifierKey;
use self::keysym::{virtual_keycode_to_keysym, xev_to_mouse_button, XKeySym};
use super::{ use super::{
keycodes::VirtualKeyCode,
window_event::{ window_event::{
ButtonEvent, ConfigureEvent, DestroyEvent, EnterEvent, KeyState, ButtonEvent, ConfigureEvent, DestroyEvent, EnterEvent, KeyState,
MapEvent, ModifierState, UnmapEvent, WindowEvent, MapEvent, ModifierState, UnmapEvent, WindowEvent,
@ -131,25 +136,153 @@ impl Display {
pub struct XLib { pub struct XLib {
display: Display, display: Display,
modifier_state: ModifierState,
root: Window, root: Window,
screen: i32, screen: i32,
atoms: XLibAtoms, atoms: XLibAtoms,
keybinds: Vec<()>, keybinds: Vec<()>,
} }
impl Drop for XLib {
fn drop(&mut self) {
self.close_dpy();
}
}
impl XLib { impl XLib {
fn dpy(&self) -> *mut xlib::Display { fn dpy(&self) -> *mut xlib::Display {
self.display.get() self.display.get()
} }
fn next_xevent(&self) -> XEvent { fn close_dpy(&self) {
unsafe { unsafe {
let mut event = xlib::XCloseDisplay(self.dpy());
std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init(); }
xlib::XNextEvent(self.dpy(), &mut event); }
fn next_xevent(&mut self) -> XEvent {
let event = unsafe {
let mut event = std::mem::MaybeUninit::<xlib::XEvent>::zeroed();
xlib::XNextEvent(self.dpy(), event.as_mut_ptr());
event.assume_init()
};
match event.get_type() {
xlib::KeyPress | xlib::KeyRelease => {
self.update_modifier_state(AsRef::<xlib::XKeyEvent>::as_ref(
&event,
));
}
_ => {}
}
event event
} }
fn check_for_protocol(
&self,
window: xlib::Window,
proto: xlib::Atom,
) -> bool {
let mut protos: *mut xlib::Atom = std::ptr::null_mut();
let mut num_protos: i32 = 0;
unsafe {
if xlib::XGetWMProtocols(
self.dpy(),
window,
&mut protos,
&mut num_protos,
) != 0
{
for i in 0..num_protos {
if *protos.offset(i as isize) == proto {
return true;
}
}
}
}
return false;
}
fn send_protocol(&self, window: xlib::Window, proto: Atom) -> bool {
if self.check_for_protocol(window, proto) {
let mut data = xlib::ClientMessageData::default();
data.set_long(0, proto as i64);
let mut event = XEvent {
client_message: xlib::XClientMessageEvent {
type_: xlib::ClientMessage,
serial: 0,
display: self.dpy(),
send_event: 0,
window,
format: 32,
message_type: self.atoms.wm_protocols,
data,
},
};
unsafe {
xlib::XSendEvent(
self.dpy(),
window,
0,
xlib::NoEventMask,
&mut event,
);
}
true
} else {
false
}
}
#[allow(non_upper_case_globals)]
fn update_modifier_state(&mut self, keyevent: &XKeyEvent) {
//keyevent.keycode
let keysym = self.keyev_to_keysym(keyevent);
use x11::keysym::*;
let modifier = match keysym.get() {
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_mod(modifier),
KeyRelease => self.modifier_state.unset_mod(modifier),
_ => unreachable!("keyyevent != (KeyPress | KeyRelease)"),
}
}
}
fn vk_to_keycode(&self, vk: VirtualKeyCode) -> i32 {
unsafe {
xlib::XKeysymToKeycode(
self.dpy(),
virtual_keycode_to_keysym(vk).unwrap() as u64,
) as i32
}
}
fn keyev_to_keysym(&self, ev: &XKeyEvent) -> XKeySym {
let keysym =
unsafe { xlib::XLookupKeysym(ev as *const _ as *mut _, 0) };
XKeySym::new(keysym as u32)
} }
} }
@ -191,7 +324,7 @@ impl TryFrom<XEvent> for XLibWindowEvent {
KeyState::Released KeyState::Released
}; };
let modifierstate = ModifierState::new(); let modifierstate = ModifierState::empty();
Ok(Self::ButtonEvent(ButtonEvent::new( Ok(Self::ButtonEvent(ButtonEvent::new(
ev.window, ev.window,
@ -208,8 +341,12 @@ impl TryFrom<XEvent> for XLibWindowEvent {
impl WindowServerBackend for XLib { impl WindowServerBackend for XLib {
type Window = xlib::Window; type Window = xlib::Window;
fn next_event(&self) -> super::window_event::WindowEvent<Self::Window> { fn next_event(&mut self) -> super::window_event::WindowEvent<Self::Window> {
self.next_xevent().try_into().unwrap() std::iter::from_fn(|| {
TryInto::<XLibWindowEvent>::try_into(self.next_xevent()).ok()
})
.next()
.unwrap()
} }
fn add_keybind( fn add_keybind(
@ -265,10 +402,24 @@ impl WindowServerBackend for XLib {
} }
fn screen_size(&self) -> (i32, i32) { fn screen_size(&self) -> (i32, i32) {
todo!() unsafe {
let mut wa =
std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed();
xlib::XGetWindowAttributes(self.dpy(), self.root, wa.as_mut_ptr());
let wa = wa.assume_init();
(wa.width, wa.height)
}
} }
fn kill_window(&self, window: Self::Window) { fn kill_window(&self, window: Self::Window) {
if !self.send_protocol(window, self.atoms.wm_delete_window) {
unsafe {
xlib::XKillClient(self.dpy(), window);
}
}
todo!() todo!()
} }
@ -290,34 +441,58 @@ impl WindowServerBackend for XLib {
} }
struct XLibAtoms { struct XLibAtoms {
protocols: Atom, wm_protocols: Atom,
delete_window: Atom, wm_delete_window: Atom,
active_window: Atom, wm_active_window: Atom,
take_focus: 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 XLibAtoms { impl XLibAtoms {
fn init(display: Display) -> Self { fn init(display: Display) -> Self {
unsafe {
Self { Self {
protocols: { wm_protocols: Self::get_atom(&display, "WM_PROTOCOLS").unwrap(),
let name = CString::new("WM_PROTOCOLS").unwrap(); wm_delete_window: Self::get_atom(&display, "WM_DELETE_WINDOW")
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) .unwrap(),
}, wm_active_window: Self::get_atom(&display, "WM_ACTIVE_WINDOW")
delete_window: { .unwrap(),
let name = CString::new("WM_DELETE_WINDOW").unwrap(); wm_take_focus: Self::get_atom(&display, "WM_TAKE_FOCUS").unwrap(),
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) net_supported: Self::get_atom(&display, "_NET_SUPPORTED").unwrap(),
}, net_active_window: Self::get_atom(&display, "_NET_ACTIVE_WINDOW")
active_window: { .unwrap(),
let name = CString::new("WM_ACTIVE_WINDOW").unwrap(); net_client_list: Self::get_atom(&display, "_NET_CLIENT_LIST")
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) .unwrap(),
}, net_wm_name: Self::get_atom(&display, "_NET_WM_NAME").unwrap(),
take_focus: { net_wm_state: Self::get_atom(&display, "_NET_WM_STATE").unwrap(),
let name = CString::new("WM_TAKE_FOCUS").unwrap(); net_wm_state_fullscreen: Self::get_atom(
XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) &display,
}, "_NET_WM_STATE_FULLSCREEN",
)
.unwrap(),
net_wm_window_type: Self::get_atom(&display, "_NET_WM_WINDOW_TYPE")
.unwrap(),
net_wm_window_type_dialog: Self::get_atom(
&display,
"_NET_WM_WINDOW_TYPE_DIALOG",
)
.unwrap(),
} }
} }
fn get_atom(display: &Display, atom: &str) -> Option<Atom> {
let name = CString::new(atom).ok()?;
match unsafe { XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) }
{
0 => None,
atom => Some(atom),
}
} }
} }

View file

@ -382,7 +382,7 @@ where
fn kill_client(&mut self) { fn kill_client(&mut self) {
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.backend.kill_window(client.window);
} }
} }