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
9 changed files with 78 additions and 23 deletions
|
@ -96,7 +96,7 @@ objc = "0.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
flume = "0.11"
|
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"
|
as-raw-xcb-connection = "1"
|
||||||
#TODO: use these on all platforms
|
#TODO: use these on all platforms
|
||||||
blade-graphics = { git = "https://github.com/kvark/blade", rev = "c4f951a88b345724cb952e920ad30e39851f7760" }
|
blade-graphics = { git = "https://github.com/kvark/blade", rev = "c4f951a88b345724cb952e920ad30e39851f7760" }
|
||||||
|
|
|
@ -111,6 +111,9 @@ impl App {
|
||||||
/// Builds an app with the given asset source.
|
/// Builds an app with the given asset source.
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
log::info!("GPUI was compiled in test mode");
|
||||||
|
|
||||||
Self(AppContext::new(
|
Self(AppContext::new(
|
||||||
current_platform(),
|
current_platform(),
|
||||||
Arc::new(()),
|
Arc::new(()),
|
||||||
|
@ -676,7 +679,6 @@ impl AppContext {
|
||||||
self.update_window(window, |_, cx| cx.draw()).unwrap();
|
self.update_window(window, |_, cx| cx.draw()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::collapsible_else_if)]
|
|
||||||
if self.pending_effects.is_empty() {
|
if self.pending_effects.is_empty() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
|
#![allow(clippy::collapsible_else_if)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod action;
|
mod action;
|
||||||
|
|
|
@ -12,7 +12,6 @@ pub(crate) use blade_atlas::*;
|
||||||
pub(crate) use dispatcher::*;
|
pub(crate) use dispatcher::*;
|
||||||
pub(crate) use platform::*;
|
pub(crate) use platform::*;
|
||||||
pub(crate) use text_system::*;
|
pub(crate) use text_system::*;
|
||||||
pub(crate) use x11::display::*;
|
|
||||||
pub(crate) use x11::*;
|
pub(crate) use x11::*;
|
||||||
|
|
||||||
use blade_belt::*;
|
use blade_belt::*;
|
||||||
|
|
|
@ -64,7 +64,9 @@ impl Default for LinuxPlatform {
|
||||||
|
|
||||||
impl LinuxPlatform {
|
impl LinuxPlatform {
|
||||||
pub(crate) fn new() -> Self {
|
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 atoms = XcbAtoms::intern_all(&xcb_connection).unwrap();
|
||||||
|
|
||||||
let xcb_connection = Arc::new(xcb_connection);
|
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 {
|
impl Client for X11Client {
|
||||||
|
@ -58,18 +63,14 @@ impl Client for X11Client {
|
||||||
// window "x" button clicked by user, we gracefully exit
|
// window "x" button clicked by user, we gracefully exit
|
||||||
let window = self.state.lock().windows.remove(&ev.window()).unwrap();
|
let window = self.state.lock().windows.remove(&ev.window()).unwrap();
|
||||||
window.destroy();
|
window.destroy();
|
||||||
let mut state = self.state.lock();
|
let state = self.state.lock();
|
||||||
self.platform_inner.state.lock().quit_requested |=
|
self.platform_inner.state.lock().quit_requested |=
|
||||||
state.windows.is_empty();
|
state.windows.is_empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xcb::Event::X(x::Event::Expose(ev)) => {
|
xcb::Event::X(x::Event::Expose(ev)) => {
|
||||||
let window = {
|
self.get_window(ev.window()).refresh();
|
||||||
let state = self.state.lock();
|
|
||||||
Rc::clone(&state.windows[&ev.window()])
|
|
||||||
};
|
|
||||||
window.expose();
|
|
||||||
}
|
}
|
||||||
xcb::Event::X(x::Event::ConfigureNotify(ev)) => {
|
xcb::Event::X(x::Event::ConfigureNotify(ev)) => {
|
||||||
let bounds = Bounds {
|
let bounds = Bounds {
|
||||||
|
@ -82,12 +83,14 @@ impl Client for X11Client {
|
||||||
height: ev.height().into(),
|
height: ev.height().into(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let window = {
|
self.get_window(ev.window()).configure(bounds)
|
||||||
let state = self.state.lock();
|
|
||||||
Rc::clone(&state.windows[&ev.window()])
|
|
||||||
};
|
|
||||||
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(
|
fn open_window(
|
||||||
&self,
|
&self,
|
||||||
handle: AnyWindowHandle,
|
_handle: AnyWindowHandle,
|
||||||
options: WindowOptions,
|
options: WindowOptions,
|
||||||
) -> Box<dyn PlatformWindow> {
|
) -> Box<dyn PlatformWindow> {
|
||||||
let x_window = self.xcb_connection.generate_id();
|
let x_window = self.xcb_connection.generate_id();
|
||||||
|
@ -129,6 +132,7 @@ impl Client for X11Client {
|
||||||
x_window,
|
x_window,
|
||||||
&self.atoms,
|
&self.atoms,
|
||||||
));
|
));
|
||||||
|
window_ptr.request_refresh();
|
||||||
|
|
||||||
self.state
|
self.state
|
||||||
.lock()
|
.lock()
|
||||||
|
|
|
@ -202,6 +202,16 @@ impl X11WindowState {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.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.send_request(&x::MapWindow { window: x_window });
|
||||||
xcb_connection.flush().unwrap();
|
xcb_connection.flush().unwrap();
|
||||||
|
|
||||||
|
@ -258,7 +268,7 @@ impl X11WindowState {
|
||||||
self.xcb_connection.flush().unwrap();
|
self.xcb_connection.flush().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expose(&self) {
|
pub fn refresh(&self) {
|
||||||
let mut cb = self.callbacks.lock();
|
let mut cb = self.callbacks.lock();
|
||||||
if let Some(ref mut fun) = cb.request_frame {
|
if let Some(ref mut fun) = cb.request_frame {
|
||||||
fun();
|
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 {
|
impl PlatformWindow for X11Window {
|
||||||
|
|
|
@ -39,10 +39,10 @@ postage.workspace = true
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
core-foundation = "0.9.3"
|
core-foundation = "0.9.3"
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
[target.'cfg(all(not(target_os = "macos")))'.dependencies]
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
collections = { workspace = true, features = ["test-support"] }
|
collections = { workspace = true }
|
||||||
gpui = { workspace = true, features = ["test-support"] }
|
gpui = { workspace = true }
|
||||||
live_kit_server.workspace = true
|
live_kit_server.workspace = true
|
||||||
nanoid = "0.4"
|
nanoid = "0.4"
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,8 @@ impl TestServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_room(&self, room: String) -> Result<()> {
|
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;
|
self.executor.simulate_random_delay().await;
|
||||||
let mut server_rooms = self.rooms.lock();
|
let mut server_rooms = self.rooms.lock();
|
||||||
if server_rooms.contains_key(&room) {
|
if server_rooms.contains_key(&room) {
|
||||||
|
@ -85,6 +87,8 @@ impl TestServer {
|
||||||
|
|
||||||
async fn delete_room(&self, room: String) -> Result<()> {
|
async fn delete_room(&self, room: String) -> Result<()> {
|
||||||
// TODO: clear state associated with all `Room`s.
|
// 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;
|
self.executor.simulate_random_delay().await;
|
||||||
let mut server_rooms = self.rooms.lock();
|
let mut server_rooms = self.rooms.lock();
|
||||||
server_rooms
|
server_rooms
|
||||||
|
@ -94,7 +98,10 @@ impl TestServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn join_room(&self, token: String, client_room: Arc<Room>) -> Result<()> {
|
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;
|
self.executor.simulate_random_delay().await;
|
||||||
|
|
||||||
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
||||||
let identity = claims.sub.unwrap().to_string();
|
let identity = claims.sub.unwrap().to_string();
|
||||||
let room_name = claims.video.room.unwrap();
|
let room_name = claims.video.room.unwrap();
|
||||||
|
@ -140,6 +147,8 @@ impl TestServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn leave_room(&self, token: String) -> Result<()> {
|
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;
|
self.executor.simulate_random_delay().await;
|
||||||
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
||||||
let identity = claims.sub.unwrap().to_string();
|
let identity = claims.sub.unwrap().to_string();
|
||||||
|
@ -160,8 +169,10 @@ impl TestServer {
|
||||||
|
|
||||||
async fn remove_participant(&self, room_name: String, identity: String) -> Result<()> {
|
async fn remove_participant(&self, room_name: String, identity: String) -> Result<()> {
|
||||||
// TODO: clear state associated with the `Room`.
|
// 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;
|
self.executor.simulate_random_delay().await;
|
||||||
|
|
||||||
let mut server_rooms = self.rooms.lock();
|
let mut server_rooms = self.rooms.lock();
|
||||||
let room = server_rooms
|
let room = server_rooms
|
||||||
.get_mut(&room_name)
|
.get_mut(&room_name)
|
||||||
|
@ -182,6 +193,8 @@ impl TestServer {
|
||||||
identity: String,
|
identity: String,
|
||||||
permission: proto::ParticipantPermission,
|
permission: proto::ParticipantPermission,
|
||||||
) -> Result<()> {
|
) -> 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;
|
self.executor.simulate_random_delay().await;
|
||||||
let mut server_rooms = self.rooms.lock();
|
let mut server_rooms = self.rooms.lock();
|
||||||
let room = server_rooms
|
let room = server_rooms
|
||||||
|
@ -192,6 +205,8 @@ impl TestServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn disconnect_client(&self, client_identity: String) {
|
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;
|
self.executor.simulate_random_delay().await;
|
||||||
let mut server_rooms = self.rooms.lock();
|
let mut server_rooms = self.rooms.lock();
|
||||||
for room in server_rooms.values_mut() {
|
for room in server_rooms.values_mut() {
|
||||||
|
@ -206,6 +221,8 @@ impl TestServer {
|
||||||
token: String,
|
token: String,
|
||||||
local_track: LocalVideoTrack,
|
local_track: LocalVideoTrack,
|
||||||
) -> Result<Sid> {
|
) -> 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;
|
self.executor.simulate_random_delay().await;
|
||||||
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
||||||
let identity = claims.sub.unwrap().to_string();
|
let identity = claims.sub.unwrap().to_string();
|
||||||
|
@ -259,7 +276,10 @@ impl TestServer {
|
||||||
token: String,
|
token: String,
|
||||||
_local_track: &LocalAudioTrack,
|
_local_track: &LocalAudioTrack,
|
||||||
) -> Result<Sid> {
|
) -> 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;
|
self.executor.simulate_random_delay().await;
|
||||||
|
|
||||||
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
let claims = live_kit_server::token::validate(&token, &self.secret_key)?;
|
||||||
let identity = claims.sub.unwrap().to_string();
|
let identity = claims.sub.unwrap().to_string();
|
||||||
let room_name = claims.video.room.unwrap();
|
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>>> {
|
pub fn display_sources(self: &Arc<Self>) -> impl Future<Output = Result<Vec<MacOSDisplay>>> {
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
async move {
|
async move {
|
||||||
let server = this.test_server();
|
//todo!(linux): Remove this once the cross-platform LiveKit implementation is merged
|
||||||
server.executor.simulate_random_delay().await;
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
{
|
||||||
|
let server = this.test_server();
|
||||||
|
server.executor.simulate_random_delay().await;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(this.0.lock().display_sources.clone())
|
Ok(this.0.lock().display_sources.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue