mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
X11: Continuous Presentation (#7762)
Alternative to #7758, which doesn't involve adding a new trait method `request_draw`. Somehow, my whole screen goes blinking black with this when moving the window, so not ready for landing. Release Notes: - N/A --------- Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
181f556269
commit
8f7a26f397
@ -96,7 +96,7 @@ objc = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
flume = "0.11"
|
||||
xcb = { version = "1.3", features = ["as-raw-xcb-connection"] }
|
||||
xcb = { version = "1.3", features = ["as-raw-xcb-connection", "present", "randr"] }
|
||||
as-raw-xcb-connection = "1"
|
||||
#TODO: use these on all platforms
|
||||
blade-graphics = { git = "https://github.com/kvark/blade", rev = "c4f951a88b345724cb952e920ad30e39851f7760" }
|
||||
|
@ -111,6 +111,9 @@ impl App {
|
||||
/// Builds an app with the given asset source.
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Self {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
log::info!("GPUI was compiled in test mode");
|
||||
|
||||
Self(AppContext::new(
|
||||
current_platform(),
|
||||
Arc::new(()),
|
||||
@ -676,7 +679,6 @@ impl AppContext {
|
||||
self.update_window(window, |_, cx| cx.draw()).unwrap();
|
||||
}
|
||||
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
if self.pending_effects.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
@ -61,6 +61,7 @@
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
#![allow(clippy::collapsible_else_if)]
|
||||
|
||||
#[macro_use]
|
||||
mod action;
|
||||
|
@ -12,7 +12,6 @@ pub(crate) use blade_atlas::*;
|
||||
pub(crate) use dispatcher::*;
|
||||
pub(crate) use platform::*;
|
||||
pub(crate) use text_system::*;
|
||||
pub(crate) use x11::display::*;
|
||||
pub(crate) use x11::*;
|
||||
|
||||
use blade_belt::*;
|
||||
|
@ -64,7 +64,9 @@ impl Default for LinuxPlatform {
|
||||
|
||||
impl LinuxPlatform {
|
||||
pub(crate) fn new() -> Self {
|
||||
let (xcb_connection, x_root_index) = xcb::Connection::connect(None).unwrap();
|
||||
let (xcb_connection, x_root_index) =
|
||||
xcb::Connection::connect_with_extensions(None, &[xcb::Extension::Present], &[])
|
||||
.unwrap();
|
||||
let atoms = XcbAtoms::intern_all(&xcb_connection).unwrap();
|
||||
|
||||
let xcb_connection = Arc::new(xcb_connection);
|
||||
|
@ -41,6 +41,11 @@ impl X11Client {
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_window(&self, win: x::Window) -> Rc<X11WindowState> {
|
||||
let state = self.state.lock();
|
||||
Rc::clone(&state.windows[&win])
|
||||
}
|
||||
}
|
||||
|
||||
impl Client for X11Client {
|
||||
@ -58,18 +63,14 @@ impl Client for X11Client {
|
||||
// window "x" button clicked by user, we gracefully exit
|
||||
let window = self.state.lock().windows.remove(&ev.window()).unwrap();
|
||||
window.destroy();
|
||||
let mut state = self.state.lock();
|
||||
let state = self.state.lock();
|
||||
self.platform_inner.state.lock().quit_requested |=
|
||||
state.windows.is_empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
xcb::Event::X(x::Event::Expose(ev)) => {
|
||||
let window = {
|
||||
let state = self.state.lock();
|
||||
Rc::clone(&state.windows[&ev.window()])
|
||||
};
|
||||
window.expose();
|
||||
self.get_window(ev.window()).refresh();
|
||||
}
|
||||
xcb::Event::X(x::Event::ConfigureNotify(ev)) => {
|
||||
let bounds = Bounds {
|
||||
@ -82,12 +83,14 @@ impl Client for X11Client {
|
||||
height: ev.height().into(),
|
||||
},
|
||||
};
|
||||
let window = {
|
||||
let state = self.state.lock();
|
||||
Rc::clone(&state.windows[&ev.window()])
|
||||
};
|
||||
window.configure(bounds)
|
||||
self.get_window(ev.window()).configure(bounds)
|
||||
}
|
||||
xcb::Event::Present(xcb::present::Event::CompleteNotify(ev)) => {
|
||||
let window = self.get_window(ev.window());
|
||||
window.refresh();
|
||||
window.request_refresh();
|
||||
}
|
||||
xcb::Event::Present(xcb::present::Event::IdleNotify(_ev)) => {}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@ -117,7 +120,7 @@ impl Client for X11Client {
|
||||
|
||||
fn open_window(
|
||||
&self,
|
||||
handle: AnyWindowHandle,
|
||||
_handle: AnyWindowHandle,
|
||||
options: WindowOptions,
|
||||
) -> Box<dyn PlatformWindow> {
|
||||
let x_window = self.xcb_connection.generate_id();
|
||||
@ -129,6 +132,7 @@ impl Client for X11Client {
|
||||
x_window,
|
||||
&self.atoms,
|
||||
));
|
||||
window_ptr.request_refresh();
|
||||
|
||||
self.state
|
||||
.lock()
|
||||
|
@ -202,6 +202,16 @@ impl X11WindowState {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let fake_id = xcb_connection.generate_id();
|
||||
xcb_connection
|
||||
.send_and_check_request(&xcb::present::SelectInput {
|
||||
eid: fake_id,
|
||||
window: x_window,
|
||||
//Note: also consider `IDLE_NOTIFY`
|
||||
event_mask: xcb::present::EventMask::COMPLETE_NOTIFY,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
xcb_connection.send_request(&x::MapWindow { window: x_window });
|
||||
xcb_connection.flush().unwrap();
|
||||
|
||||
@ -258,7 +268,7 @@ impl X11WindowState {
|
||||
self.xcb_connection.flush().unwrap();
|
||||
}
|
||||
|
||||
pub fn expose(&self) {
|
||||
pub fn refresh(&self) {
|
||||
let mut cb = self.callbacks.lock();
|
||||
if let Some(ref mut fun) = cb.request_frame {
|
||||
fun();
|
||||
@ -291,6 +301,18 @@ impl X11WindowState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_refresh(&self) {
|
||||
self.xcb_connection
|
||||
.send_and_check_request(&xcb::present::NotifyMsc {
|
||||
window: self.x_window,
|
||||
serial: 0,
|
||||
target_msc: 0,
|
||||
divisor: 1,
|
||||
remainder: 0,
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformWindow for X11Window {
|
||||
|
@ -39,10 +39,10 @@ postage.workspace = true
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = "0.9.3"
|
||||
|
||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||
[target.'cfg(all(not(target_os = "macos")))'.dependencies]
|
||||
async-trait = { workspace = true }
|
||||
collections = { workspace = true, features = ["test-support"] }
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
collections = { workspace = true }
|
||||
gpui = { workspace = true }
|
||||
live_kit_server.workspace = true
|
||||
nanoid = "0.4"
|
||||
|
||||
|
@ -73,6 +73,8 @@ impl TestServer {
|
||||
}
|
||||
|
||||
pub async fn create_room(&self, room: String) -> Result<()> {
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
let mut server_rooms = self.rooms.lock();
|
||||
if server_rooms.contains_key(&room) {
|
||||
@ -85,6 +87,8 @@ impl TestServer {
|
||||
|
||||
async fn delete_room(&self, room: String) -> Result<()> {
|
||||
// TODO: clear state associated with all `Room`s.
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
let mut server_rooms = self.rooms.lock();
|
||||
server_rooms
|
||||
@ -94,7 +98,10 @@ impl TestServer {
|
||||
}
|
||||
|
||||
async fn join_room(&self, token: String, client_room: Arc<Room>) -> Result<()> {
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
|
||||
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
||||
let identity = claims.sub.unwrap().to_string();
|
||||
let room_name = claims.video.room.unwrap();
|
||||
@ -140,6 +147,8 @@ impl TestServer {
|
||||
}
|
||||
|
||||
async fn leave_room(&self, token: String) -> Result<()> {
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
||||
let identity = claims.sub.unwrap().to_string();
|
||||
@ -160,8 +169,10 @@ impl TestServer {
|
||||
|
||||
async fn remove_participant(&self, room_name: String, identity: String) -> Result<()> {
|
||||
// TODO: clear state associated with the `Room`.
|
||||
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
|
||||
let mut server_rooms = self.rooms.lock();
|
||||
let room = server_rooms
|
||||
.get_mut(&room_name)
|
||||
@ -182,6 +193,8 @@ impl TestServer {
|
||||
identity: String,
|
||||
permission: proto::ParticipantPermission,
|
||||
) -> Result<()> {
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
let mut server_rooms = self.rooms.lock();
|
||||
let room = server_rooms
|
||||
@ -192,6 +205,8 @@ impl TestServer {
|
||||
}
|
||||
|
||||
pub async fn disconnect_client(&self, client_identity: String) {
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
let mut server_rooms = self.rooms.lock();
|
||||
for room in server_rooms.values_mut() {
|
||||
@ -206,6 +221,8 @@ impl TestServer {
|
||||
token: String,
|
||||
local_track: LocalVideoTrack,
|
||||
) -> Result<Sid> {
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
||||
let identity = claims.sub.unwrap().to_string();
|
||||
@ -259,7 +276,10 @@ impl TestServer {
|
||||
token: String,
|
||||
_local_track: &LocalAudioTrack,
|
||||
) -> Result<Sid> {
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
self.executor.simulate_random_delay().await;
|
||||
|
||||
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
||||
let identity = claims.sub.unwrap().to_string();
|
||||
let room_name = claims.video.room.unwrap();
|
||||
@ -539,8 +559,13 @@ impl Room {
|
||||
pub fn display_sources(self: &Arc<Self>) -> impl Future<Output = Result<Vec<MacOSDisplay>>> {
|
||||
let this = self.clone();
|
||||
async move {
|
||||
let server = this.test_server();
|
||||
server.executor.simulate_random_delay().await;
|
||||
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
{
|
||||
let server = this.test_server();
|
||||
server.executor.simulate_random_delay().await;
|
||||
}
|
||||
|
||||
Ok(this.0.lock().display_sources.clone())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user