diff --git a/Cargo.lock b/Cargo.lock index 20d35c96e8..1dc42a42dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4409,7 +4409,7 @@ dependencies = [ "wayland-cursor", "wayland-protocols", "windows 0.53.0", - "xcb", + "x11rb", "xkbcommon", ] @@ -12516,7 +12516,9 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" dependencies = [ + "as-raw-xcb-connection", "gethostname", + "libc", "rustix 0.38.30", "x11rb-protocol", ] @@ -12536,18 +12538,6 @@ dependencies = [ "libc", ] -[[package]] -name = "xcb" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d27b37e69b8c05bfadcd968eb1a4fe27c9c52565b727f88512f43b89567e262" -dependencies = [ - "as-raw-xcb-connection", - "bitflags 1.3.2", - "libc", - "quick-xml 0.30.0", -] - [[package]] name = "xcursor" version = "0.3.5" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 440a6788bc..02cb514d9e 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -108,7 +108,7 @@ copypasta = "0.10.1" [target.'cfg(target_os = "linux")'.dependencies] open = "5.0.1" ashpd = "0.7.0" -xcb = { version = "1.3", features = ["as-raw-xcb-connection", "randr", "xkb"] } +x11rb = { version = "0.13.0", features = ["allow-unsafe-code", "xkb", "randr"] } wayland-client = { version = "0.31.2" } wayland-cursor = "0.31.1" wayland-protocols = { version = "0.31.2", features = [ diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index 89b35d8ed2..8a20c77490 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -2,18 +2,25 @@ use std::cell::RefCell; use std::rc::Rc; use std::time::Duration; -use xcb::{x, Xid as _}; -use xkbcommon::xkb; - use collections::HashMap; use copypasta::x11_clipboard::{Clipboard, Primary, X11ClipboardContext}; use copypasta::ClipboardProvider; +use x11rb::connection::{Connection, RequestConnection}; +use x11rb::errors::ConnectionError; +use x11rb::protocol::randr::ConnectionExt as _; +use x11rb::protocol::xkb::ConnectionExt as _; +use x11rb::protocol::xproto::ConnectionExt as _; +use x11rb::protocol::{randr, xkb, xproto, Event}; +use x11rb::xcb_ffi::XCBConnection; +use xkbc::x11::ffi::{XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION}; +use xkbcommon::xkb as xkbc; + use crate::platform::linux::client::Client; use crate::platform::{LinuxPlatformInner, PlatformWindow}; use crate::{ AnyWindowHandle, Bounds, CursorStyle, DisplayId, PlatformDisplay, PlatformInput, Point, - ScrollDelta, Size, TouchPhase, + ScrollDelta, Size, TouchPhase, WindowParams, }; use super::{X11Display, X11Window, X11WindowState, XcbAtoms}; @@ -28,55 +35,56 @@ struct WindowRef { } struct X11ClientState { - windows: HashMap, - xkb: xkbcommon::xkb::State, + windows: HashMap, + xkb: xkbc::State, clipboard: Rc>>, primary: Rc>>, } pub(crate) struct X11Client { platform_inner: Rc, - xcb_connection: Rc, - x_root_index: i32, + xcb_connection: Rc, + x_root_index: usize, atoms: XcbAtoms, state: RefCell, } impl X11Client { pub(crate) fn new(inner: Rc) -> Rc { - let (xcb_connection, x_root_index) = xcb::Connection::connect_with_extensions( - None, - &[xcb::Extension::RandR, xcb::Extension::Xkb], - &[], - ) - .unwrap(); - - let xkb_ver = xcb_connection - .wait_for_reply(xcb_connection.send_request(&xcb::xkb::UseExtension { - wanted_major: xcb::xkb::MAJOR_VERSION as u16, - wanted_minor: xcb::xkb::MINOR_VERSION as u16, - })) + let (xcb_connection, x_root_index) = XCBConnection::connect(None).unwrap(); + xcb_connection + .prefetch_extension_information(xkb::X11_EXTENSION_NAME) + .unwrap(); + xcb_connection + .prefetch_extension_information(randr::X11_EXTENSION_NAME) .unwrap(); - assert!(xkb_ver.supported()); - let atoms = XcbAtoms::intern_all(&xcb_connection).unwrap(); - let xcb_connection = Rc::new(xcb_connection); + let atoms = XcbAtoms::new(&xcb_connection).unwrap(); + let xkb = xcb_connection + .xkb_use_extension(XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION) + .unwrap(); + + let atoms = atoms.reply().unwrap(); + let xkb = xkb.reply().unwrap(); + assert!(xkb.supported); let xkb_state = { - let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); - let xkb_device_id = xkb::x11::get_core_keyboard_device_id(&xcb_connection); - let xkb_keymap = xkb::x11::keymap_new_from_device( + let xkb_context = xkbc::Context::new(xkbc::CONTEXT_NO_FLAGS); + let xkb_device_id = xkbc::x11::get_core_keyboard_device_id(&xcb_connection); + let xkb_keymap = xkbc::x11::keymap_new_from_device( &xkb_context, &xcb_connection, xkb_device_id, - xkb::KEYMAP_COMPILE_NO_FLAGS, + xkbc::KEYMAP_COMPILE_NO_FLAGS, ); - xkb::x11::state_new_from_device(&xkb_keymap, &xcb_connection, xkb_device_id) + xkbc::x11::state_new_from_device(&xkb_keymap, &xcb_connection, xkb_device_id) }; let clipboard = X11ClipboardContext::::new().unwrap(); let primary = X11ClipboardContext::::new().unwrap(); + let xcb_connection = Rc::new(xcb_connection); + let client: Rc = Rc::new(Self { platform_inner: inner.clone(), xcb_connection: Rc::clone(&xcb_connection), @@ -96,7 +104,7 @@ impl X11Client { inner .loop_handle .insert_source( - Generic::new_with_error::( + Generic::new_with_error::( fd, calloop::Interest::READ, calloop::Mode::Level, @@ -116,69 +124,68 @@ impl X11Client { client } - fn get_window(&self, win: x::Window) -> Option> { + fn get_window(&self, win: xproto::Window) -> Option> { let state = self.state.borrow(); state.windows.get(&win).map(|wr| Rc::clone(&wr.state)) } - fn handle_event(&self, event: xcb::Event) -> Option<()> { + fn handle_event(&self, event: Event) -> Option<()> { match event { - xcb::Event::X(x::Event::ClientMessage(event)) => { - if let x::ClientMessageData::Data32([atom, ..]) = event.data() { - if atom == self.atoms.wm_del_window.resource_id() { - // window "x" button clicked by user, we gracefully exit - let window_ref = self - .state - .borrow_mut() - .windows - .remove(&event.window()) - .unwrap(); + Event::ClientMessage(event) => { + let [atom, ..] = event.data.as_data32(); + if atom == self.atoms.WM_DELETE_WINDOW { + // window "x" button clicked by user, we gracefully exit + let window_ref = self + .state + .borrow_mut() + .windows + .remove(&event.window) + .unwrap(); - self.platform_inner - .loop_handle - .remove(window_ref.refresh_event_token); - window_ref.state.destroy(); + self.platform_inner + .loop_handle + .remove(window_ref.refresh_event_token); + window_ref.state.destroy(); - if self.state.borrow().windows.is_empty() { - self.platform_inner.loop_signal.stop(); - } + if self.state.borrow().windows.is_empty() { + self.platform_inner.loop_signal.stop(); } } } - xcb::Event::X(x::Event::ConfigureNotify(event)) => { + Event::ConfigureNotify(event) => { let bounds = Bounds { origin: Point { - x: event.x().into(), - y: event.y().into(), + x: event.x.into(), + y: event.y.into(), }, size: Size { - width: event.width().into(), - height: event.height().into(), + width: event.width.into(), + height: event.height.into(), }, }; - let window = self.get_window(event.window())?; + let window = self.get_window(event.window)?; window.configure(bounds); } - xcb::Event::X(x::Event::Expose(event)) => { - let window = self.get_window(event.window())?; + Event::Expose(event) => { + let window = self.get_window(event.window)?; window.refresh(); } - xcb::Event::X(x::Event::FocusIn(event)) => { - let window = self.get_window(event.event())?; + Event::FocusIn(event) => { + let window = self.get_window(event.event)?; window.set_focused(true); } - xcb::Event::X(x::Event::FocusOut(event)) => { - let window = self.get_window(event.event())?; + Event::FocusOut(event) => { + let window = self.get_window(event.event)?; window.set_focused(false); } - xcb::Event::X(x::Event::KeyPress(event)) => { - let window = self.get_window(event.event())?; - let modifiers = super::modifiers_from_state(event.state()); + Event::KeyPress(event) => { + let window = self.get_window(event.event)?; + let modifiers = super::modifiers_from_state(event.state); let keystroke = { - let code = event.detail().into(); + let code = event.detail.into(); let mut state = self.state.borrow_mut(); let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code); - state.xkb.update_key(code, xkb::KeyDirection::Down); + state.xkb.update_key(code, xkbc::KeyDirection::Down); keystroke }; @@ -187,36 +194,34 @@ impl X11Client { is_held: false, })); } - xcb::Event::X(x::Event::KeyRelease(event)) => { - let window = self.get_window(event.event())?; - let modifiers = super::modifiers_from_state(event.state()); + Event::KeyRelease(event) => { + let window = self.get_window(event.event)?; + let modifiers = super::modifiers_from_state(event.state); let keystroke = { - let code = event.detail().into(); + let code = event.detail.into(); let mut state = self.state.borrow_mut(); let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code); - state.xkb.update_key(code, xkb::KeyDirection::Up); + state.xkb.update_key(code, xkbc::KeyDirection::Up); keystroke }; window.handle_input(PlatformInput::KeyUp(crate::KeyUpEvent { keystroke })); } - xcb::Event::X(x::Event::ButtonPress(event)) => { - let window = self.get_window(event.event())?; - let modifiers = super::modifiers_from_state(event.state()); - let position = Point::new( - (event.event_x() as f32).into(), - (event.event_y() as f32).into(), - ); - if let Some(button) = super::button_of_key(event.detail()) { + Event::ButtonPress(event) => { + let window = self.get_window(event.event)?; + let modifiers = super::modifiers_from_state(event.state); + let position = + Point::new((event.event_x as f32).into(), (event.event_y as f32).into()); + if let Some(button) = super::button_of_key(event.detail) { window.handle_input(PlatformInput::MouseDown(crate::MouseDownEvent { button, position, modifiers, click_count: 1, })); - } else if event.detail() >= 4 && event.detail() <= 5 { + } else if event.detail >= 4 && event.detail <= 5 { // https://stackoverflow.com/questions/15510472/scrollwheel-event-in-x11 - let delta_x = if event.detail() == 4 { 1.0 } else { -1.0 }; + let delta_x = if event.detail == 4 { 1.0 } else { -1.0 }; window.handle_input(PlatformInput::ScrollWheel(crate::ScrollWheelEvent { position, delta: ScrollDelta::Lines(Point::new(0.0, delta_x)), @@ -227,14 +232,12 @@ impl X11Client { log::warn!("Unknown button press: {event:?}"); } } - xcb::Event::X(x::Event::ButtonRelease(event)) => { - let window = self.get_window(event.event())?; - let modifiers = super::modifiers_from_state(event.state()); - let position = Point::new( - (event.event_x() as f32).into(), - (event.event_y() as f32).into(), - ); - if let Some(button) = super::button_of_key(event.detail()) { + Event::ButtonRelease(event) => { + let window = self.get_window(event.event)?; + let modifiers = super::modifiers_from_state(event.state); + let position = + Point::new((event.event_x as f32).into(), (event.event_y as f32).into()); + if let Some(button) = super::button_of_key(event.detail) { window.handle_input(PlatformInput::MouseUp(crate::MouseUpEvent { button, position, @@ -243,28 +246,24 @@ impl X11Client { })); } } - xcb::Event::X(x::Event::MotionNotify(event)) => { - let window = self.get_window(event.event())?; - let pressed_button = super::button_from_state(event.state()); - let position = Point::new( - (event.event_x() as f32).into(), - (event.event_y() as f32).into(), - ); - let modifiers = super::modifiers_from_state(event.state()); + Event::MotionNotify(event) => { + let window = self.get_window(event.event)?; + let pressed_button = super::button_from_state(event.state); + let position = + Point::new((event.event_x as f32).into(), (event.event_y as f32).into()); + let modifiers = super::modifiers_from_state(event.state); window.handle_input(PlatformInput::MouseMove(crate::MouseMoveEvent { pressed_button, position, modifiers, })); } - xcb::Event::X(x::Event::LeaveNotify(event)) => { - let window = self.get_window(event.event())?; - let pressed_button = super::button_from_state(event.state()); - let position = Point::new( - (event.event_x() as f32).into(), - (event.event_y() as f32).into(), - ); - let modifiers = super::modifiers_from_state(event.state()); + Event::LeaveNotify(event) => { + let window = self.get_window(event.event)?; + let pressed_button = super::button_from_state(event.state); + let position = + Point::new((event.event_x as f32).into(), (event.event_y as f32).into()); + let modifiers = super::modifiers_from_state(event.state); window.handle_input(PlatformInput::MouseExited(crate::MouseExitEvent { pressed_button, position, @@ -280,21 +279,23 @@ impl X11Client { impl Client for X11Client { fn displays(&self) -> Vec> { - let setup = self.xcb_connection.get_setup(); + let setup = self.xcb_connection.setup(); setup - .roots() + .roots + .iter() .enumerate() .filter_map(|(root_id, _)| { - Some( - Rc::new(X11Display::new(&self.xcb_connection, root_id as i32)?) - as Rc, - ) + Some(Rc::new(X11Display::new(&self.xcb_connection, root_id)?) + as Rc) }) .collect() } fn display(&self, id: DisplayId) -> Option> { - Some(Rc::new(X11Display::new(&self.xcb_connection, id.0 as i32)?)) + Some(Rc::new(X11Display::new( + &self.xcb_connection, + id.0 as usize, + )?)) } fn primary_display(&self) -> Option> { @@ -307,36 +308,44 @@ impl Client for X11Client { fn open_window( &self, _handle: AnyWindowHandle, - params: crate::WindowParams, + options: WindowParams, ) -> Box { - let x_window = self.xcb_connection.generate_id(); + let x_window = self.xcb_connection.generate_id().unwrap(); let window_ptr = Rc::new(X11WindowState::new( - params, + options, &self.xcb_connection, self.x_root_index, x_window, &self.atoms, )); - let cookie = self + let screen_resources = self .xcb_connection - .send_request(&xcb::randr::GetScreenResourcesCurrent { window: x_window }); - let screen_resources = self.xcb_connection.wait_for_reply(cookie).expect("TODO"); + .randr_get_screen_resources(x_window) + .unwrap() + .reply() + .expect("TODO"); + let mode = screen_resources - .crtcs() + .crtcs .iter() .find_map(|crtc| { - let cookie = self.xcb_connection.send_request(&xcb::randr::GetCrtcInfo { - crtc: crtc.to_owned(), - config_timestamp: xcb::x::Time::CurrentTime as u32, - }); - let crtc_info = self.xcb_connection.wait_for_reply(cookie).expect("TODO"); + let crtc_info = self + .xcb_connection + .randr_get_crtc_info(*crtc, x11rb::CURRENT_TIME) + .ok()? + .reply() + .ok()?; - let mode_id = crtc_info.mode().resource_id(); - screen_resources.modes().iter().find(|m| m.id == mode_id) + screen_resources + .modes + .iter() + .find(|m| m.id == crtc_info.mode) }) - .expect("Missing screen mode for crtc specified mode id"); + .expect("Unable to find screen refresh rate"); + + // .expect("Missing screen mode for crtc specified mode id"); let refresh_event_token = self .platform_inner @@ -345,13 +354,24 @@ impl Client for X11Client { let refresh_duration = mode_refresh_rate(mode); let xcb_connection = Rc::clone(&self.xcb_connection); move |mut instant, (), _| { - xcb_connection.send_request(&x::SendEvent { - propagate: false, - destination: x::SendEventDest::Window(x_window), - event_mask: x::EventMask::EXPOSURE, - event: &x::ExposeEvent::new(x_window, 0, 0, 0, 0, 1), - }); - let _ = xcb_connection.flush(); + xcb_connection + .send_event( + false, + x_window, + xproto::EventMask::EXPOSURE, + xproto::ExposeEvent { + response_type: xproto::EXPOSE_EVENT, + sequence: 0, + window: x_window, + x: 0, + y: 0, + width: 0, + height: 0, + count: 1, + }, + ) + .unwrap(); + let _ = xcb_connection.flush().unwrap(); // Take into account that some frames have been skipped let now = time::Instant::now(); while instant < now { @@ -384,7 +404,7 @@ impl Client for X11Client { // Adatpted from: // https://docs.rs/winit/0.29.11/src/winit/platform_impl/linux/x11/monitor.rs.html#103-111 -pub fn mode_refresh_rate(mode: &xcb::randr::ModeInfo) -> Duration { +pub fn mode_refresh_rate(mode: &randr::ModeInfo) -> Duration { let millihertz = mode.dot_clock as u64 * 1_000 / (mode.htotal as u64 * mode.vtotal as u64); let micros = 1_000_000_000 / millihertz; log::info!("Refreshing at {} micros", micros); diff --git a/crates/gpui/src/platform/linux/x11/display.rs b/crates/gpui/src/platform/linux/x11/display.rs index 7ec29b71f4..b96fdb319b 100644 --- a/crates/gpui/src/platform/linux/x11/display.rs +++ b/crates/gpui/src/platform/linux/x11/display.rs @@ -1,25 +1,26 @@ use anyhow::Result; use uuid::Uuid; +use x11rb::{connection::Connection as _, xcb_ffi::XCBConnection}; use crate::{Bounds, DisplayId, GlobalPixels, PlatformDisplay, Size}; #[derive(Debug)] pub(crate) struct X11Display { - x_screen_index: i32, + x_screen_index: usize, bounds: Bounds, uuid: Uuid, } impl X11Display { - pub(crate) fn new(xc: &xcb::Connection, x_screen_index: i32) -> Option { - let screen = xc.get_setup().roots().nth(x_screen_index as usize)?; + pub(crate) fn new(xc: &XCBConnection, x_screen_index: usize) -> Option { + let screen = xc.setup().roots.get(x_screen_index).unwrap(); Some(Self { - x_screen_index, + x_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]), diff --git a/crates/gpui/src/platform/linux/x11/event.rs b/crates/gpui/src/platform/linux/x11/event.rs index b346c55ab8..a63e1c68cb 100644 --- a/crates/gpui/src/platform/linux/x11/event.rs +++ b/crates/gpui/src/platform/linux/x11/event.rs @@ -1,8 +1,8 @@ -use xcb::x; +use x11rb::protocol::xproto; use crate::{Modifiers, MouseButton, NavigationDirection}; -pub(crate) fn button_of_key(detail: x::Button) -> Option { +pub(crate) fn button_of_key(detail: xproto::Button) -> Option { Some(match detail { 1 => MouseButton::Left, 2 => MouseButton::Middle, @@ -13,22 +13,22 @@ pub(crate) fn button_of_key(detail: x::Button) -> Option { }) } -pub(crate) fn modifiers_from_state(state: x::KeyButMask) -> Modifiers { +pub(crate) fn modifiers_from_state(state: xproto::KeyButMask) -> Modifiers { Modifiers { - control: state.contains(x::KeyButMask::CONTROL), - alt: state.contains(x::KeyButMask::MOD1), - shift: state.contains(x::KeyButMask::SHIFT), - command: state.contains(x::KeyButMask::MOD4), + control: state.contains(xproto::KeyButMask::CONTROL), + alt: state.contains(xproto::KeyButMask::MOD1), + shift: state.contains(xproto::KeyButMask::SHIFT), + command: state.contains(xproto::KeyButMask::MOD4), function: false, } } -pub(crate) fn button_from_state(state: x::KeyButMask) -> Option { - Some(if state.contains(x::KeyButMask::BUTTON1) { +pub(crate) fn button_from_state(state: xproto::KeyButMask) -> Option { + Some(if state.contains(xproto::KeyButMask::BUTTON1) { MouseButton::Left - } else if state.contains(x::KeyButMask::BUTTON2) { + } else if state.contains(xproto::KeyButMask::BUTTON2) { MouseButton::Middle - } else if state.contains(x::KeyButMask::BUTTON3) { + } else if state.contains(xproto::KeyButMask::BUTTON3) { MouseButton::Right } else { return None; diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index 6b9e958b20..1a59d85bb5 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -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>, } -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: Rc, display: Rc, raw: RawWindow, - x_window: x::Window, + x_window: xproto::Window, callbacks: RefCell, inner: RefCell, } @@ -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 { 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, - x_main_screen_index: i32, - x_window: x::Window, + xcb_connection: &Rc, + 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 { - 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) {