gpui: Switch to x11rb
(#9113)
Switch to using `x11rb` crate instead of current `xcb` crate for gpui's x11 platform. Also fixes the crash on resize, and white flashing on resize. Release Notes: - N/A --------- Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
47afc70979
commit
80b80dfa78
6 changed files with 288 additions and 276 deletions
|
@ -9,10 +9,11 @@ use crate::{
|
|||
use blade_graphics as gpu;
|
||||
use parking_lot::Mutex;
|
||||
use raw_window_handle as rwh;
|
||||
|
||||
use xcb::{
|
||||
x::{self, StackMode},
|
||||
Xid as _,
|
||||
use x11rb::{
|
||||
connection::Connection,
|
||||
protocol::xproto::{self, ConnectionExt as _, CreateWindowAux},
|
||||
wrapper::ConnectionExt,
|
||||
xcb_ffi::XCBConnection,
|
||||
};
|
||||
|
||||
use std::{
|
||||
|
@ -40,14 +41,13 @@ struct Callbacks {
|
|||
appearance_changed: Option<Box<dyn FnMut()>>,
|
||||
}
|
||||
|
||||
xcb::atoms_struct! {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct XcbAtoms {
|
||||
pub wm_protocols => b"WM_PROTOCOLS",
|
||||
pub wm_del_window => b"WM_DELETE_WINDOW",
|
||||
wm_state => b"_NET_WM_STATE",
|
||||
wm_state_maxv => b"_NET_WM_STATE_MAXIMIZED_VERT",
|
||||
wm_state_maxh => b"_NET_WM_STATE_MAXIMIZED_HORZ",
|
||||
x11rb::atom_manager! {
|
||||
pub XcbAtoms: AtomsCookie {
|
||||
WM_PROTOCOLS,
|
||||
WM_DELETE_WINDOW,
|
||||
_NET_WM_STATE,
|
||||
_NET_WM_STATE_MAXIMIZED_VERT,
|
||||
_NET_WM_STATE_MAXIMIZED_HORZ,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,30 +68,31 @@ impl LinuxWindowInner {
|
|||
}
|
||||
}
|
||||
|
||||
fn query_render_extent(xcb_connection: &xcb::Connection, x_window: x::Window) -> gpu::Extent {
|
||||
let cookie = xcb_connection.send_request(&x::GetGeometry {
|
||||
drawable: x::Drawable::Window(x_window),
|
||||
});
|
||||
let reply = xcb_connection.wait_for_reply(cookie).unwrap();
|
||||
fn query_render_extent(xcb_connection: &XCBConnection, x_window: xproto::Window) -> gpu::Extent {
|
||||
let reply = xcb_connection
|
||||
.get_geometry(x_window)
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap();
|
||||
gpu::Extent {
|
||||
width: reply.width() as u32,
|
||||
height: reply.height() as u32,
|
||||
width: reply.width as u32,
|
||||
height: reply.height as u32,
|
||||
depth: 1,
|
||||
}
|
||||
}
|
||||
|
||||
struct RawWindow {
|
||||
connection: *mut c_void,
|
||||
screen_id: i32,
|
||||
screen_id: usize,
|
||||
window_id: u32,
|
||||
visual_id: u32,
|
||||
}
|
||||
|
||||
pub(crate) struct X11WindowState {
|
||||
xcb_connection: Rc<xcb::Connection>,
|
||||
xcb_connection: Rc<XCBConnection>,
|
||||
display: Rc<dyn PlatformDisplay>,
|
||||
raw: RawWindow,
|
||||
x_window: x::Window,
|
||||
x_window: xproto::Window,
|
||||
callbacks: RefCell<Callbacks>,
|
||||
inner: RefCell<LinuxWindowInner>,
|
||||
}
|
||||
|
@ -112,7 +113,7 @@ unsafe impl blade_rwh::HasRawDisplayHandle for RawWindow {
|
|||
fn raw_display_handle(&self) -> blade_rwh::RawDisplayHandle {
|
||||
let mut dh = blade_rwh::XcbDisplayHandle::empty();
|
||||
dh.connection = self.connection;
|
||||
dh.screen = self.screen_id;
|
||||
dh.screen = self.screen_id as i32;
|
||||
dh.into()
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +131,7 @@ impl rwh::HasDisplayHandle for X11Window {
|
|||
fn display_handle(&self) -> Result<rwh::DisplayHandle, rwh::HandleError> {
|
||||
Ok(unsafe {
|
||||
let non_zero = NonNull::new(self.0.raw.connection).unwrap();
|
||||
let handle = rwh::XcbDisplayHandle::new(Some(non_zero), self.0.raw.screen_id);
|
||||
let handle = rwh::XcbDisplayHandle::new(Some(non_zero), self.0.raw.screen_id as i32);
|
||||
rwh::DisplayHandle::borrow_raw(handle.into())
|
||||
})
|
||||
}
|
||||
|
@ -139,76 +140,76 @@ impl rwh::HasDisplayHandle for X11Window {
|
|||
impl X11WindowState {
|
||||
pub fn new(
|
||||
params: WindowParams,
|
||||
xcb_connection: &Rc<xcb::Connection>,
|
||||
x_main_screen_index: i32,
|
||||
x_window: x::Window,
|
||||
xcb_connection: &Rc<XCBConnection>,
|
||||
x_main_screen_index: usize,
|
||||
x_window: xproto::Window,
|
||||
atoms: &XcbAtoms,
|
||||
) -> Self {
|
||||
let x_screen_index = params
|
||||
.display_id
|
||||
.map_or(x_main_screen_index, |did| did.0 as i32);
|
||||
let screen = xcb_connection
|
||||
.get_setup()
|
||||
.roots()
|
||||
.nth(x_screen_index as usize)
|
||||
.map_or(x_main_screen_index, |did| did.0 as usize);
|
||||
let screen = xcb_connection.setup().roots.get(x_screen_index).unwrap();
|
||||
|
||||
let win_aux = xproto::CreateWindowAux::new().event_mask(
|
||||
xproto::EventMask::EXPOSURE
|
||||
| xproto::EventMask::STRUCTURE_NOTIFY
|
||||
| xproto::EventMask::ENTER_WINDOW
|
||||
| xproto::EventMask::LEAVE_WINDOW
|
||||
| xproto::EventMask::FOCUS_CHANGE
|
||||
| xproto::EventMask::KEY_PRESS
|
||||
| xproto::EventMask::KEY_RELEASE
|
||||
| xproto::EventMask::BUTTON_PRESS
|
||||
| xproto::EventMask::BUTTON_RELEASE
|
||||
| xproto::EventMask::POINTER_MOTION
|
||||
| xproto::EventMask::BUTTON1_MOTION
|
||||
| xproto::EventMask::BUTTON2_MOTION
|
||||
| xproto::EventMask::BUTTON3_MOTION
|
||||
| xproto::EventMask::BUTTON4_MOTION
|
||||
| xproto::EventMask::BUTTON5_MOTION
|
||||
| xproto::EventMask::BUTTON_MOTION,
|
||||
);
|
||||
|
||||
xcb_connection
|
||||
.create_window(
|
||||
x11rb::COPY_FROM_PARENT as _,
|
||||
x_window,
|
||||
screen.root,
|
||||
params.bounds.origin.x.0 as i16,
|
||||
params.bounds.origin.y.0 as i16,
|
||||
params.bounds.size.width.0 as u16,
|
||||
params.bounds.size.height.0 as u16,
|
||||
0,
|
||||
xproto::WindowClass::INPUT_OUTPUT,
|
||||
screen.root_visual,
|
||||
&win_aux,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let xcb_values = [
|
||||
x::Cw::BackPixel(screen.white_pixel()),
|
||||
x::Cw::EventMask(
|
||||
x::EventMask::EXPOSURE
|
||||
| x::EventMask::STRUCTURE_NOTIFY
|
||||
| x::EventMask::ENTER_WINDOW
|
||||
| x::EventMask::LEAVE_WINDOW
|
||||
| x::EventMask::FOCUS_CHANGE
|
||||
| x::EventMask::KEY_PRESS
|
||||
| x::EventMask::KEY_RELEASE
|
||||
| x::EventMask::BUTTON_PRESS
|
||||
| x::EventMask::BUTTON_RELEASE
|
||||
| x::EventMask::POINTER_MOTION
|
||||
| x::EventMask::BUTTON1_MOTION
|
||||
| x::EventMask::BUTTON2_MOTION
|
||||
| x::EventMask::BUTTON3_MOTION
|
||||
| x::EventMask::BUTTON4_MOTION
|
||||
| x::EventMask::BUTTON5_MOTION
|
||||
| x::EventMask::BUTTON_MOTION,
|
||||
),
|
||||
];
|
||||
|
||||
xcb_connection.send_request(&x::CreateWindow {
|
||||
depth: x::COPY_FROM_PARENT as u8,
|
||||
wid: x_window,
|
||||
parent: screen.root(),
|
||||
x: params.bounds.origin.x.0 as i16,
|
||||
y: params.bounds.origin.y.0 as i16,
|
||||
width: params.bounds.size.width.0 as u16,
|
||||
height: params.bounds.size.height.0 as u16,
|
||||
border_width: 0,
|
||||
class: x::WindowClass::InputOutput,
|
||||
visual: screen.root_visual(),
|
||||
value_list: &xcb_values,
|
||||
});
|
||||
|
||||
if let Some(titlebar) = params.titlebar {
|
||||
if let Some(title) = titlebar.title {
|
||||
xcb_connection.send_request(&x::ChangeProperty {
|
||||
mode: x::PropMode::Replace,
|
||||
window: x_window,
|
||||
property: x::ATOM_WM_NAME,
|
||||
r#type: x::ATOM_STRING,
|
||||
data: title.as_bytes(),
|
||||
});
|
||||
xcb_connection
|
||||
.change_property8(
|
||||
xproto::PropMode::REPLACE,
|
||||
x_window,
|
||||
xproto::AtomEnum::WM_NAME,
|
||||
xproto::AtomEnum::STRING,
|
||||
title.as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
xcb_connection.send_request(&x::ChangeProperty {
|
||||
mode: x::PropMode::Replace,
|
||||
window: x_window,
|
||||
property: atoms.wm_protocols,
|
||||
r#type: x::ATOM_ATOM,
|
||||
data: &[atoms.wm_del_window],
|
||||
});
|
||||
|
||||
xcb_connection.send_request(&x::MapWindow { window: x_window });
|
||||
xcb_connection
|
||||
.change_property32(
|
||||
xproto::PropMode::REPLACE,
|
||||
x_window,
|
||||
atoms.WM_PROTOCOLS,
|
||||
xproto::AtomEnum::ATOM,
|
||||
&[atoms.WM_DELETE_WINDOW],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
xcb_connection.map_window(x_window).unwrap();
|
||||
xcb_connection.flush().unwrap();
|
||||
|
||||
let raw = RawWindow {
|
||||
|
@ -216,8 +217,8 @@ impl X11WindowState {
|
|||
xcb_connection,
|
||||
) as *mut _,
|
||||
screen_id: x_screen_index,
|
||||
window_id: x_window.resource_id(),
|
||||
visual_id: screen.root_visual(),
|
||||
window_id: x_window,
|
||||
visual_id: screen.root_visual,
|
||||
};
|
||||
let gpu = Arc::new(
|
||||
unsafe {
|
||||
|
@ -254,12 +255,8 @@ impl X11WindowState {
|
|||
|
||||
pub fn destroy(&self) {
|
||||
self.inner.borrow_mut().renderer.destroy();
|
||||
self.xcb_connection.send_request(&x::UnmapWindow {
|
||||
window: self.x_window,
|
||||
});
|
||||
self.xcb_connection.send_request(&x::DestroyWindow {
|
||||
window: self.x_window,
|
||||
});
|
||||
self.xcb_connection.unmap_window(self.x_window).unwrap();
|
||||
self.xcb_connection.destroy_window(self.x_window).unwrap();
|
||||
if let Some(fun) = self.callbacks.borrow_mut().close.take() {
|
||||
fun();
|
||||
}
|
||||
|
@ -359,14 +356,14 @@ impl PlatformWindow for X11Window {
|
|||
}
|
||||
|
||||
fn mouse_position(&self) -> Point<Pixels> {
|
||||
let cookie = self.0.xcb_connection.send_request(&x::QueryPointer {
|
||||
window: self.0.x_window,
|
||||
});
|
||||
let reply: x::QueryPointerReply = self.0.xcb_connection.wait_for_reply(cookie).unwrap();
|
||||
Point::new(
|
||||
(reply.root_x() as u32).into(),
|
||||
(reply.root_y() as u32).into(),
|
||||
)
|
||||
let reply = self
|
||||
.0
|
||||
.xcb_connection
|
||||
.query_pointer(self.0.x_window)
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap();
|
||||
Point::new((reply.root_x as u32).into(), (reply.root_y as u32).into())
|
||||
}
|
||||
|
||||
// todo(linux)
|
||||
|
@ -397,20 +394,24 @@ impl PlatformWindow for X11Window {
|
|||
}
|
||||
|
||||
fn activate(&self) {
|
||||
self.0.xcb_connection.send_request(&x::ConfigureWindow {
|
||||
window: self.0.x_window,
|
||||
value_list: &[x::ConfigWindow::StackMode(x::StackMode::Above)],
|
||||
});
|
||||
let win_aux = xproto::ConfigureWindowAux::new().stack_mode(xproto::StackMode::ABOVE);
|
||||
self.0
|
||||
.xcb_connection
|
||||
.configure_window(self.0.x_window, &win_aux)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn set_title(&mut self, title: &str) {
|
||||
self.0.xcb_connection.send_request(&x::ChangeProperty {
|
||||
mode: x::PropMode::Replace,
|
||||
window: self.0.x_window,
|
||||
property: x::ATOM_WM_NAME,
|
||||
r#type: x::ATOM_STRING,
|
||||
data: title.as_bytes(),
|
||||
});
|
||||
self.0
|
||||
.xcb_connection
|
||||
.change_property8(
|
||||
xproto::PropMode::REPLACE,
|
||||
self.0.x_window,
|
||||
xproto::AtomEnum::WM_NAME,
|
||||
xproto::AtomEnum::STRING,
|
||||
title.as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// todo(linux)
|
||||
|
@ -443,7 +444,7 @@ impl PlatformWindow for X11Window {
|
|||
|
||||
// todo(linux)
|
||||
fn is_full_screen(&self) -> bool {
|
||||
unimplemented!()
|
||||
false
|
||||
}
|
||||
|
||||
fn on_request_frame(&self, callback: Box<dyn FnMut()>) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue