mirror of
https://github.com/wez/wezterm.git
synced 2024-11-10 15:04:32 +03:00
basic xcb windows too
This commit is contained in:
parent
ddd323464b
commit
dc6ef6c55d
@ -26,3 +26,12 @@ winapi = { version = "0.3", features = [
|
||||
"winuser",
|
||||
]}
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
|
||||
x11 = {version ="2.18", features = ["xlib_xcb"]}
|
||||
xcb = "0.8"
|
||||
xcb-util = { features = [ "icccm", "ewmh", "keysyms", ], version = "0.2" }
|
||||
xkbcommon = { version = "0.4", features = ["x11"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
mio = "0.6"
|
||||
mio-extras = "2.0"
|
||||
|
@ -1,5 +1,5 @@
|
||||
use ::window::*;
|
||||
use failure::Fallible;
|
||||
use window::*;
|
||||
|
||||
struct MyWindow {
|
||||
allow_close: bool,
|
||||
@ -9,7 +9,7 @@ impl WindowCallbacks for MyWindow {
|
||||
fn can_close(&mut self) -> bool {
|
||||
eprintln!("can I close?");
|
||||
if self.allow_close {
|
||||
terminate_message_loop();
|
||||
Connection::get().unwrap().terminate_message_loop();
|
||||
true
|
||||
} else {
|
||||
self.allow_close = true;
|
||||
@ -19,6 +19,8 @@ impl WindowCallbacks for MyWindow {
|
||||
}
|
||||
|
||||
fn main() -> Fallible<()> {
|
||||
let conn = Connection::init()?;
|
||||
|
||||
let win = Window::new_window(
|
||||
"myclass",
|
||||
"the title",
|
||||
@ -29,5 +31,5 @@ fn main() -> Fallible<()> {
|
||||
|
||||
win.show();
|
||||
|
||||
run_message_loop()
|
||||
conn.run_message_loop()
|
||||
}
|
||||
|
@ -5,8 +5,7 @@ pub mod os;
|
||||
pub use bitmaps::BitmapImage;
|
||||
pub use color::Color;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub use os::windows::window::*;
|
||||
pub use os::*;
|
||||
|
||||
/// Compositing operator.
|
||||
/// We implement a small subset of possible compositing operators.
|
||||
|
@ -1,2 +1,9 @@
|
||||
#[cfg(windows)]
|
||||
pub mod windows;
|
||||
#[cfg(windows)]
|
||||
pub use windows::*;
|
||||
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
pub mod x11;
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
pub use self::x11::*;
|
||||
|
55
window/src/os/windows/connection.rs
Normal file
55
window/src/os/windows/connection.rs
Normal file
@ -0,0 +1,55 @@
|
||||
//! The connection to the GUI subsystem
|
||||
use failure::Fallible;
|
||||
use std::cell::RefCell;
|
||||
use std::io::Error as IoError;
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::Arc;
|
||||
use winapi::um::winuser::*;
|
||||
|
||||
pub struct Connection {}
|
||||
|
||||
thread_local! {
|
||||
static CONN: RefCell<Option<Arc<Connection>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub fn get() -> Option<Arc<Self>> {
|
||||
let mut res = None;
|
||||
CONN.with(|m| {
|
||||
if let Some(mux) = &*m.borrow() {
|
||||
res = Some(Arc::clone(mux));
|
||||
}
|
||||
});
|
||||
res
|
||||
}
|
||||
|
||||
pub fn init() -> Fallible<Arc<Self>> {
|
||||
let conn = Arc::new(Self {});
|
||||
CONN.with(|m| *m.borrow_mut() = Some(Arc::clone(&conn)));
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub fn terminate_message_loop(&self) {
|
||||
unsafe {
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_message_loop(&self) -> Fallible<()> {
|
||||
let mut msg: MSG = unsafe { std::mem::zeroed() };
|
||||
loop {
|
||||
let res = unsafe { GetMessageW(&mut msg, null_mut(), 0, 0) };
|
||||
if res == -1 {
|
||||
return Err(IoError::last_os_error().into());
|
||||
}
|
||||
if res == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
TranslateMessage(&mut msg);
|
||||
DispatchMessageW(&mut msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
pub mod connection;
|
||||
pub mod gdi;
|
||||
pub mod window;
|
||||
|
||||
pub use connection::*;
|
||||
pub use gdi::*;
|
||||
pub use window::*;
|
||||
|
||||
/// Convert a rust string to a windows wide string
|
||||
fn wide_string(s: &str) -> Vec<u16> {
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
|
@ -369,27 +369,3 @@ unsafe extern "system" fn wnd_proc(
|
||||
Err(_) => std::process::exit(1),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_message_loop() -> Fallible<()> {
|
||||
let mut msg: MSG = unsafe { std::mem::zeroed() };
|
||||
loop {
|
||||
let res = unsafe { GetMessageW(&mut msg, null_mut(), 0, 0) };
|
||||
if res == -1 {
|
||||
return Err(IoError::last_os_error().into());
|
||||
}
|
||||
if res == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
TranslateMessage(&mut msg);
|
||||
DispatchMessageW(&mut msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn terminate_message_loop() {
|
||||
unsafe {
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
}
|
||||
|
229
window/src/os/x11/connection.rs
Normal file
229
window/src/os/x11/connection.rs
Normal file
@ -0,0 +1,229 @@
|
||||
use crate::Window;
|
||||
use failure::Fallible;
|
||||
use mio::unix::EventedFd;
|
||||
use mio::{Evented, Poll, PollOpt, Ready, Token};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::Arc;
|
||||
use xcb_util::ffi::keysyms::{xcb_key_symbols_alloc, xcb_key_symbols_free, xcb_key_symbols_t};
|
||||
|
||||
pub struct Connection {
|
||||
pub display: *mut x11::xlib::Display,
|
||||
conn: xcb::Connection,
|
||||
screen_num: i32,
|
||||
pub atom_protocols: xcb::Atom,
|
||||
pub atom_delete: xcb::Atom,
|
||||
pub atom_utf8_string: xcb::Atom,
|
||||
pub atom_xsel_data: xcb::Atom,
|
||||
pub atom_targets: xcb::Atom,
|
||||
pub atom_clipboard: xcb::Atom,
|
||||
keysyms: *mut xcb_key_symbols_t,
|
||||
pub(crate) windows: RefCell<HashMap<xcb::xproto::Window, Window>>,
|
||||
should_terminate: RefCell<bool>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Connection {
|
||||
type Target = xcb::Connection;
|
||||
|
||||
fn deref(&self) -> &xcb::Connection {
|
||||
&self.conn
|
||||
}
|
||||
}
|
||||
|
||||
impl Evented for Connection {
|
||||
fn register(
|
||||
&self,
|
||||
poll: &Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> std::io::Result<()> {
|
||||
EventedFd(&self.conn.as_raw_fd()).register(poll, token, interest, opts)
|
||||
}
|
||||
|
||||
fn reregister(
|
||||
&self,
|
||||
poll: &Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> std::io::Result<()> {
|
||||
EventedFd(&self.conn.as_raw_fd()).reregister(poll, token, interest, opts)
|
||||
}
|
||||
|
||||
fn deregister(&self, poll: &Poll) -> std::io::Result<()> {
|
||||
EventedFd(&self.conn.as_raw_fd()).deregister(poll)
|
||||
}
|
||||
}
|
||||
|
||||
#[link(name = "X11-xcb")]
|
||||
extern "C" {
|
||||
fn XGetXCBConnection(display: *mut x11::xlib::Display) -> *mut xcb::ffi::xcb_connection_t;
|
||||
fn XSetEventQueueOwner(display: *mut x11::xlib::Display, owner: i32);
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static CONN: RefCell<Option<Arc<Connection>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
fn window_id_from_event(event: &xcb::GenericEvent) -> Option<xcb::xproto::Window> {
|
||||
match event.response_type() & 0x7f {
|
||||
xcb::EXPOSE => {
|
||||
let expose: &xcb::ExposeEvent = unsafe { xcb::cast_event(event) };
|
||||
Some(expose.window())
|
||||
}
|
||||
xcb::CONFIGURE_NOTIFY => {
|
||||
let cfg: &xcb::ConfigureNotifyEvent = unsafe { xcb::cast_event(event) };
|
||||
Some(cfg.window())
|
||||
}
|
||||
xcb::KEY_PRESS | xcb::KEY_RELEASE => {
|
||||
let key_press: &xcb::KeyPressEvent = unsafe { xcb::cast_event(event) };
|
||||
Some(key_press.event())
|
||||
}
|
||||
xcb::MOTION_NOTIFY => {
|
||||
let motion: &xcb::MotionNotifyEvent = unsafe { xcb::cast_event(event) };
|
||||
Some(motion.event())
|
||||
}
|
||||
xcb::BUTTON_PRESS | xcb::BUTTON_RELEASE => {
|
||||
let button_press: &xcb::ButtonPressEvent = unsafe { xcb::cast_event(event) };
|
||||
Some(button_press.event())
|
||||
}
|
||||
xcb::CLIENT_MESSAGE => {
|
||||
let msg: &xcb::ClientMessageEvent = unsafe { xcb::cast_event(event) };
|
||||
Some(msg.window())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub fn get() -> Option<Arc<Self>> {
|
||||
let mut res = None;
|
||||
CONN.with(|m| {
|
||||
if let Some(mux) = &*m.borrow() {
|
||||
res = Some(Arc::clone(mux));
|
||||
}
|
||||
});
|
||||
res
|
||||
}
|
||||
|
||||
pub fn terminate_message_loop(&self) {
|
||||
*self.should_terminate.borrow_mut() = true;
|
||||
}
|
||||
|
||||
pub fn run_message_loop(&self) -> Fallible<()> {
|
||||
self.conn.flush();
|
||||
while let Some(event) = self.conn.wait_for_event() {
|
||||
self.process_xcb_event(&event)?;
|
||||
self.conn.flush();
|
||||
if *self.should_terminate.borrow() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_xcb_event(&self, event: &xcb::GenericEvent) -> Fallible<()> {
|
||||
if let Some(window_id) = window_id_from_event(event) {
|
||||
self.process_window_event(window_id, event)?;
|
||||
} else {
|
||||
/*
|
||||
let r = event.response_type() & 0x7f;
|
||||
if r == self.conn.kbd_ev {
|
||||
// key press/release are not processed here.
|
||||
// xkbcommon depends on those events in order to:
|
||||
// - update modifiers state
|
||||
// - update keymap/state on keyboard changes
|
||||
self.conn.keyboard.process_xkb_event(&self.conn, event)?;
|
||||
}
|
||||
*/
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn window_by_id(&self, window_id: xcb::xproto::Window) -> Option<Window> {
|
||||
self.windows.borrow().get(&window_id).cloned()
|
||||
}
|
||||
|
||||
fn process_window_event(
|
||||
&self,
|
||||
window_id: xcb::xproto::Window,
|
||||
event: &xcb::GenericEvent,
|
||||
) -> Fallible<()> {
|
||||
if let Some(window) = self.window_by_id(window_id) {
|
||||
window.dispatch_event(event)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init() -> Fallible<Arc<Connection>> {
|
||||
let display = unsafe { x11::xlib::XOpenDisplay(std::ptr::null()) };
|
||||
if display.is_null() {
|
||||
failure::bail!("failed to open display");
|
||||
}
|
||||
let screen_num = unsafe { x11::xlib::XDefaultScreen(display) };
|
||||
let conn = unsafe { xcb::Connection::from_raw_conn(XGetXCBConnection(display)) };
|
||||
unsafe { XSetEventQueueOwner(display, 1) };
|
||||
|
||||
let atom_protocols = xcb::intern_atom(&conn, false, "WM_PROTOCOLS")
|
||||
.get_reply()?
|
||||
.atom();
|
||||
let atom_delete = xcb::intern_atom(&conn, false, "WM_DELETE_WINDOW")
|
||||
.get_reply()?
|
||||
.atom();
|
||||
let atom_utf8_string = xcb::intern_atom(&conn, false, "UTF8_STRING")
|
||||
.get_reply()?
|
||||
.atom();
|
||||
let atom_xsel_data = xcb::intern_atom(&conn, false, "XSEL_DATA")
|
||||
.get_reply()?
|
||||
.atom();
|
||||
let atom_targets = xcb::intern_atom(&conn, false, "TARGETS")
|
||||
.get_reply()?
|
||||
.atom();
|
||||
let atom_clipboard = xcb::intern_atom(&conn, false, "CLIPBOARD")
|
||||
.get_reply()?
|
||||
.atom();
|
||||
|
||||
let keysyms = unsafe { xcb_key_symbols_alloc(conn.get_raw_conn()) };
|
||||
|
||||
let conn = Arc::new(Connection {
|
||||
display,
|
||||
conn,
|
||||
screen_num,
|
||||
atom_protocols,
|
||||
atom_clipboard,
|
||||
atom_delete,
|
||||
keysyms,
|
||||
atom_utf8_string,
|
||||
atom_xsel_data,
|
||||
atom_targets,
|
||||
windows: RefCell::new(HashMap::new()),
|
||||
should_terminate: RefCell::new(false),
|
||||
});
|
||||
|
||||
CONN.with(|m| *m.borrow_mut() = Some(Arc::clone(&conn)));
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub fn conn(&self) -> &xcb::Connection {
|
||||
&self.conn
|
||||
}
|
||||
|
||||
pub fn screen_num(&self) -> i32 {
|
||||
self.screen_num
|
||||
}
|
||||
|
||||
pub fn atom_delete(&self) -> xcb::Atom {
|
||||
self.atom_delete
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Connection {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
xcb_key_symbols_free(self.keysyms);
|
||||
}
|
||||
}
|
||||
}
|
4
window/src/os/x11/mod.rs
Normal file
4
window/src/os/x11/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod connection;
|
||||
pub mod window;
|
||||
pub use connection::*;
|
||||
pub use window::*;
|
225
window/src/os/x11/window.rs
Normal file
225
window/src/os/x11/window.rs
Normal file
@ -0,0 +1,225 @@
|
||||
use super::connection::*;
|
||||
use crate::WindowCallbacks;
|
||||
use failure::Fallible;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
struct WindowHolder {
|
||||
window_id: xcb::xproto::Window,
|
||||
conn: Arc<Connection>,
|
||||
callbacks: Mutex<Box<WindowCallbacks>>,
|
||||
}
|
||||
|
||||
impl Drop for WindowHolder {
|
||||
fn drop(&mut self) {
|
||||
xcb::destroy_window(self.conn.conn(), self.window_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// A Window!
|
||||
#[derive(Clone)]
|
||||
pub struct Window {
|
||||
window: Arc<WindowHolder>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
/// Create a new window on the specified screen with the specified
|
||||
/// dimensions
|
||||
pub fn new_window(
|
||||
_class_name: &str,
|
||||
name: &str,
|
||||
width: usize,
|
||||
height: usize,
|
||||
callbacks: Box<WindowCallbacks>,
|
||||
) -> Fallible<Window> {
|
||||
let conn = Connection::get().ok_or_else(|| {
|
||||
failure::err_msg(
|
||||
"new_window must be called on the gui thread after Connection::init has succeeded",
|
||||
)
|
||||
})?;
|
||||
|
||||
let window = {
|
||||
let setup = conn.conn().get_setup();
|
||||
let screen = setup
|
||||
.roots()
|
||||
.nth(conn.screen_num() as usize)
|
||||
.ok_or_else(|| failure::err_msg("no screen?"))?;
|
||||
|
||||
let window_id = conn.conn().generate_id();
|
||||
|
||||
xcb::create_window_checked(
|
||||
conn.conn(),
|
||||
xcb::COPY_FROM_PARENT as u8,
|
||||
window_id,
|
||||
screen.root(),
|
||||
// x, y
|
||||
0,
|
||||
0,
|
||||
// width, height
|
||||
width.try_into()?,
|
||||
height.try_into()?,
|
||||
// border width
|
||||
0,
|
||||
xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
|
||||
screen.root_visual(),
|
||||
&[(
|
||||
xcb::CW_EVENT_MASK,
|
||||
xcb::EVENT_MASK_EXPOSURE
|
||||
| xcb::EVENT_MASK_KEY_PRESS
|
||||
| xcb::EVENT_MASK_BUTTON_PRESS
|
||||
| xcb::EVENT_MASK_BUTTON_RELEASE
|
||||
| xcb::EVENT_MASK_POINTER_MOTION
|
||||
| xcb::EVENT_MASK_BUTTON_MOTION
|
||||
| xcb::EVENT_MASK_KEY_RELEASE
|
||||
| xcb::EVENT_MASK_STRUCTURE_NOTIFY,
|
||||
)],
|
||||
)
|
||||
.request_check()?;
|
||||
Arc::new(WindowHolder {
|
||||
window_id,
|
||||
conn: Arc::clone(&conn),
|
||||
callbacks: Mutex::new(callbacks),
|
||||
})
|
||||
};
|
||||
|
||||
xcb::change_property(
|
||||
&*conn,
|
||||
xcb::PROP_MODE_REPLACE as u8,
|
||||
window.window_id,
|
||||
conn.atom_protocols,
|
||||
4,
|
||||
32,
|
||||
&[conn.atom_delete],
|
||||
);
|
||||
|
||||
let window = Window { window };
|
||||
|
||||
conn.windows
|
||||
.borrow_mut()
|
||||
.insert(window.window.window_id, window.clone());
|
||||
|
||||
window.set_title(name);
|
||||
window.show();
|
||||
|
||||
Ok(window)
|
||||
}
|
||||
|
||||
/// Change the title for the window manager
|
||||
pub fn set_title(&self, title: &str) {
|
||||
xcb_util::icccm::set_wm_name(self.window.conn.conn(), self.window.window_id, title);
|
||||
}
|
||||
|
||||
/// Display the window
|
||||
pub fn show(&self) {
|
||||
xcb::map_window(self.window.conn.conn(), self.window.window_id);
|
||||
}
|
||||
|
||||
pub fn dispatch_event(&self, event: &xcb::GenericEvent) -> Fallible<()> {
|
||||
let r = event.response_type() & 0x7f;
|
||||
match r {
|
||||
xcb::EXPOSE => {
|
||||
let expose: &xcb::ExposeEvent = unsafe { xcb::cast_event(event) };
|
||||
eprintln!("EXPOSE");
|
||||
//self.expose(expose.x(), expose.y(), expose.width(), expose.height())?;
|
||||
}
|
||||
xcb::CONFIGURE_NOTIFY => {
|
||||
let cfg: &xcb::ConfigureNotifyEvent = unsafe { xcb::cast_event(event) };
|
||||
eprintln!("CONFIGURE_NOTIFY");
|
||||
/*
|
||||
let schedule = self.have_pending_resize.is_none();
|
||||
self.have_pending_resize = Some((cfg.width(), cfg.height()));
|
||||
if schedule {
|
||||
self.host.with_window(|win| win.check_for_resize());
|
||||
}
|
||||
*/
|
||||
}
|
||||
xcb::KEY_PRESS => {
|
||||
let key_press: &xcb::KeyPressEvent = unsafe { xcb::cast_event(event) };
|
||||
eprintln!("KEY_PRESS");
|
||||
/*
|
||||
let mux = Mux::get().unwrap();
|
||||
let tab = match mux.get_active_tab_for_window(self.get_mux_window_id()) {
|
||||
Some(tab) => tab,
|
||||
None => return Ok(()),
|
||||
};
|
||||
if let Some((code, mods)) = self.decode_key(key_press) {
|
||||
if self.host.process_gui_shortcuts(&*tab, mods, code)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
tab.key_down(code, mods)?;
|
||||
}
|
||||
*/
|
||||
}
|
||||
xcb::MOTION_NOTIFY => {
|
||||
let motion: &xcb::MotionNotifyEvent = unsafe { xcb::cast_event(event) };
|
||||
eprintln!("MOTION_NOTIFY");
|
||||
/*
|
||||
|
||||
let event = MouseEvent {
|
||||
kind: MouseEventKind::Move,
|
||||
button: MouseButton::None,
|
||||
x: (motion.event_x() as usize / self.cell_width) as usize,
|
||||
y: (motion.event_y() as usize / self.cell_height) as i64,
|
||||
modifiers: xkeysyms::modifiers_from_state(motion.state()),
|
||||
};
|
||||
self.mouse_event(event)?;
|
||||
*/
|
||||
}
|
||||
xcb::BUTTON_PRESS | xcb::BUTTON_RELEASE => {
|
||||
let button_press: &xcb::ButtonPressEvent = unsafe { xcb::cast_event(event) };
|
||||
eprintln!("BUTTON_PRESS");
|
||||
/*
|
||||
|
||||
let event = MouseEvent {
|
||||
kind: match r {
|
||||
xcb::BUTTON_PRESS => MouseEventKind::Press,
|
||||
xcb::BUTTON_RELEASE => MouseEventKind::Release,
|
||||
_ => unreachable!("button event mismatch"),
|
||||
},
|
||||
x: (button_press.event_x() as usize / self.cell_width) as usize,
|
||||
y: (button_press.event_y() as usize / self.cell_height) as i64,
|
||||
button: match button_press.detail() {
|
||||
1 => MouseButton::Left,
|
||||
2 => MouseButton::Middle,
|
||||
3 => MouseButton::Right,
|
||||
4 => MouseButton::WheelUp(1),
|
||||
5 => MouseButton::WheelDown(1),
|
||||
_ => {
|
||||
error!("button {} is not implemented", button_press.detail());
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
modifiers: xkeysyms::modifiers_from_state(button_press.state()),
|
||||
};
|
||||
|
||||
self.mouse_event(event)?;
|
||||
*/
|
||||
}
|
||||
xcb::CLIENT_MESSAGE => {
|
||||
let msg: &xcb::ClientMessageEvent = unsafe { xcb::cast_event(event) };
|
||||
eprintln!("CLIENT_MESSAGE {:?}", msg.data().data32());
|
||||
if msg.data().data32()[0] == self.window.conn.atom_delete() {
|
||||
eprintln!("close requested");
|
||||
if self.window.callbacks.lock().unwrap().can_close() {
|
||||
self.close_window();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
eprintln!("unhandled: {:x}", r);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn close_window(&self) {
|
||||
self.window
|
||||
.conn
|
||||
.windows
|
||||
.borrow_mut()
|
||||
.remove(&self.window.window_id);
|
||||
xcb::destroy_window(self.window.conn.conn(), self.window.window_id);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user