Skip to content

Commit

Permalink
server: Add flush_clients method to DisplayHandle, matching `Disp…
Browse files Browse the repository at this point in the history
…lay`

It seems like this is necessary to insert the `Display` itself as a
calloop source, but still allow compositors to flush output where they
wish to.

I don't believe there should be any issues with doing this. This matches
how clients can call `Connection::flush` wherever they wish.
  • Loading branch information
ids1024 authored and elinorbgr committed Jul 14, 2023
1 parent be86c69 commit 9383041
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 27 deletions.
2 changes: 2 additions & 0 deletions wayland-backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Add `flush` method to server `Handle`.

## 0.2.0 -- 2023-07-13

#### Breaking changes
Expand Down
9 changes: 9 additions & 0 deletions wayland-backend/src/rs/server_impl/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ impl InnerHandle {
.expect("Wrong type parameter passed to Handle::get_global_handler().");
state.registry.get_handler(id)
}

pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
self.state.lock().unwrap().flush(client)
}
}

pub(crate) trait ErasedState: downcast_rs::Downcast {
Expand Down Expand Up @@ -291,6 +295,7 @@ pub(crate) trait ErasedState: downcast_rs::Downcast {
fn post_error(&mut self, object_id: InnerObjectId, error_code: u32, message: CString);
fn kill_client(&mut self, client_id: InnerClientId, reason: DisconnectReason);
fn global_info(&self, id: InnerGlobalId) -> Result<GlobalInfo, InvalidId>;
fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()>;
}

downcast_rs::impl_downcast!(ErasedState);
Expand Down Expand Up @@ -426,4 +431,8 @@ impl<D> ErasedState for State<D> {
fn global_info(&self, id: InnerGlobalId) -> Result<GlobalInfo, InvalidId> {
self.registry.get_info(id)
}

fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
self.flush(client)
}
}
7 changes: 7 additions & 0 deletions wayland-backend/src/server_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,13 @@ impl Handle {
) -> Result<Arc<dyn GlobalHandler<D>>, InvalidId> {
self.handle.get_global_handler(id.id)
}

/// Flushes pending events destined for a client.
///
/// If no client is specified, all pending events are flushed to all clients.
pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
self.handle.flush(client)
}
}

/// A backend object that represents the state of a wayland server.
Expand Down
62 changes: 35 additions & 27 deletions wayland-backend/src/sys/server_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,33 +374,7 @@ impl<D> InnerBackend<D> {
}

pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
let mut state = self.state.lock().unwrap();
if let Some(ClientId { id: client_id }) = client {
if client_id.alive.load(Ordering::Acquire) {
unsafe { ffi_dispatch!(wayland_server_handle(), wl_client_flush, client_id.ptr) }
}
} else {
// wl_display_flush_clients might invoke destructors
PENDING_DESTRUCTORS.set(
&(&mut state.pending_destructors as *mut _ as *mut _),
|| unsafe {
ffi_dispatch!(wayland_server_handle(), wl_display_flush_clients, state.display);
},
);
}
if !state.pending_destructors.is_empty() {
// Arm the timer to trigger a wakeup of the inner event loop in 1ms, so that the user
// is indicated to call dispatch_clients() and have the destructors run
unsafe {
ffi_dispatch!(
wayland_server_handle(),
wl_event_source_timer_update,
state.timer_source,
1
)
};
}
Ok(())
self.state.lock().unwrap().flush(client)
}

pub fn handle(&self) -> Handle {
Expand Down Expand Up @@ -838,6 +812,10 @@ impl InnerHandle {
Ok(udata.handler.clone())
}

pub fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
self.state.lock().unwrap().flush(client)
}

pub fn display_ptr(&self) -> *mut wl_display {
self.state.lock().unwrap().display_ptr()
}
Expand Down Expand Up @@ -874,6 +852,7 @@ pub(crate) trait ErasedState: downcast_rs::Downcast {
fn kill_client(&mut self, client_id: InnerClientId, reason: DisconnectReason);
fn global_info(&self, id: InnerGlobalId) -> Result<GlobalInfo, InvalidId>;
fn is_known_global(&self, global_ptr: *const wl_global) -> bool;
fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()>;
fn display_ptr(&self) -> *mut wl_display;
}

Expand Down Expand Up @@ -1249,6 +1228,35 @@ impl<D: 'static> ErasedState for State<D> {
self.known_globals.iter().any(|ginfo| (ginfo.ptr as *const wl_global) == global_ptr)
}

fn flush(&mut self, client: Option<ClientId>) -> std::io::Result<()> {
if let Some(ClientId { id: client_id }) = client {
if client_id.alive.load(Ordering::Acquire) {
unsafe { ffi_dispatch!(wayland_server_handle(), wl_client_flush, client_id.ptr) }
}
} else {
// wl_display_flush_clients might invoke destructors
PENDING_DESTRUCTORS.set(
&(&mut self.pending_destructors as *mut _ as *mut _),
|| unsafe {
ffi_dispatch!(wayland_server_handle(), wl_display_flush_clients, self.display);
},
);
}
if !self.pending_destructors.is_empty() {
// Arm the timer to trigger a wakeup of the inner event loop in 1ms, so that the user
// is indicated to call dispatch_clients() and have the destructors run
unsafe {
ffi_dispatch!(
wayland_server_handle(),
wl_event_source_timer_update,
self.timer_source,
1
)
};
}
Ok(())
}

fn display_ptr(&self) -> *mut wl_display {
self.display
}
Expand Down
2 changes: 2 additions & 0 deletions wayland-server/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Add `flush_clients` method to server `DisplayHandle`.

#### Breaking changes

- Bump bitflags to 2.0
Expand Down
5 changes: 5 additions & 0 deletions wayland-server/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ impl DisplayHandle {
) -> Result<Arc<dyn std::any::Any + Send + Sync + 'static>, InvalidId> {
self.handle.get_object_data_any(id)
}

/// Flush outgoing buffers into their respective sockets.
pub fn flush_clients(&mut self) -> std::io::Result<()> {
self.handle.flush(None)
}
}

impl From<Handle> for DisplayHandle {
Expand Down

0 comments on commit 9383041

Please sign in to comment.