Fix or promote leftover TODOs and GPUI APIs (#12514)

fixes https://github.com/zed-industries/zed/issues/11966

Release Notes:

- N/A
This commit is contained in:
Mikayla Maki 2024-05-31 18:36:15 -07:00 committed by GitHub
parent a6e0c8aca1
commit 94c3101fb0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 581 additions and 441 deletions

View file

@ -1,14 +1,11 @@
use core::hash;
use std::cell::{RefCell, RefMut};
use std::ffi::OsString;
use std::ops::{Deref, DerefMut};
use std::hash::Hash;
use std::os::fd::{AsRawFd, BorrowedFd};
use std::path::PathBuf;
use std::rc::{Rc, Weak};
use std::sync::Arc;
use std::time::{Duration, Instant};
use async_task::Runnable;
use calloop::timer::{TimeoutAction, Timer};
use calloop::{EventLoop, LoopHandle};
use calloop_wayland_source::WaylandSource;
@ -16,7 +13,7 @@ use collections::HashMap;
use copypasta::wayland_clipboard::{create_clipboards_from_external, Clipboard, Primary};
use copypasta::ClipboardProvider;
use filedescriptor::Pipe;
use parking_lot::Mutex;
use smallvec::SmallVec;
use util::ResultExt;
use wayland_backend::client::ObjectId;
@ -26,9 +23,8 @@ use wayland_client::globals::{registry_queue_init, GlobalList, GlobalListContent
use wayland_client::protocol::wl_callback::{self, WlCallback};
use wayland_client::protocol::wl_data_device_manager::DndAction;
use wayland_client::protocol::wl_pointer::AxisSource;
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::protocol::{
wl_data_device, wl_data_device_manager, wl_data_offer, wl_data_source, wl_output, wl_region,
wl_data_device, wl_data_device_manager, wl_data_offer, wl_output, wl_region,
};
use wayland_client::{
delegate_noop,
@ -38,7 +34,6 @@ use wayland_client::{
},
Connection, Dispatch, Proxy, QueueHandle,
};
use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape;
use wayland_protocols::wp::cursor_shape::v1::client::{
wp_cursor_shape_device_v1, wp_cursor_shape_manager_v1,
};
@ -62,7 +57,8 @@ use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1;
use xkbcommon::xkb::{self, Keycode, KEYMAP_COMPILE_NO_FLAGS};
use super::super::{open_uri_internal, read_fd, DOUBLE_CLICK_INTERVAL};
use super::window::{ImeInput, WaylandWindowState, WaylandWindowStatePtr};
use super::display::WaylandDisplay;
use super::window::{ImeInput, WaylandWindowStatePtr};
use crate::platform::linux::is_within_click_distance;
use crate::platform::linux::wayland::cursor::Cursor;
use crate::platform::linux::wayland::serial::{SerialKind, SerialTracker};
@ -71,7 +67,7 @@ use crate::platform::linux::xdg_desktop_portal::{Event as XDPEvent, XDPEventSour
use crate::platform::linux::LinuxClient;
use crate::platform::PlatformWindow;
use crate::{
point, px, Bounds, FileDropEvent, ForegroundExecutor, MouseExitEvent, WindowAppearance,
point, px, size, Bounds, DevicePixels, FileDropEvent, ForegroundExecutor, MouseExitEvent, Size,
SCROLL_LINES,
};
use crate::{
@ -143,11 +139,49 @@ impl Globals {
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InProgressOutput {
scale: Option<i32>,
position: Option<Point<DevicePixels>>,
size: Option<Size<DevicePixels>>,
}
impl InProgressOutput {
fn complete(&self) -> Option<Output> {
if let Some((position, size)) = self.position.zip(self.size) {
let scale = self.scale.unwrap_or(1);
Some(Output {
scale,
bounds: Bounds::new(position, size),
})
} else {
None
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Output {
pub scale: i32,
pub bounds: Bounds<DevicePixels>,
}
impl Hash for Output {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write_i32(self.scale);
state.write_i32(self.bounds.origin.x.0);
state.write_i32(self.bounds.origin.y.0);
state.write_i32(self.bounds.size.width.0);
state.write_i32(self.bounds.size.height.0);
}
}
pub(crate) struct WaylandClientState {
serial_tracker: SerialTracker,
globals: Globals,
wl_seat: wl_seat::WlSeat, // todo(linux): multi-seat support
wl_seat: wl_seat::WlSeat, // TODO: Multi seat support
wl_pointer: Option<wl_pointer::WlPointer>,
wl_keyboard: Option<wl_keyboard::WlKeyboard>,
cursor_shape_device: Option<wp_cursor_shape_device_v1::WpCursorShapeDeviceV1>,
data_device: Option<wl_data_device::WlDataDevice>,
text_input: Option<zwp_text_input_v3::ZwpTextInputV3>,
@ -156,15 +190,16 @@ pub(crate) struct WaylandClientState {
// Surface to Window mapping
windows: HashMap<ObjectId, WaylandWindowStatePtr>,
// Output to scale mapping
output_scales: HashMap<ObjectId, i32>,
outputs: HashMap<ObjectId, Output>,
in_progress_outputs: HashMap<ObjectId, InProgressOutput>,
keymap_state: Option<xkb::State>,
compose_state: Option<xkb::compose::State>,
drag: DragState,
click: ClickState,
repeat: KeyRepeat,
modifiers: Modifiers,
pub modifiers: Modifiers,
axis_source: AxisSource,
mouse_location: Option<Point<Pixels>>,
pub mouse_location: Option<Point<Pixels>>,
continuous_scroll_delta: Option<Point<Pixels>>,
discrete_scroll_delta: Option<Point<f32>>,
vertical_modifier: f32,
@ -210,7 +245,7 @@ pub(crate) struct KeyRepeat {
pub struct WaylandClientStatePtr(Weak<RefCell<WaylandClientState>>);
impl WaylandClientStatePtr {
fn get_client(&self) -> Rc<RefCell<WaylandClientState>> {
pub fn get_client(&self) -> Rc<RefCell<WaylandClientState>> {
self.0
.upgrade()
.expect("The pointer should always be valid when dispatching in wayland")
@ -328,7 +363,7 @@ impl WaylandClient {
let qh = event_queue.handle();
let mut seat: Option<wl_seat::WlSeat> = None;
let mut outputs = HashMap::default();
let mut in_progress_outputs = HashMap::default();
globals.contents().with_list(|list| {
for global in list {
match &global.interface[..] {
@ -347,7 +382,7 @@ impl WaylandClient {
&qh,
(),
);
outputs.insert(output.id(), 1);
in_progress_outputs.insert(output.id(), InProgressOutput::default());
}
_ => {}
}
@ -361,11 +396,13 @@ impl WaylandClient {
let (common, main_receiver) = LinuxCommon::new(event_loop.get_signal());
let handle = event_loop.handle();
handle.insert_source(main_receiver, |event, _, _: &mut WaylandClientStatePtr| {
if let calloop::channel::Event::Msg(runnable) = event {
runnable.run();
}
});
handle
.insert_source(main_receiver, |event, _, _: &mut WaylandClientStatePtr| {
if let calloop::channel::Event::Msg(runnable) = event {
runnable.run();
}
})
.unwrap();
let seat = seat.unwrap();
let globals = Globals::new(
@ -384,33 +421,37 @@ impl WaylandClient {
let cursor = Cursor::new(&conn, &globals, 24);
handle.insert_source(XDPEventSource::new(&common.background_executor), {
move |event, _, client| match event {
XDPEvent::WindowAppearance(appearance) => {
if let Some(client) = client.0.upgrade() {
let mut client = client.borrow_mut();
handle
.insert_source(XDPEventSource::new(&common.background_executor), {
move |event, _, client| match event {
XDPEvent::WindowAppearance(appearance) => {
if let Some(client) = client.0.upgrade() {
let mut client = client.borrow_mut();
client.common.appearance = appearance;
client.common.appearance = appearance;
for (_, window) in &mut client.windows {
window.set_appearance(appearance);
for (_, window) in &mut client.windows {
window.set_appearance(appearance);
}
}
}
}
}
});
})
.unwrap();
let mut state = Rc::new(RefCell::new(WaylandClientState {
serial_tracker: SerialTracker::new(),
globals,
wl_seat: seat,
wl_pointer: None,
wl_keyboard: None,
cursor_shape_device: None,
data_device,
text_input: None,
pre_edit_text: None,
composing: false,
output_scales: outputs,
outputs: HashMap::default(),
in_progress_outputs,
windows: HashMap::default(),
common,
keymap_state: None,
@ -459,7 +500,9 @@ impl WaylandClient {
pending_open_uri: None,
}));
WaylandSource::new(conn, event_queue).insert(handle);
WaylandSource::new(conn, event_queue)
.insert(handle)
.unwrap();
Self(state)
}
@ -467,11 +510,32 @@ impl WaylandClient {
impl LinuxClient for WaylandClient {
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
Vec::new()
self.0
.borrow()
.outputs
.iter()
.map(|(id, output)| {
Rc::new(WaylandDisplay {
id: id.clone(),
bounds: output.bounds,
}) as Rc<dyn PlatformDisplay>
})
.collect()
}
fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
unimplemented!()
self.0
.borrow()
.outputs
.iter()
.find_map(|(object_id, output)| {
(object_id.protocol_id() == id.0).then(|| {
Rc::new(WaylandDisplay {
id: object_id.clone(),
bounds: output.bounds,
}) as Rc<dyn PlatformDisplay>
})
})
}
fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
@ -486,6 +550,7 @@ impl LinuxClient for WaylandClient {
let mut state = self.0.borrow_mut();
let (window, surface_id) = WaylandWindow::new(
handle,
state.globals.clone(),
WaylandClientStatePtr(Rc::downgrade(&self.0)),
params,
@ -566,7 +631,8 @@ impl LinuxClient for WaylandClient {
.primary
.as_mut()
.unwrap()
.set_contents(item.text);
.set_contents(item.text)
.ok();
}
fn write_to_clipboard(&self, item: crate::ClipboardItem) {
@ -575,7 +641,8 @@ impl LinuxClient for WaylandClient {
.clipboard
.as_mut()
.unwrap()
.set_contents(item.text);
.set_contents(item.text)
.ok();
}
fn read_from_primary(&self) -> Option<crate::ClipboardItem> {
@ -605,6 +672,14 @@ impl LinuxClient for WaylandClient {
metadata: None,
})
}
fn active_window(&self) -> Option<AnyWindowHandle> {
self.0
.borrow_mut()
.keyboard_focused_window
.as_ref()
.map(|window| window.handle())
}
}
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStatePtr {
@ -626,18 +701,33 @@ impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStat
version,
} => match &interface[..] {
"wl_seat" => {
state.wl_pointer = None;
registry.bind::<wl_seat::WlSeat, _, _>(name, wl_seat_version(version), qh, ());
if let Some(wl_pointer) = state.wl_pointer.take() {
wl_pointer.release();
}
if let Some(wl_keyboard) = state.wl_keyboard.take() {
wl_keyboard.release();
}
state.wl_seat.release();
state.wl_seat = registry.bind::<wl_seat::WlSeat, _, _>(
name,
wl_seat_version(version),
qh,
(),
);
}
"wl_output" => {
let output =
registry.bind::<wl_output::WlOutput, _, _>(name, WL_OUTPUT_VERSION, qh, ());
state.output_scales.insert(output.id(), 1);
state
.in_progress_outputs
.insert(output.id(), InProgressOutput::default());
}
_ => {}
},
wl_registry::Event::GlobalRemove { name: _ } => {}
wl_registry::Event::GlobalRemove { name: _ } => {
// TODO: handle global removal
}
_ => {}
}
}
@ -667,7 +757,7 @@ impl Dispatch<WlCallback, ObjectId> for WaylandClientStatePtr {
event: wl_callback::Event,
surface_id: &ObjectId,
_: &Connection,
qh: &QueueHandle<Self>,
_: &QueueHandle<Self>,
) {
let client = state.get_client();
let mut state = client.borrow_mut();
@ -677,7 +767,7 @@ impl Dispatch<WlCallback, ObjectId> for WaylandClientStatePtr {
drop(state);
match event {
wl_callback::Event::Done { callback_data } => {
wl_callback::Event::Done { .. } => {
window.frame(true);
}
_ => {}
@ -707,10 +797,10 @@ impl Dispatch<wl_surface::WlSurface, ()> for WaylandClientStatePtr {
let Some(window) = get_window(&mut state, &surface.id()) else {
return;
};
let scales = state.output_scales.clone();
let outputs = state.outputs.clone();
drop(state);
window.handle_surface_event(event, scales);
window.handle_surface_event(event, outputs);
}
}
@ -726,13 +816,25 @@ impl Dispatch<wl_output::WlOutput, ()> for WaylandClientStatePtr {
let mut client = this.get_client();
let mut state = client.borrow_mut();
let Some(mut output_scale) = state.output_scales.get_mut(&output.id()) else {
let Some(mut in_progress_output) = state.in_progress_outputs.get_mut(&output.id()) else {
return;
};
match event {
wl_output::Event::Scale { factor } => {
*output_scale = factor;
in_progress_output.scale = Some(factor);
}
wl_output::Event::Geometry { x, y, .. } => {
in_progress_output.position = Some(point(DevicePixels(x), DevicePixels(y)))
}
wl_output::Event::Mode { width, height, .. } => {
in_progress_output.size = Some(size(DevicePixels(width), DevicePixels(height)))
}
wl_output::Event::Done => {
if let Some(complete) = in_progress_output.complete() {
state.outputs.insert(output.id(), complete);
}
state.in_progress_outputs.remove(&output.id());
}
_ => {}
}
@ -742,7 +844,7 @@ impl Dispatch<wl_output::WlOutput, ()> for WaylandClientStatePtr {
impl Dispatch<xdg_surface::XdgSurface, ObjectId> for WaylandClientStatePtr {
fn event(
state: &mut Self,
xdg_surface: &xdg_surface::XdgSurface,
_: &xdg_surface::XdgSurface,
event: xdg_surface::Event,
surface_id: &ObjectId,
_: &Connection,
@ -761,7 +863,7 @@ impl Dispatch<xdg_surface::XdgSurface, ObjectId> for WaylandClientStatePtr {
impl Dispatch<xdg_toplevel::XdgToplevel, ObjectId> for WaylandClientStatePtr {
fn event(
this: &mut Self,
xdg_toplevel: &xdg_toplevel::XdgToplevel,
_: &xdg_toplevel::XdgToplevel,
event: <xdg_toplevel::XdgToplevel as Proxy>::Event,
surface_id: &ObjectId,
_: &Connection,
@ -824,8 +926,8 @@ impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientStatePtr {
state: &mut Self,
seat: &wl_seat::WlSeat,
event: wl_seat::Event,
data: &(),
conn: &Connection,
_: &(),
_: &Connection,
qh: &QueueHandle<Self>,
) {
if let wl_seat::Event::Capabilities {
@ -835,12 +937,19 @@ impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientStatePtr {
let client = state.get_client();
let mut state = client.borrow_mut();
if capabilities.contains(wl_seat::Capability::Keyboard) {
seat.get_keyboard(qh, ());
let keyboard = seat.get_keyboard(qh, ());
state.text_input = state
.globals
.text_input_manager
.as_ref()
.map(|text_input_manager| text_input_manager.get_text_input(&seat, qh, ()));
if let Some(wl_keyboard) = &state.wl_keyboard {
wl_keyboard.release();
}
state.wl_keyboard = Some(keyboard);
}
if capabilities.contains(wl_seat::Capability::Pointer) {
let pointer = seat.get_pointer(qh, ());
@ -849,6 +958,11 @@ impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientStatePtr {
.cursor_shape_manager
.as_ref()
.map(|cursor_shape_manager| cursor_shape_manager.get_pointer(&pointer, qh, ()));
if let Some(wl_pointer) = &state.wl_pointer {
wl_pointer.release();
}
state.wl_pointer = Some(pointer);
}
}
@ -858,11 +972,11 @@ impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientStatePtr {
impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
fn event(
this: &mut Self,
keyboard: &wl_keyboard::WlKeyboard,
_: &wl_keyboard::WlKeyboard,
event: wl_keyboard::Event,
data: &(),
conn: &Connection,
qh: &QueueHandle<Self>,
_: &(),
_: &Connection,
_: &QueueHandle<Self>,
) {
let mut client = this.get_client();
let mut state = client.borrow_mut();
@ -1018,8 +1132,8 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
state.compose_state = Some(compose);
}
let input = PlatformInput::KeyDown(KeyDownEvent {
keystroke: keystroke,
is_held: false, // todo(linux)
keystroke: keystroke.clone(),
is_held: false,
});
state.repeat.current_id += 1;
@ -1030,8 +1144,11 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
state
.loop_handle
.insert_source(Timer::from_duration(state.repeat.delay), {
let input = input.clone();
move |event, _metadata, this| {
let input = PlatformInput::KeyDown(KeyDownEvent {
keystroke,
is_held: true,
});
move |_event, _metadata, this| {
let mut client = this.get_client();
let mut state = client.borrow_mut();
let is_repeating = id == state.repeat.current_id
@ -1080,18 +1197,18 @@ impl Dispatch<zwp_text_input_v3::ZwpTextInputV3, ()> for WaylandClientStatePtr {
this: &mut Self,
text_input: &zwp_text_input_v3::ZwpTextInputV3,
event: <zwp_text_input_v3::ZwpTextInputV3 as Proxy>::Event,
data: &(),
conn: &Connection,
qhandle: &QueueHandle<Self>,
_: &(),
_: &Connection,
_: &QueueHandle<Self>,
) {
let client = this.get_client();
let mut state = client.borrow_mut();
match event {
zwp_text_input_v3::Event::Enter { surface } => {
zwp_text_input_v3::Event::Enter { .. } => {
drop(state);
this.enable_ime();
}
zwp_text_input_v3::Event::Leave { surface } => {
zwp_text_input_v3::Event::Leave { .. } => {
drop(state);
this.disable_ime();
}
@ -1119,11 +1236,7 @@ impl Dispatch<zwp_text_input_v3::ZwpTextInputV3, ()> for WaylandClientStatePtr {
}
}
}
zwp_text_input_v3::Event::PreeditString {
text,
cursor_begin,
cursor_end,
} => {
zwp_text_input_v3::Event::PreeditString { text, .. } => {
state.composing = true;
state.pre_edit_text = text;
}
@ -1183,9 +1296,9 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
this: &mut Self,
wl_pointer: &wl_pointer::WlPointer,
event: wl_pointer::Event,
data: &(),
conn: &Connection,
qh: &QueueHandle<Self>,
_: &(),
_: &Connection,
_: &QueueHandle<Self>,
) {
let mut client = this.get_client();
let mut state = client.borrow_mut();
@ -1220,7 +1333,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
window.set_focused(true);
}
}
wl_pointer::Event::Leave { surface, .. } => {
wl_pointer::Event::Leave { .. } => {
if let Some(focused_window) = state.mouse_focused_window.clone() {
let input = PlatformInput::MouseExited(MouseExitEvent {
position: state.mouse_location.unwrap(),
@ -1237,7 +1350,6 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
}
}
wl_pointer::Event::Motion {
time,
surface_x,
surface_y,
..
@ -1280,7 +1392,6 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
wl_pointer::ButtonState::Pressed => {
if let Some(window) = state.keyboard_focused_window.clone() {
if state.composing && state.text_input.is_some() {
let text_input = state.text_input.as_ref().unwrap();
drop(state);
// text_input_v3 don't have something like a reset function
this.disable_ime();
@ -1351,7 +1462,6 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
state.axis_source = axis_source;
}
wl_pointer::Event::Axis {
time,
axis: WEnum::Value(axis),
value,
..
@ -1364,13 +1474,10 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
wl_pointer::Axis::HorizontalScroll => state.horizontal_modifier,
_ => 1.0,
};
let supports_relative_direction =
wl_pointer.version() >= wl_pointer::EVT_AXIS_RELATIVE_DIRECTION_SINCE;
state.scroll_event_received = true;
let scroll_delta = state
.continuous_scroll_delta
.get_or_insert(point(px(0.0), px(0.0)));
// TODO: Make nice feeling kinetic scrolling that integrates with the platform's scroll settings
let modifier = 3.0;
match axis {
wl_pointer::Axis::VerticalScroll => {