@@ -1,25 +1,24 @@
-use crate::{point, size, Bounds, DisplayId, GlobalPixels, PlatformDisplay, Size};
+use crate::{Bounds, DisplayId, GlobalPixels, PlatformDisplay, Size};
use anyhow::Result;
use uuid::Uuid;
-use x11rb::{connection::Connection as _, rust_connection::RustConnection};
#[derive(Debug)]
pub(crate) struct LinuxDisplay {
- x11_screen_index: usize,
+ x_screen_index: i32,
bounds: Bounds<GlobalPixels>,
uuid: Uuid,
}
impl LinuxDisplay {
- pub(crate) fn new(xc: &RustConnection, x11_screen_index: usize) -> Self {
- let screen = &xc.setup().roots[x11_screen_index];
+ pub(crate) fn new(xc: &xcb::Connection, x_screen_index: i32) -> Self {
+ let screen = xc.get_setup().roots().nth(x_screen_index as usize).unwrap();
Self {
- x11_screen_index,
+ x_screen_index,
bounds: Bounds {
origin: Default::default(),
size: Size {
- width: GlobalPixels(screen.width_in_pixels as f32),
- height: GlobalPixels(screen.height_in_pixels as f32),
+ width: GlobalPixels(screen.width_in_pixels() as f32),
+ height: GlobalPixels(screen.height_in_pixels() as f32),
},
},
uuid: Uuid::from_bytes([0; 16]),
@@ -29,7 +28,7 @@ impl LinuxDisplay {
impl PlatformDisplay for LinuxDisplay {
fn id(&self) -> DisplayId {
- DisplayId(self.x11_screen_index as u32)
+ DisplayId(self.x_screen_index as u32)
}
fn uuid(&self) -> Result<Uuid> {
@@ -19,48 +19,28 @@ use std::{
time::Duration,
};
use time::UtcOffset;
-use x11rb::{
- connection::Connection as _,
- protocol::{
- xproto::{Atom, ConnectionExt as _},
- Event,
- },
- rust_connection::RustConnection,
-};
-
-pub(crate) struct LinuxPlatform(Mutex<LinuxPlatformState>);
-
-pub(crate) struct WmAtoms {
- pub protocols: Atom,
- pub delete_window: Atom,
-}
-
-impl WmAtoms {
- fn new(x11_connection: &RustConnection) -> Self {
- Self {
- protocols: x11_connection
- .intern_atom(false, b"WM_PROTOCOLS")
- .unwrap()
- .reply()
- .unwrap()
- .atom,
- delete_window: x11_connection
- .intern_atom(false, b"WM_DELETE_WINDOW")
- .unwrap()
- .reply()
- .unwrap()
- .atom,
- }
+use xcb::{x, Xid as _};
+
+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",
}
}
+pub(crate) struct LinuxPlatform(Mutex<LinuxPlatformState>);
+
pub(crate) struct LinuxPlatformState {
- x11_connection: RustConnection,
- x11_root_index: usize,
- atoms: WmAtoms,
+ xcb_connection: xcb::Connection,
+ x_root_index: i32,
+ atoms: XcbAtoms,
background_executor: BackgroundExecutor,
foreground_executor: ForegroundExecutor,
- windows: HashMap<u32, LinuxWindowStatePtr>,
+ windows: HashMap<x::Window, LinuxWindowStatePtr>,
text_system: Arc<LinuxTextSystem>,
}
@@ -72,14 +52,14 @@ impl Default for LinuxPlatform {
impl LinuxPlatform {
pub(crate) fn new() -> Self {
- let (x11_connection, x11_root_index) = x11rb::connect(None).unwrap();
- let atoms = WmAtoms::new(&x11_connection);
+ let (xcb_connection, x_root_index) = xcb::Connection::connect(None).unwrap();
+ let atoms = XcbAtoms::intern_all(&xcb_connection).unwrap();
let dispatcher = Arc::new(LinuxDispatcher::new());
Self(Mutex::new(LinuxPlatformState {
- x11_connection,
- x11_root_index,
+ xcb_connection,
+ x_root_index,
atoms,
background_executor: BackgroundExecutor::new(dispatcher.clone()),
foreground_executor: ForegroundExecutor::new(dispatcher),
@@ -105,54 +85,44 @@ impl Platform for LinuxPlatform {
fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
on_finish_launching();
- let mut need_repaint = HashSet::<u32>::default();
+ let mut need_repaint = HashSet::<x::Window>::default();
while !self.0.lock().windows.is_empty() {
- let event = self.0.lock().x11_connection.wait_for_event().unwrap();
- let mut event_option = Some(event);
- while let Some(event) = event_option {
- match event {
- Event::Expose(event) => {
- if event.count == 0 {
- need_repaint.insert(event.window);
- }
- }
- Event::ConfigureNotify(event) => {
- let lock = self.0.lock();
- let mut window = lock.windows[&event.window].lock();
- window.resize(event.width, event.height);
- }
- Event::MotionNotify(_event) => {
- //mouse_position = (event.event_x, event.event_y);
- //need_repaint.insert(event.window);
- }
- Event::MapNotify(_) => {}
- Event::ClientMessage(event) => {
+ let event = self.0.lock().xcb_connection.wait_for_event().unwrap();
+ match event {
+ xcb::Event::X(x::Event::ClientMessage(ev)) => {
+ if let x::ClientMessageData::Data32([atom, ..]) = ev.data() {
let mut lock = self.0.lock();
- let data = event.data.as_data32();
- if data[0] == lock.atoms.delete_window {
+ if atom == lock.atoms.wm_del_window.resource_id() {
+ // window "x" button clicked by user, we gracefully exit
{
- let mut window = lock.windows[&event.window].lock();
+ let mut window = lock.windows[&ev.window()].lock();
window.destroy();
}
- lock.windows.remove(&event.window);
+ lock.windows.remove(&ev.window());
+ break;
}
}
- Event::Error(error) => {
- log::error!("X11 error {:?}", error);
- }
- _ => {}
}
-
- let lock = self.0.lock();
- event_option = lock.x11_connection.poll_for_event().unwrap();
+ _ => {} /*
+ Event::Expose(event) => {
+ if event.count == 0 {
+ need_repaint.insert(event.window);
+ }
+ }
+ Event::ConfigureNotify(event) => {
+ let lock = self.0.lock();
+ let mut window = lock.windows[&event.window].lock();
+ window.resize(event.width, event.height);
+ }
+ _ => {}*/
}
- for x11_window in need_repaint.drain() {
+ for x_window in need_repaint.drain() {
let lock = self.0.lock();
- let mut window = lock.windows[&x11_window].lock();
+ let mut window = lock.windows[&x_window].lock();
window.paint();
- lock.x11_connection.flush().unwrap();
+ lock.xcb_connection.flush();
}
}
}
@@ -171,10 +141,13 @@ impl Platform for LinuxPlatform {
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
let lock = self.0.lock();
- let setup = lock.x11_connection.setup();
- (0..setup.roots.len())
- .map(|id| {
- Rc::new(LinuxDisplay::new(&lock.x11_connection, id)) as Rc<dyn PlatformDisplay>
+ let setup = lock.xcb_connection.get_setup();
+ setup
+ .roots()
+ .enumerate()
+ .map(|(root_id, _)| {
+ Rc::new(LinuxDisplay::new(&lock.xcb_connection, root_id as i32))
+ as Rc<dyn PlatformDisplay>
})
.collect()
}
@@ -182,8 +155,8 @@ impl Platform for LinuxPlatform {
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
let lock = self.0.lock();
Some(Rc::new(LinuxDisplay::new(
- &lock.x11_connection,
- id.0 as usize,
+ &lock.xcb_connection,
+ id.0 as i32,
)))
}
@@ -197,17 +170,17 @@ impl Platform for LinuxPlatform {
options: WindowOptions,
) -> Box<dyn PlatformWindow> {
let mut lock = self.0.lock();
- let win_id = lock.x11_connection.generate_id().unwrap();
+ let x_window = lock.xcb_connection.generate_id();
let window_ptr = LinuxWindowState::new_ptr(
options,
handle,
- &lock.x11_connection,
- lock.x11_root_index,
- win_id,
+ &lock.xcb_connection,
+ lock.x_root_index,
+ x_window,
&lock.atoms,
);
- lock.windows.insert(win_id, window_ptr.clone());
+ lock.windows.insert(x_window, window_ptr.clone());
Box::new(LinuxWindow(window_ptr))
}
@@ -1,28 +1,19 @@
use super::BladeRenderer;
use crate::{
- px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, BladeAtlas, Bounds, KeyDownEvent,
- Keystroke, LinuxDisplay, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
- PlatformInputHandler, PlatformWindow, Point, Size, TileId, WindowAppearance, WindowBounds,
- WindowOptions, WmAtoms,
+ AnyWindowHandle, BladeAtlas, LinuxDisplay, Pixels, PlatformDisplay, PlatformInputHandler,
+ PlatformWindow, Point, Size, WindowAppearance, WindowBounds, WindowOptions, XcbAtoms,
};
-use collections::HashMap;
use parking_lot::Mutex;
use std::{
- rc::{Rc, Weak},
+ ffi::c_void,
+ rc::Rc,
sync::{self, Arc},
};
-use x11rb::{
- connection::Connection as _,
- protocol::xproto::{
- AtomEnum, ConnectionExt as _, CreateWindowAux, EventMask, PropMode, WindowClass,
- },
- rust_connection::RustConnection,
- wrapper::ConnectionExt as _,
-};
+use xcb::{x, Xid as _};
pub(crate) struct LinuxWindowState {
display: Rc<dyn PlatformDisplay>,
- x11_window: u32,
+ x_window: x::Window,
window_bounds: WindowBounds,
content_size: Size<Pixels>,
sprite_atlas: Arc<BladeAtlas>,
@@ -33,29 +24,53 @@ pub(crate) type LinuxWindowStatePtr = Arc<Mutex<LinuxWindowState>>;
#[derive(Clone)]
pub(crate) struct LinuxWindow(pub(crate) LinuxWindowStatePtr);
+struct RawWindow {
+ connection: *mut c_void,
+ screen_id: i32,
+ window_id: u32,
+}
+unsafe impl raw_window_handle::HasRawWindowHandle for RawWindow {
+ fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
+ let mut wh = raw_window_handle::XcbWindowHandle::empty();
+ wh.window = self.window_id;
+ wh.into()
+ }
+}
+unsafe impl raw_window_handle::HasRawDisplayHandle for RawWindow {
+ fn raw_display_handle(&self) -> raw_window_handle::RawDisplayHandle {
+ let mut dh = raw_window_handle::XcbDisplayHandle::empty();
+ dh.connection = self.connection;
+ dh.screen = self.screen_id;
+ dh.into()
+ }
+}
+
impl LinuxWindowState {
pub fn new_ptr(
options: WindowOptions,
handle: AnyWindowHandle,
- x11_connection: &RustConnection,
- x11_main_screen_index: usize,
- x11_window: u32,
- atoms: &WmAtoms,
+ xcb_connection: &xcb::Connection,
+ x_main_screen_index: i32,
+ x_window: x::Window,
+ atoms: &XcbAtoms,
) -> LinuxWindowStatePtr {
- let x11_screen_index = options
+ let x_screen_index = options
.display_id
- .map_or(x11_main_screen_index, |did| did.0 as usize);
- let screen = &x11_connection.setup().roots[x11_screen_index];
+ .map_or(x_main_screen_index, |did| did.0 as i32);
+ let screen = xcb_connection
+ .get_setup()
+ .roots()
+ .nth(x_screen_index as usize)
+ .unwrap();
- let win_aux = CreateWindowAux::new()
- .event_mask(
- EventMask::EXPOSURE | EventMask::STRUCTURE_NOTIFY | EventMask::POINTER_MOTION,
- )
- .background_pixel(screen.white_pixel);
+ let xcb_values = [
+ x::Cw::BackPixel(screen.white_pixel()),
+ x::Cw::EventMask(x::EventMask::EXPOSURE | x::EventMask::KEY_PRESS),
+ ];
let (bound_x, bound_y, bound_width, bound_height) = match options.bounds {
WindowBounds::Fullscreen | WindowBounds::Maximized => {
- (0, 0, screen.width_in_pixels, screen.height_in_pixels)
+ (0, 0, screen.width_in_pixels(), screen.height_in_pixels())
}
WindowBounds::Fixed(bounds) => (
bounds.origin.x.0 as i16,
@@ -65,61 +80,67 @@ impl LinuxWindowState {
),
};
- x11_connection
- .create_window(
- x11rb::COPY_DEPTH_FROM_PARENT,
- x11_window,
- screen.root,
- bound_x,
- bound_y,
- bound_width,
- bound_height,
- 0,
- WindowClass::INPUT_OUTPUT,
- 0,
- &win_aux,
- )
- .unwrap();
+ xcb_connection.send_request(&x::CreateWindow {
+ depth: x::COPY_FROM_PARENT as u8,
+ wid: x_window,
+ parent: screen.root(),
+ x: bound_x,
+ y: bound_y,
+ width: bound_width,
+ height: bound_height,
+ border_width: 0,
+ class: x::WindowClass::InputOutput,
+ visual: screen.root_visual(),
+ value_list: &xcb_values,
+ });
if let Some(titlebar) = options.titlebar {
if let Some(title) = titlebar.title {
- x11_connection
- .change_property8(
- PropMode::REPLACE,
- x11_window,
- AtomEnum::WM_NAME,
- AtomEnum::STRING,
- title.as_bytes(),
- )
- .unwrap();
+ 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(),
+ });
}
}
- x11_connection
- .change_property32(
- PropMode::REPLACE,
- x11_window,
- atoms.protocols,
- AtomEnum::ATOM,
- &[atoms.delete_window],
- )
+ xcb_connection
+ .send_and_check_request(&x::ChangeProperty {
+ mode: x::PropMode::Replace,
+ window: x_window,
+ property: atoms.wm_protocols,
+ r#type: x::ATOM_ATOM,
+ data: &[atoms.wm_del_window],
+ })
.unwrap();
- x11_connection.map_window(x11_window).unwrap();
- x11_connection.flush().unwrap();
+ xcb_connection.send_request(&x::MapWindow { window: x_window });
+ xcb_connection.flush().unwrap();
+ let raw_window = RawWindow {
+ connection: as_raw_xcb_connection::AsRawXcbConnection::as_raw_xcb_connection(
+ xcb_connection,
+ ) as *mut _,
+ screen_id: x_screen_index,
+ window_id: x_window.resource_id(),
+ };
let gpu = Arc::new(
unsafe {
- blade::Context::init(blade::ContextDesc {
- validation: cfg!(debug_assertions),
- capture: false,
- })
+ blade::Context::init_windowed(
+ &raw_window,
+ blade::ContextDesc {
+ validation: cfg!(debug_assertions),
+ capture: false,
+ },
+ )
}
.unwrap(),
);
Arc::new(Mutex::new(Self {
- display: Rc::new(LinuxDisplay::new(x11_connection, x11_screen_index)),
- x11_window,
+ display: Rc::new(LinuxDisplay::new(xcb_connection, x_screen_index)),
+ x_window,
window_bounds: options.bounds,
content_size: Size {
width: Pixels(bound_width as f32),