1
0
Fork 0

x11: Event::WillClose support

this is a nightmare of ICCCM protocols but hey it's done now.
This commit is contained in:
William Light 2020-09-11 18:02:22 +02:00
parent ce48ae111a
commit b64183fb19
4 changed files with 89 additions and 7 deletions

View file

@ -17,6 +17,7 @@ raw-window-handle = "0.3.3"
[target.'cfg(target_os="linux")'.dependencies]
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] }
x11 = { version = "2.18", features = ["xlib"] }
xcb-util = { version = "0.3", features = ["icccm"] }
libc = "0.2"
nix = "0.18"

View file

@ -22,7 +22,7 @@ impl WindowHandler for MyProgram {
fn on_frame(&mut self) {}
fn on_event(&mut self, _window: &mut Window, event: Event) {
fn on_event(&mut self, window: &mut Window, event: Event) {
match event {
Event::CursorMotion(x, y) => {
println!("Cursor moved, x: {}, y: {}", x, y);

View file

@ -89,6 +89,17 @@ impl Window {
title.as_bytes(),
);
xcb_connection.atoms.wm_protocols
.zip(xcb_connection.atoms.wm_delete_window)
.map(|(wm_protocols, wm_delete_window)| {
xcb_util::icccm::set_wm_protocols(
&xcb_connection.conn,
window_id,
wm_protocols,
&[wm_delete_window]
);
});
xcb_connection.conn.flush();
let scaling = xcb_connection.get_scaling().unwrap_or(1.0);
@ -187,9 +198,35 @@ impl Window {
// http://rtbo.github.io/rust-xcb/src/xcb/ffi/xproto.rs.html#445
match event_type {
////
// keys
////
xcb::EXPOSE => {
handler.on_frame();
}
xcb::CLIENT_MESSAGE => {
let event = unsafe { xcb::cast_event::<xcb::ClientMessageEvent>(&event) };
// what an absolute trajedy this all is
let data = event.data().data;
let (_, data32, _) = unsafe { data.align_to::<u32>() };
let wm_delete_window = self.xcb_connection.atoms.wm_delete_window.unwrap_or(xcb::NONE);
if wm_delete_window == data32[0] {
handler.on_event(self, Event::WillClose);
// FIXME: handler should decide whether window stays open or not
self.event_loop_running = false;
}
}
////
// mouse
////
xcb::MOTION_NOTIFY => {
let event = unsafe { xcb::cast_event::<xcb::MotionNotifyEvent>(&event) };
let detail = event.detail();
@ -201,6 +238,7 @@ impl Window {
);
}
}
xcb::BUTTON_PRESS => {
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
let detail = event.detail();
@ -230,6 +268,7 @@ impl Window {
}
}
}
xcb::BUTTON_RELEASE => {
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
let detail = event.detail();
@ -239,18 +278,25 @@ impl Window {
handler.on_event(self, Event::MouseUp(button_id));
}
}
////
// keys
////
xcb::KEY_PRESS => {
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
let detail = event.detail();
handler.on_event(self, Event::KeyDown(detail));
}
xcb::KEY_RELEASE => {
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
let detail = event.detail();
handler.on_event(self, Event::KeyUp(detail));
}
_ => {
println!("Unhandled event type: {:?}", event_type);
}

View file

@ -7,19 +7,54 @@ use std::ffi::{
CStr
};
pub(crate) struct Atoms {
pub wm_protocols: Option<u32>,
pub wm_delete_window: Option<u32>
}
pub struct XcbConnection {
pub conn: xcb::Connection,
pub xlib_display: i32,
pub(crate) atoms: Atoms
}
macro_rules! intern_atoms {
($conn:expr, $( $name:ident ),+ ) => {{
$(
#[allow(non_snake_case)]
let $name = xcb::intern_atom($conn, true, stringify!($name));
)+
// splitting request and reply to improve throughput
(
$( $name.get_reply()
.map(|r| r.atom())
.ok()),+
)
}};
}
impl XcbConnection {
pub fn new() -> Result<Self, xcb::base::ConnError> {
xcb::Connection::connect_with_xlib_display()
.map(|(conn, xlib_display)|
Self {
conn,
xlib_display
})
let (conn, xlib_display) = xcb::Connection::connect_with_xlib_display()?;
let (wm_protocols, wm_delete_window) =
intern_atoms!(&conn,
WM_PROTOCOLS,
WM_DELETE_WINDOW);
Ok(Self {
conn,
xlib_display,
atoms: Atoms {
wm_protocols,
wm_delete_window
}
})
}
// Try to get the scaling with this function first.