aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dbus/mutter_screen_cast.rs42
-rw-r--r--src/niri.rs166
-rw-r--r--src/pw_utils.rs8
3 files changed, 99 insertions, 117 deletions
diff --git a/src/dbus/mutter_screen_cast.rs b/src/dbus/mutter_screen_cast.rs
index a19535ae..d7918989 100644
--- a/src/dbus/mutter_screen_cast.rs
+++ b/src/dbus/mutter_screen_cast.rs
@@ -62,6 +62,8 @@ static STREAM_ID: AtomicUsize = AtomicUsize::new(0);
#[derive(Clone)]
pub struct Stream {
+ id: usize,
+ session_id: usize,
target: StreamTarget,
cursor_mode: CursorMode,
was_started: Arc<AtomicBool>,
@@ -93,6 +95,7 @@ struct StreamParameters {
pub enum ScreenCastToNiri {
StartCast {
session_id: usize,
+ stream_id: usize,
target: StreamTargetId,
cursor_mode: CursorMode,
signal_ctx: SignalEmitter<'static>,
@@ -149,7 +152,7 @@ impl Session {
debug!("start");
for (stream, iface) in &*self.streams.lock().unwrap() {
- stream.start(self.id, iface.signal_emitter().clone());
+ stream.start(iface.signal_emitter().clone());
}
}
@@ -204,16 +207,20 @@ impl Session {
return Err(fdo::Error::Failed("monitor is disabled".to_owned()));
}
- let path = format!(
- "/org/gnome/Mutter/ScreenCast/Stream/u{}",
- STREAM_ID.fetch_add(1, Ordering::SeqCst)
- );
+ let stream_id = STREAM_ID.fetch_add(1, Ordering::SeqCst);
+ let path = format!("/org/gnome/Mutter/ScreenCast/Stream/u{stream_id}");
let path = OwnedObjectPath::try_from(path).unwrap();
let cursor_mode = properties.cursor_mode.unwrap_or_default();
let target = StreamTarget::Output(output);
- let stream = Stream::new(target, cursor_mode, self.to_niri.clone());
+ let stream = Stream::new(
+ stream_id,
+ self.id,
+ target,
+ cursor_mode,
+ self.to_niri.clone(),
+ );
match server.at(&path, stream.clone()).await {
Ok(true) => {
let iface = server.interface(&path).await.unwrap();
@@ -237,10 +244,8 @@ impl Session {
) -> fdo::Result<OwnedObjectPath> {
debug!(?properties, "record_window");
- let path = format!(
- "/org/gnome/Mutter/ScreenCast/Stream/u{}",
- STREAM_ID.fetch_add(1, Ordering::SeqCst)
- );
+ let stream_id = STREAM_ID.fetch_add(1, Ordering::SeqCst);
+ let path = format!("/org/gnome/Mutter/ScreenCast/Stream/u{stream_id}");
let path = OwnedObjectPath::try_from(path).unwrap();
let cursor_mode = properties.cursor_mode.unwrap_or_default();
@@ -248,7 +253,13 @@ impl Session {
let target = StreamTarget::Window {
id: properties.window_id,
};
- let stream = Stream::new(target, cursor_mode, self.to_niri.clone());
+ let stream = Stream::new(
+ stream_id,
+ self.id,
+ target,
+ cursor_mode,
+ self.to_niri.clone(),
+ );
match server.at(&path, stream.clone()).await {
Ok(true) => {
let iface = server.interface(&path).await.unwrap();
@@ -350,11 +361,15 @@ impl Drop for Session {
impl Stream {
fn new(
+ id: usize,
+ session_id: usize,
target: StreamTarget,
cursor_mode: CursorMode,
to_niri: calloop::channel::Sender<ScreenCastToNiri>,
) -> Self {
Self {
+ id,
+ session_id,
target,
cursor_mode,
was_started: Arc::new(AtomicBool::new(false)),
@@ -362,13 +377,14 @@ impl Stream {
}
}
- fn start(&self, session_id: usize, ctxt: SignalEmitter<'static>) {
+ fn start(&self, ctxt: SignalEmitter<'static>) {
if self.was_started.load(Ordering::SeqCst) {
return;
}
let msg = ScreenCastToNiri::StartCast {
- session_id,
+ session_id: self.session_id,
+ stream_id: self.id,
target: self.target.make_id(),
cursor_mode: self.cursor_mode,
signal_ctx: ctxt,
diff --git a/src/niri.rs b/src/niri.rs
index b7829d0e..a045e4dd 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -1592,20 +1592,7 @@ impl State {
pub fn on_pw_msg(&mut self, msg: PwToNiri) {
match msg {
PwToNiri::StopCast { session_id } => self.niri.stop_cast(session_id),
- PwToNiri::Redraw(target) => match target {
- CastTarget::Output(weak) => {
- if let Some(output) = weak.upgrade() {
- self.niri.queue_redraw(&output);
- }
- }
- CastTarget::Window { id } => {
- self.backend.with_primary_renderer(|renderer| {
- // FIXME: target presentation time at the time of window commit?
- self.niri
- .render_window_for_screen_cast(renderer, id, get_monotonic_time());
- });
- }
- },
+ PwToNiri::Redraw { stream_id } => self.redraw_cast(stream_id),
PwToNiri::FatalError => {
warn!("stopping PipeWire due to fatal error");
if let Some(pw) = self.niri.pipewire.take() {
@@ -1620,6 +1607,67 @@ impl State {
}
#[cfg(feature = "xdp-gnome-screencast")]
+ fn redraw_cast(&mut self, stream_id: usize) {
+ let _span = tracy_client::span!("State::redraw_cast");
+
+ let casts = &mut self.niri.casts;
+ let Some(cast) = casts.iter_mut().find(|cast| cast.stream_id == stream_id) else {
+ warn!("cast to redraw is missing");
+ return;
+ };
+
+ match &cast.target {
+ CastTarget::Output(weak) => {
+ if let Some(output) = weak.upgrade() {
+ self.niri.queue_redraw(&output);
+ }
+ }
+ CastTarget::Window { id } => {
+ let mut windows = self.niri.layout.windows();
+ let Some((_, mapped)) = windows.find(|(_, mapped)| mapped.id().get() == *id) else {
+ return;
+ };
+
+ // Use the cached output since it will be present even if the output was
+ // currently disconnected.
+ let Some(output) = self.niri.mapped_cast_output.get(&mapped.window) else {
+ return;
+ };
+
+ let scale = Scale::from(output.current_scale().fractional_scale());
+ let bbox = mapped
+ .window
+ .bbox_with_popups()
+ .to_physical_precise_up(scale);
+
+ match cast.ensure_size(bbox.size) {
+ Ok(CastSizeChange::Ready) => (),
+ Ok(CastSizeChange::Pending) => return,
+ Err(err) => {
+ warn!("error updating stream size, stopping screencast: {err:?}");
+ drop(windows);
+ let session_id = cast.session_id;
+ self.niri.stop_cast(session_id);
+ return;
+ }
+ }
+
+ self.backend.with_primary_renderer(|renderer| {
+ // FIXME: pointer.
+ let elements = mapped
+ .render_for_screen_cast(renderer, scale)
+ .rev()
+ .collect::<Vec<_>>();
+
+ if cast.dequeue_buffer_and_render(renderer, &elements, bbox.size, scale) {
+ cast.last_frame_time = get_monotonic_time();
+ }
+ });
+ }
+ }
+ }
+
+ #[cfg(feature = "xdp-gnome-screencast")]
pub fn on_screen_cast_msg(&mut self, msg: ScreenCastToNiri) {
use smithay::reexports::gbm::Modifier;
@@ -1628,13 +1676,14 @@ impl State {
match msg {
ScreenCastToNiri::StartCast {
session_id,
+ stream_id,
target,
cursor_mode,
signal_ctx,
} => {
let _span = tracy_client::span!("StartCast");
- debug!(session_id, "StartCast");
+ debug!(session_id, stream_id, "StartCast");
let Some(gbm) = self.backend.gbm_device() else {
warn!("error starting screencast: no GBM device available");
@@ -1726,6 +1775,7 @@ impl State {
gbm,
render_formats,
session_id,
+ stream_id,
target,
size,
refresh,
@@ -4336,92 +4386,6 @@ impl Niri {
}
}
- #[cfg(feature = "xdp-gnome-screencast")]
- fn render_window_for_screen_cast(
- &mut self,
- renderer: &mut GlesRenderer,
- window_id: u64,
- target_presentation_time: Duration,
- ) {
- let _span = tracy_client::span!("Niri::render_window_for_screen_cast");
-
- let mut window = None;
- self.layout.with_windows(|mapped, _, _| {
- if mapped.id().get() != window_id {
- return;
- }
-
- window = Some(mapped.window.clone());
- });
-
- let Some(window) = window else {
- return;
- };
-
- // Use the cached output since it will be present even if the output was
- // currently disconnected.
- let Some(output) = self.mapped_cast_output.get(&window) else {
- return;
- };
-
- let mut windows = self.layout.windows_for_output(output);
- let mapped = windows
- .find(|mapped| mapped.id().get() == window_id)
- .unwrap();
-
- let scale = Scale::from(output.current_scale().fractional_scale());
- let bbox = mapped
- .window
- .bbox_with_popups()
- .to_physical_precise_up(scale);
-
- let mut elements = None;
- let mut casts_to_stop = vec![];
-
- let mut casts = mem::take(&mut self.casts);
- for cast in &mut casts {
- if !cast.is_active.get() {
- continue;
- }
-
- if cast.target != (CastTarget::Window { id: window_id }) {
- continue;
- }
-
- match cast.ensure_size(bbox.size) {
- Ok(CastSizeChange::Ready) => (),
- Ok(CastSizeChange::Pending) => continue,
- Err(err) => {
- warn!("error updating stream size, stopping screencast: {err:?}");
- casts_to_stop.push(cast.session_id);
- }
- }
-
- if cast.check_time_and_schedule(&self.event_loop, output, target_presentation_time) {
- continue;
- }
-
- let elements = elements.get_or_insert_with(|| {
- // FIXME: pointer.
- mapped
- .render_for_screen_cast(renderer, scale)
- .rev()
- .collect::<Vec<_>>()
- });
-
- if cast.dequeue_buffer_and_render(renderer, elements, bbox.size, scale) {
- cast.last_frame_time = target_presentation_time;
- }
- }
- self.casts = casts;
-
- drop(windows);
-
- for id in casts_to_stop {
- self.stop_cast(id);
- }
- }
-
pub fn render_for_screencopy_with_damage(
&mut self,
renderer: &mut GlesRenderer,
diff --git a/src/pw_utils.rs b/src/pw_utils.rs
index 7cc3a88e..5cc16d85 100644
--- a/src/pw_utils.rs
+++ b/src/pw_utils.rs
@@ -60,12 +60,13 @@ pub struct PipeWire {
pub enum PwToNiri {
StopCast { session_id: usize },
- Redraw(CastTarget),
+ Redraw { stream_id: usize },
FatalError,
}
pub struct Cast {
pub session_id: usize,
+ pub stream_id: usize,
pub stream: Stream,
_listener: StreamListener<()>,
pub is_active: Rc<Cell<bool>>,
@@ -189,6 +190,7 @@ impl PipeWire {
gbm: GbmDevice<DrmDeviceFd>,
formats: FormatSet,
session_id: usize,
+ stream_id: usize,
target: CastTarget,
size: Size<i32, Physical>,
refresh: u32,
@@ -204,10 +206,9 @@ impl PipeWire {
warn!("error sending StopCast to niri: {err:?}");
}
};
- let target_ = target.clone();
let to_niri_ = self.to_niri.clone();
let redraw = move || {
- if let Err(err) = to_niri_.send(PwToNiri::Redraw(target_.clone())) {
+ if let Err(err) = to_niri_.send(PwToNiri::Redraw { stream_id }) {
warn!("error sending Redraw to niri: {err:?}");
}
};
@@ -651,6 +652,7 @@ impl PipeWire {
let cast = Cast {
session_id,
+ stream_id,
stream,
_listener: listener,
is_active,