x11: Event::WillClose support
this is a nightmare of ICCCM protocols but hey it's done now.
This commit is contained in:
parent
ce48ae111a
commit
b64183fb19
4 changed files with 89 additions and 7 deletions
|
@ -17,6 +17,7 @@ raw-window-handle = "0.3.3"
|
||||||
[target.'cfg(target_os="linux")'.dependencies]
|
[target.'cfg(target_os="linux")'.dependencies]
|
||||||
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] }
|
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] }
|
||||||
x11 = { version = "2.18", features = ["xlib"] }
|
x11 = { version = "2.18", features = ["xlib"] }
|
||||||
|
xcb-util = { version = "0.3", features = ["icccm"] }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
nix = "0.18"
|
nix = "0.18"
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ impl WindowHandler for MyProgram {
|
||||||
|
|
||||||
fn on_frame(&mut self) {}
|
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 {
|
match event {
|
||||||
Event::CursorMotion(x, y) => {
|
Event::CursorMotion(x, y) => {
|
||||||
println!("Cursor moved, x: {}, y: {}", x, y);
|
println!("Cursor moved, x: {}, y: {}", x, y);
|
||||||
|
|
|
@ -89,6 +89,17 @@ impl Window {
|
||||||
title.as_bytes(),
|
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();
|
xcb_connection.conn.flush();
|
||||||
|
|
||||||
let scaling = xcb_connection.get_scaling().unwrap_or(1.0);
|
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
|
// http://rtbo.github.io/rust-xcb/src/xcb/ffi/xproto.rs.html#445
|
||||||
|
|
||||||
match event_type {
|
match event_type {
|
||||||
|
////
|
||||||
|
// keys
|
||||||
|
////
|
||||||
|
|
||||||
xcb::EXPOSE => {
|
xcb::EXPOSE => {
|
||||||
handler.on_frame();
|
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 => {
|
xcb::MOTION_NOTIFY => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::MotionNotifyEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::MotionNotifyEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
@ -201,6 +238,7 @@ impl Window {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb::BUTTON_PRESS => {
|
xcb::BUTTON_PRESS => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
@ -230,6 +268,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb::BUTTON_RELEASE => {
|
xcb::BUTTON_RELEASE => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
@ -239,18 +278,25 @@ impl Window {
|
||||||
handler.on_event(self, Event::MouseUp(button_id));
|
handler.on_event(self, Event::MouseUp(button_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
// keys
|
||||||
|
////
|
||||||
|
|
||||||
xcb::KEY_PRESS => {
|
xcb::KEY_PRESS => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
|
||||||
handler.on_event(self, Event::KeyDown(detail));
|
handler.on_event(self, Event::KeyDown(detail));
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb::KEY_RELEASE => {
|
xcb::KEY_RELEASE => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
|
||||||
handler.on_event(self, Event::KeyUp(detail));
|
handler.on_event(self, Event::KeyUp(detail));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unhandled event type: {:?}", event_type);
|
println!("Unhandled event type: {:?}", event_type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,19 +7,54 @@ use std::ffi::{
|
||||||
CStr
|
CStr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) struct Atoms {
|
||||||
|
pub wm_protocols: Option<u32>,
|
||||||
|
pub wm_delete_window: Option<u32>
|
||||||
|
}
|
||||||
|
|
||||||
pub struct XcbConnection {
|
pub struct XcbConnection {
|
||||||
pub conn: xcb::Connection,
|
pub conn: xcb::Connection,
|
||||||
pub xlib_display: i32,
|
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 {
|
impl XcbConnection {
|
||||||
pub fn new() -> Result<Self, xcb::base::ConnError> {
|
pub fn new() -> Result<Self, xcb::base::ConnError> {
|
||||||
xcb::Connection::connect_with_xlib_display()
|
let (conn, xlib_display) = xcb::Connection::connect_with_xlib_display()?;
|
||||||
.map(|(conn, xlib_display)|
|
|
||||||
Self {
|
let (wm_protocols, wm_delete_window) =
|
||||||
conn,
|
intern_atoms!(&conn,
|
||||||
xlib_display
|
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.
|
// Try to get the scaling with this function first.
|
||||||
|
|
Loading…
Add table
Reference in a new issue