Skip to content

Commit

Permalink
Linux/x11 input handling (#7811)
Browse files Browse the repository at this point in the history
Implements the basics of keyboard and mouse handling.
Some keys will need special treatment, like Backspace/Delete. In this
PR, all keys are treated as append-only. Leaving this for a follow-up.

I used @gabydd 's branch as a reference (thank you!) as well as
https://github.com/xkbcommon/libxkbcommon/blob/master/doc/quick-guide.md
For future work, I'll also use
https://github.com/xkbcommon/libxkbcommon/blob/master/tools/interactive-x11.c

All commits are separately compileable and reviewable.

Release Notes:
- N/A

---------

Co-authored-by: Mikayla Maki <[email protected]>
  • Loading branch information
kvark and mikayla-maki authored Feb 15, 2024
1 parent aa319cc commit a41fb29
Show file tree
Hide file tree
Showing 15 changed files with 253 additions and 53 deletions.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion crates/gpui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ objc = "0.2"

[target.'cfg(target_os = "linux")'.dependencies]
flume = "0.11"
xcb = { version = "1.3", features = ["as-raw-xcb-connection", "present", "randr"] }
# todo!(linux) - Technically do not use `randr`, but it doesn't compile otherwise
xcb = { version = "1.3", features = ["as-raw-xcb-connection", "present", "randr", "xkb"] }
wayland-client= { version = "0.31.2" }
wayland-protocols = { version = "0.31.2", features = ["client"] }
wayland-backend = { version = "0.3.3", features = ["client_system"] }
Expand All @@ -106,3 +107,4 @@ blade-graphics = { git = "https://github.com/kvark/blade", rev = "c4f951a88b3457
blade-macros = { git = "https://github.com/kvark/blade", rev = "c4f951a88b345724cb952e920ad30e39851f7760" }
bytemuck = "1"
cosmic-text = "0.10.0"
xkbcommon = { version = "0.7", features = ["x11"] }
3 changes: 0 additions & 3 deletions crates/gpui/src/platform/linux.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//todo!(linux): remove this
#![allow(unused_variables)]

mod blade_atlas;
mod blade_belt;
mod blade_renderer;
Expand Down
4 changes: 2 additions & 2 deletions crates/gpui/src/platform/linux/blade_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ impl BladeRenderer {
sprites,
} => {
let tex_info = self.atlas.get_texture_info(texture_id);
let instance_buf = self.instance_belt.alloc_data(&sprites, &self.gpu);
let instance_buf = self.instance_belt.alloc_data(sprites, &self.gpu);
let mut encoder = pass.with(&self.pipelines.mono_sprites);
encoder.bind(
0,
Expand All @@ -476,7 +476,7 @@ impl BladeRenderer {
sprites,
} => {
let tex_info = self.atlas.get_texture_info(texture_id);
let instance_buf = self.instance_belt.alloc_data(&sprites, &self.gpu);
let instance_buf = self.instance_belt.alloc_data(sprites, &self.gpu);
let mut encoder = pass.with(&self.pipelines.poly_sprites);
encoder.bind(
0,
Expand Down
36 changes: 24 additions & 12 deletions crates/gpui/src/platform/linux/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ pub(crate) struct LinuxPlatformInner {
}

pub(crate) struct LinuxPlatform {
client: Arc<dyn Client>,
inner: Arc<LinuxPlatformInner>,
client: Rc<dyn Client>,
inner: Rc<LinuxPlatformInner>,
}

pub(crate) struct LinuxPlatformState {
Expand Down Expand Up @@ -93,18 +93,18 @@ impl LinuxPlatform {
let client_dispatcher: Arc<dyn ClientDispatcher + Send + Sync> =
Arc::new(WaylandClientDispatcher::new(&conn));
let dispatcher = Arc::new(LinuxDispatcher::new(main_sender, &client_dispatcher));
let inner = Arc::new(LinuxPlatformInner {
let inner = Rc::new(LinuxPlatformInner {
background_executor: BackgroundExecutor::new(dispatcher.clone()),
foreground_executor: ForegroundExecutor::new(dispatcher.clone()),
main_receiver,
text_system,
callbacks,
state,
});
let client = Arc::new(WaylandClient::new(Arc::clone(&inner), Arc::clone(&conn)));
let client = Rc::new(WaylandClient::new(Rc::clone(&inner), Arc::clone(&conn)));
Self {
client,
inner: Arc::clone(&inner),
inner: Rc::clone(&inner),
}
}

Expand All @@ -115,31 +115,43 @@ impl LinuxPlatform {
callbacks: Mutex<Callbacks>,
state: Mutex<LinuxPlatformState>,
) -> Self {
let (xcb_connection, x_root_index) =
xcb::Connection::connect_with_extensions(None, &[xcb::Extension::Present], &[])
.unwrap();
let (xcb_connection, x_root_index) = xcb::Connection::connect_with_extensions(
None,
&[xcb::Extension::Present, 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,
}))
.unwrap();
assert!(xkb_ver.supported());

let atoms = XcbAtoms::intern_all(&xcb_connection).unwrap();
let xcb_connection = Arc::new(xcb_connection);
let client_dispatcher: Arc<dyn ClientDispatcher + Send + Sync> =
Arc::new(X11ClientDispatcher::new(&xcb_connection, x_root_index));
let dispatcher = Arc::new(LinuxDispatcher::new(main_sender, &client_dispatcher));
let inner = Arc::new(LinuxPlatformInner {
let inner = Rc::new(LinuxPlatformInner {
background_executor: BackgroundExecutor::new(dispatcher.clone()),
foreground_executor: ForegroundExecutor::new(dispatcher.clone()),
main_receiver,
text_system,
callbacks,
state,
});
let client = Arc::new(X11Client::new(
Arc::clone(&inner),
let client = Rc::new(X11Client::new(
Rc::clone(&inner),
xcb_connection,
x_root_index,
atoms,
));
Self {
client,
inner: Arc::clone(&inner),
inner: Rc::clone(&inner),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/gpui/src/platform/linux/wayland.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//todo!(linux): remove this once the relevant functionality has been implemented
#![allow(unused_variables)]

pub(crate) use client::*;
pub(crate) use client_dispatcher::*;

Expand Down
17 changes: 7 additions & 10 deletions crates/gpui/src/platform/linux/wayland/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,26 @@ pub(crate) struct WaylandClientState {
compositor: Option<wl_compositor::WlCompositor>,
buffer: Option<wl_buffer::WlBuffer>,
wm_base: Option<xdg_wm_base::XdgWmBase>,
windows: Vec<(xdg_surface::XdgSurface, Arc<WaylandWindowState>)>,
platform_inner: Arc<LinuxPlatformInner>,
windows: Vec<(xdg_surface::XdgSurface, Rc<WaylandWindowState>)>,
platform_inner: Rc<LinuxPlatformInner>,
}

pub(crate) struct WaylandClient {
platform_inner: Arc<LinuxPlatformInner>,
platform_inner: Rc<LinuxPlatformInner>,
conn: Arc<Connection>,
state: Mutex<WaylandClientState>,
event_queue: Mutex<EventQueue<WaylandClientState>>,
qh: Arc<QueueHandle<WaylandClientState>>,
}

impl WaylandClient {
pub(crate) fn new(
linux_platform_inner: Arc<LinuxPlatformInner>,
conn: Arc<Connection>,
) -> Self {
pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>, conn: Arc<Connection>) -> Self {
let state = WaylandClientState {
compositor: None,
buffer: None,
wm_base: None,
windows: Vec::new(),
platform_inner: Arc::clone(&linux_platform_inner),
platform_inner: Rc::clone(&linux_platform_inner),
};
let event_queue: EventQueue<WaylandClientState> = conn.new_event_queue();
let qh = event_queue.handle();
Expand Down Expand Up @@ -109,14 +106,14 @@ impl Client for WaylandClient {
wl_surface.frame(&self.qh, wl_surface.clone());
wl_surface.commit();

let window_state: Arc<WaylandWindowState> = Arc::new(WaylandWindowState::new(
let window_state = Rc::new(WaylandWindowState::new(
&self.conn,
wl_surface.clone(),
Arc::new(toplevel),
options,
));

state.windows.push((xdg_surface, Arc::clone(&window_state)));
state.windows.push((xdg_surface, Rc::clone(&window_state)));
Box::new(WaylandWindow(window_state))
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/gpui/src/platform/linux/wayland/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ pub(crate) struct WaylandDisplay {}
impl PlatformDisplay for WaylandDisplay {
// todo!(linux)
fn id(&self) -> DisplayId {
return DisplayId(123); // return some fake data so it doesn't panic
DisplayId(123) // return some fake data so it doesn't panic
}

// todo!(linux)
fn uuid(&self) -> anyhow::Result<Uuid> {
return Ok(Uuid::from_bytes([0; 16])); // return some fake data so it doesn't panic
Ok(Uuid::from_bytes([0; 16])) // return some fake data so it doesn't panic
}

// todo!(linux)
Expand Down
4 changes: 2 additions & 2 deletions crates/gpui/src/platform/linux/wayland/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ impl WaylandWindowState {
}

#[derive(Clone)]
pub(crate) struct WaylandWindow(pub(crate) Arc<WaylandWindowState>);
pub(crate) struct WaylandWindow(pub(crate) Rc<WaylandWindowState>);

impl HasWindowHandle for WaylandWindow {
fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
Expand Down Expand Up @@ -212,7 +212,7 @@ impl PlatformWindow for WaylandWindow {

// todo!(linux)
fn scale_factor(&self) -> f32 {
return 1f32;
1f32
}

//todo!(linux)
Expand Down
4 changes: 3 additions & 1 deletion crates/gpui/src/platform/linux/x11.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod client;
mod client_dispatcher;
pub mod display;
mod display;
mod event;
mod window;

pub(crate) use client::*;
pub(crate) use client_dispatcher::*;
pub(crate) use display::*;
pub(crate) use event::*;
pub(crate) use window::*;
Loading

0 comments on commit a41fb29

Please sign in to comment.