implemented most backend trait functions for XLib
This commit is contained in:
parent
d3afc30ceb
commit
af21769d52
|
@ -1,16 +1,17 @@
|
||||||
use super::{
|
use super::{
|
||||||
window_event,
|
window_event,
|
||||||
window_event::{KeyBind, Point},
|
window_event::{KeyBind, MouseBind, Point},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait WindowServerBackend {
|
pub trait WindowServerBackend {
|
||||||
type Window;
|
type Window;
|
||||||
|
|
||||||
fn new() -> Self;
|
fn build() -> Self;
|
||||||
|
|
||||||
fn next_event(&mut self) -> window_event::WindowEvent<Self::Window>;
|
fn next_event(&mut self) -> window_event::WindowEvent<Self::Window>;
|
||||||
fn handle_event(&mut self, event: window_event::WindowEvent<Self::Window>);
|
fn handle_event(&mut self, event: window_event::WindowEvent<Self::Window>);
|
||||||
|
|
||||||
|
/// adds a keybind to the specified `window`, or globally if `window` is `None`.
|
||||||
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,
|
||||||
|
@ -18,10 +19,14 @@ pub trait WindowServerBackend {
|
||||||
window: Option<Self::Window>,
|
window: Option<Self::Window>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn add_mousebind(&mut self, keybind: KeyBind, window: Option<Self::Window>);
|
fn add_mousebind(
|
||||||
|
&mut self,
|
||||||
|
keybind: MouseBind,
|
||||||
|
window: Option<Self::Window>,
|
||||||
|
);
|
||||||
fn remove_mousebind(
|
fn remove_mousebind(
|
||||||
&mut self,
|
&mut self,
|
||||||
keybind: KeyBind,
|
keybind: MouseBind,
|
||||||
window: Option<Self::Window>,
|
window: Option<Self::Window>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
#![allow(unused_variables, dead_code)]
|
#![allow(unused_variables, dead_code)]
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use std::{
|
use std::{ffi::CString, rc::Rc};
|
||||||
convert::{TryFrom, TryInto},
|
|
||||||
ffi::CString,
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -20,7 +16,7 @@ use super::{
|
||||||
keycodes::VirtualKeyCode,
|
keycodes::VirtualKeyCode,
|
||||||
window_event::{
|
window_event::{
|
||||||
ButtonEvent, ConfigureEvent, DestroyEvent, EnterEvent, KeyState,
|
ButtonEvent, ConfigureEvent, DestroyEvent, EnterEvent, KeyState,
|
||||||
MapEvent, ModifierState, UnmapEvent, WindowEvent,
|
MapEvent, ModifierState, Point, UnmapEvent, WindowEvent,
|
||||||
},
|
},
|
||||||
WindowServerBackend,
|
WindowServerBackend,
|
||||||
};
|
};
|
||||||
|
@ -150,6 +146,54 @@ impl Drop for XLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XLib {
|
impl XLib {
|
||||||
|
fn new() -> Self {
|
||||||
|
let (display, screen, root) = {
|
||||||
|
let display = unsafe { xlib::XOpenDisplay(std::ptr::null()) };
|
||||||
|
assert_eq!(display, std::ptr::null_mut());
|
||||||
|
let screen = unsafe { xlib::XDefaultScreen(display) };
|
||||||
|
let root = unsafe { xlib::XRootWindow(display, screen) };
|
||||||
|
|
||||||
|
let display = Display::new(display);
|
||||||
|
|
||||||
|
(display, screen, root)
|
||||||
|
};
|
||||||
|
|
||||||
|
let atoms = XLibAtoms::init(display.clone());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
display,
|
||||||
|
screen,
|
||||||
|
root,
|
||||||
|
modifier_state: ModifierState::empty(),
|
||||||
|
atoms,
|
||||||
|
keybinds: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn init_as_wm(&self) {
|
||||||
|
let mut window_attributes =
|
||||||
|
std::mem::MaybeUninit::<xlib::XSetWindowAttributes>::zeroed()
|
||||||
|
.assume_init();
|
||||||
|
|
||||||
|
window_attributes.event_mask = xlib::SubstructureRedirectMask
|
||||||
|
| xlib::StructureNotifyMask
|
||||||
|
| xlib::SubstructureNotifyMask
|
||||||
|
| xlib::EnterWindowMask
|
||||||
|
| xlib::PointerMotionMask
|
||||||
|
| xlib::ButtonPressMask;
|
||||||
|
|
||||||
|
xlib::XChangeWindowAttributes(
|
||||||
|
self.dpy(),
|
||||||
|
self.root,
|
||||||
|
xlib::CWEventMask,
|
||||||
|
&mut window_attributes,
|
||||||
|
);
|
||||||
|
|
||||||
|
xlib::XSelectInput(self.dpy(), self.root, window_attributes.event_mask);
|
||||||
|
xlib::XSetErrorHandler(Some(xlib_error_handler));
|
||||||
|
xlib::XSync(self.dpy(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
fn dpy(&self) -> *mut xlib::Display {
|
fn dpy(&self) -> *mut xlib::Display {
|
||||||
self.display.get()
|
self.display.get()
|
||||||
}
|
}
|
||||||
|
@ -180,6 +224,84 @@ impl XLib {
|
||||||
event
|
event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn xevent_to_window_event(&self, event: XEvent) -> Option<XLibWindowEvent> {
|
||||||
|
match event.get_type() {
|
||||||
|
xlib::MapRequest => {
|
||||||
|
let ev = unsafe { &event.map_request };
|
||||||
|
Some(XLibWindowEvent::MapRequestEvent(MapEvent {
|
||||||
|
window: ev.window,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
xlib::UnmapNotify => {
|
||||||
|
let ev = unsafe { &event.unmap };
|
||||||
|
Some(XLibWindowEvent::UnmapEvent(UnmapEvent {
|
||||||
|
window: ev.window,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
xlib::ConfigureRequest => {
|
||||||
|
let ev = unsafe { &event.configure_request };
|
||||||
|
Some(XLibWindowEvent::ConfigureEvent(ConfigureEvent {
|
||||||
|
window: ev.window,
|
||||||
|
position: (ev.x, ev.y).into(),
|
||||||
|
size: (ev.width, ev.height).into(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
xlib::EnterNotify => {
|
||||||
|
let ev = unsafe { &event.crossing };
|
||||||
|
Some(XLibWindowEvent::EnterEvent(EnterEvent {
|
||||||
|
window: ev.window,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
xlib::DestroyNotify => {
|
||||||
|
let ev = unsafe { &event.destroy_window };
|
||||||
|
Some(XLibWindowEvent::DestroyEvent(DestroyEvent {
|
||||||
|
window: ev.window,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
// both ButtonPress and ButtonRelease use the XButtonEvent structure, aliased as either
|
||||||
|
// XButtonReleasedEvent or XButtonPressedEvent
|
||||||
|
xlib::ButtonPress | xlib::ButtonRelease => {
|
||||||
|
let ev = unsafe { &event.button };
|
||||||
|
let keycode = xev_to_mouse_button(ev).unwrap();
|
||||||
|
let state = if ev.state as i32 == xlib::ButtonPress {
|
||||||
|
KeyState::Pressed
|
||||||
|
} else {
|
||||||
|
KeyState::Released
|
||||||
|
};
|
||||||
|
|
||||||
|
let modifierstate = ModifierState::empty();
|
||||||
|
|
||||||
|
Some(XLibWindowEvent::ButtonEvent(ButtonEvent::new(
|
||||||
|
ev.subwindow,
|
||||||
|
state,
|
||||||
|
keycode,
|
||||||
|
(ev.x, ev.y).into(),
|
||||||
|
modifierstate,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn get_window_attributes(
|
||||||
|
&self,
|
||||||
|
window: xlib::Window,
|
||||||
|
) -> Option<xlib::XWindowAttributes> {
|
||||||
|
let mut wa = unsafe {
|
||||||
|
std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed()
|
||||||
|
.assume_init()
|
||||||
|
};
|
||||||
|
|
||||||
|
if unsafe {
|
||||||
|
xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0
|
||||||
|
} {
|
||||||
|
Some(wa)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_for_protocol(
|
fn check_for_protocol(
|
||||||
&self,
|
&self,
|
||||||
window: xlib::Window,
|
window: xlib::Window,
|
||||||
|
@ -286,72 +408,31 @@ impl XLib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<XEvent> for XLibWindowEvent {
|
|
||||||
type Error = crate::error::Error;
|
|
||||||
|
|
||||||
fn try_from(event: XEvent) -> Result<Self, Self::Error> {
|
|
||||||
match event.get_type() {
|
|
||||||
xlib::MapRequest => {
|
|
||||||
let ev = unsafe { &event.map_request };
|
|
||||||
Ok(Self::MapRequestEvent(MapEvent { window: ev.window }))
|
|
||||||
}
|
|
||||||
xlib::UnmapNotify => {
|
|
||||||
let ev = unsafe { &event.unmap };
|
|
||||||
Ok(Self::UnmapEvent(UnmapEvent { window: ev.window }))
|
|
||||||
}
|
|
||||||
xlib::ConfigureRequest => {
|
|
||||||
let ev = unsafe { &event.configure_request };
|
|
||||||
Ok(Self::ConfigureEvent(ConfigureEvent {
|
|
||||||
window: ev.window,
|
|
||||||
position: (ev.x, ev.y).into(),
|
|
||||||
size: (ev.width, ev.height).into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
xlib::EnterNotify => {
|
|
||||||
let ev = unsafe { &event.crossing };
|
|
||||||
Ok(Self::EnterEvent(EnterEvent { window: ev.window }))
|
|
||||||
}
|
|
||||||
xlib::DestroyNotify => {
|
|
||||||
let ev = unsafe { &event.destroy_window };
|
|
||||||
Ok(Self::DestroyEvent(DestroyEvent { window: ev.window }))
|
|
||||||
}
|
|
||||||
// both ButtonPress and ButtonRelease use the XButtonEvent structure, aliased as either
|
|
||||||
// XButtonReleasedEvent or XButtonPressedEvent
|
|
||||||
xlib::ButtonPress | xlib::ButtonRelease => {
|
|
||||||
let ev = unsafe { &event.button };
|
|
||||||
let keycode = xev_to_mouse_button(ev).unwrap();
|
|
||||||
let state = if ev.state as i32 == xlib::ButtonPress {
|
|
||||||
KeyState::Pressed
|
|
||||||
} else {
|
|
||||||
KeyState::Released
|
|
||||||
};
|
|
||||||
|
|
||||||
let modifierstate = ModifierState::empty();
|
|
||||||
|
|
||||||
Ok(Self::ButtonEvent(ButtonEvent::new(
|
|
||||||
ev.subwindow,
|
|
||||||
state,
|
|
||||||
keycode,
|
|
||||||
(ev.x, ev.y).into(),
|
|
||||||
modifierstate,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
_ => Err(Self::Error::UnknownEvent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowServerBackend for XLib {
|
impl WindowServerBackend for XLib {
|
||||||
type Window = xlib::Window;
|
type Window = xlib::Window;
|
||||||
|
|
||||||
|
fn build() -> Self {
|
||||||
|
let xlib = Self::new();
|
||||||
|
unsafe { xlib.init_as_wm() };
|
||||||
|
xlib
|
||||||
|
}
|
||||||
|
|
||||||
fn next_event(&mut self) -> super::window_event::WindowEvent<Self::Window> {
|
fn next_event(&mut self) -> super::window_event::WindowEvent<Self::Window> {
|
||||||
std::iter::from_fn(|| {
|
std::iter::from_fn(|| {
|
||||||
TryInto::<XLibWindowEvent>::try_into(self.next_xevent()).ok()
|
let ev = self.next_xevent();
|
||||||
|
self.xevent_to_window_event(ev)
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_event(
|
||||||
|
&mut self,
|
||||||
|
event: super::window_event::WindowEvent<Self::Window>,
|
||||||
|
) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn add_keybind(
|
fn add_keybind(
|
||||||
&mut self,
|
&mut self,
|
||||||
keybind: super::window_event::KeyBind,
|
keybind: super::window_event::KeyBind,
|
||||||
|
@ -370,7 +451,7 @@ impl WindowServerBackend for XLib {
|
||||||
|
|
||||||
fn add_mousebind(
|
fn add_mousebind(
|
||||||
&mut self,
|
&mut self,
|
||||||
keybind: super::window_event::KeyBind,
|
keybind: super::window_event::MouseBind,
|
||||||
window: Option<Self::Window>,
|
window: Option<Self::Window>,
|
||||||
) {
|
) {
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -378,43 +459,76 @@ impl WindowServerBackend for XLib {
|
||||||
|
|
||||||
fn remove_mousebind(
|
fn remove_mousebind(
|
||||||
&mut self,
|
&mut self,
|
||||||
keybind: super::window_event::KeyBind,
|
keybind: super::window_event::MouseBind,
|
||||||
window: Option<Self::Window>,
|
window: Option<Self::Window>,
|
||||||
) {
|
) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_window(&self, window: Self::Window) {
|
fn focus_window(&self, window: Self::Window) {
|
||||||
todo!()
|
unsafe {
|
||||||
|
xlib::XSetInputFocus(
|
||||||
|
self.dpy(),
|
||||||
|
window,
|
||||||
|
xlib::RevertToPointerRoot,
|
||||||
|
xlib::CurrentTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: make painting the window border a seperate function, and configurable
|
||||||
|
let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
|
||||||
|
|
||||||
|
if let Some(screen) = screen {
|
||||||
|
xlib::XSetWindowBorder(self.dpy(), window, screen.white_pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
xlib::XChangeProperty(
|
||||||
|
self.dpy(),
|
||||||
|
self.root,
|
||||||
|
self.atoms.wm_active_window,
|
||||||
|
xlib::XA_WINDOW,
|
||||||
|
32,
|
||||||
|
xlib::PropModeReplace,
|
||||||
|
&window as *const u64 as *const _,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.send_protocol(window, self.atoms.wm_take_focus);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unfocus_window(&self, window: Self::Window) {
|
fn unfocus_window(&self, window: Self::Window) {
|
||||||
todo!()
|
unsafe {
|
||||||
|
xlib::XSetInputFocus(
|
||||||
|
self.dpy(),
|
||||||
|
self.root,
|
||||||
|
xlib::RevertToPointerRoot,
|
||||||
|
xlib::CurrentTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: make painting the window border a seperate function, and configurable
|
||||||
|
let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref();
|
||||||
|
|
||||||
|
if let Some(screen) = screen {
|
||||||
|
xlib::XSetWindowBorder(self.dpy(), window, screen.black_pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_window(&self, window: Self::Window, new_pos: (i32, i32)) {
|
xlib::XDeleteProperty(
|
||||||
todo!()
|
self.dpy(),
|
||||||
|
self.root,
|
||||||
|
self.atoms.wm_active_window,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize_window(&self, window: Self::Window, new_pos: (i32, i32)) {
|
fn raise_window(&self, window: Self::Window) {
|
||||||
todo!()
|
unsafe {
|
||||||
|
xlib::XRaiseWindow(self.dpy(), window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hide_window(&self, window: Self::Window) {
|
fn hide_window(&self, window: Self::Window) {
|
||||||
todo!()
|
let screen_size = self.screen_size();
|
||||||
}
|
self.move_window(window, screen_size);
|
||||||
|
|
||||||
fn screen_size(&self) -> (i32, i32) {
|
|
||||||
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) {
|
||||||
|
@ -426,20 +540,69 @@ impl WindowServerBackend for XLib {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raise_window(&self, window: Self::Window) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_parent_window(&self, window: Self::Window) -> Option<Self::Window> {
|
fn get_parent_window(&self, window: Self::Window) -> Option<Self::Window> {
|
||||||
todo!()
|
let mut parent_window: Self::Window = 0;
|
||||||
|
if unsafe {
|
||||||
|
xlib::XGetTransientForHint(self.dpy(), window, &mut parent_window)
|
||||||
|
!= 0
|
||||||
|
} {
|
||||||
|
Some(parent_window)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_window_size(&self, window: Self::Window) -> Option<(i32, i32)> {
|
fn configure_window(
|
||||||
todo!()
|
&self,
|
||||||
|
window: Self::Window,
|
||||||
|
new_size: Option<super::window_event::Point<i32>>,
|
||||||
|
new_pos: Option<super::window_event::Point<i32>>,
|
||||||
|
) {
|
||||||
|
let position = new_pos.unwrap_or(Point::new(0, 0));
|
||||||
|
let size = new_size.unwrap_or(Point::new(0, 0));
|
||||||
|
let mut wc = xlib::XWindowChanges {
|
||||||
|
x: position.x,
|
||||||
|
y: position.y,
|
||||||
|
width: size.x,
|
||||||
|
height: size.y,
|
||||||
|
border_width: 0,
|
||||||
|
sibling: 0,
|
||||||
|
stack_mode: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mask = {
|
||||||
|
let mut mask = 0;
|
||||||
|
if new_pos.is_some() {
|
||||||
|
mask |= xlib::CWX | xlib::CWY;
|
||||||
|
}
|
||||||
|
if new_size.is_some() {
|
||||||
|
mask |= xlib::CWWidth | xlib::CWHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> Self {
|
u32::from(mask)
|
||||||
todo!()
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xlib::XConfigureWindow(self.dpy(), window, mask, &mut wc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_size(&self) -> Point<i32> {
|
||||||
|
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).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_window_size(&self, window: Self::Window) -> Option<Point<i32>> {
|
||||||
|
self.get_window_attributes(window)
|
||||||
|
.map(|wa| (wa.width, wa.height).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue