mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
Store cast Stream ID, use it for Redraw request
Unlike StopCast, Redraw targets a specific Cast. Use the stream ID to identify it.
This commit is contained in:
@@ -62,6 +62,8 @@ static STREAM_ID: AtomicUsize = AtomicUsize::new(0);
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Stream {
|
pub struct Stream {
|
||||||
|
id: usize,
|
||||||
|
session_id: usize,
|
||||||
target: StreamTarget,
|
target: StreamTarget,
|
||||||
cursor_mode: CursorMode,
|
cursor_mode: CursorMode,
|
||||||
was_started: Arc<AtomicBool>,
|
was_started: Arc<AtomicBool>,
|
||||||
@@ -93,6 +95,7 @@ struct StreamParameters {
|
|||||||
pub enum ScreenCastToNiri {
|
pub enum ScreenCastToNiri {
|
||||||
StartCast {
|
StartCast {
|
||||||
session_id: usize,
|
session_id: usize,
|
||||||
|
stream_id: usize,
|
||||||
target: StreamTargetId,
|
target: StreamTargetId,
|
||||||
cursor_mode: CursorMode,
|
cursor_mode: CursorMode,
|
||||||
signal_ctx: SignalEmitter<'static>,
|
signal_ctx: SignalEmitter<'static>,
|
||||||
@@ -149,7 +152,7 @@ impl Session {
|
|||||||
debug!("start");
|
debug!("start");
|
||||||
|
|
||||||
for (stream, iface) in &*self.streams.lock().unwrap() {
|
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()));
|
return Err(fdo::Error::Failed("monitor is disabled".to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = format!(
|
let stream_id = STREAM_ID.fetch_add(1, Ordering::SeqCst);
|
||||||
"/org/gnome/Mutter/ScreenCast/Stream/u{}",
|
let path = format!("/org/gnome/Mutter/ScreenCast/Stream/u{stream_id}");
|
||||||
STREAM_ID.fetch_add(1, Ordering::SeqCst)
|
|
||||||
);
|
|
||||||
let path = OwnedObjectPath::try_from(path).unwrap();
|
let path = OwnedObjectPath::try_from(path).unwrap();
|
||||||
|
|
||||||
let cursor_mode = properties.cursor_mode.unwrap_or_default();
|
let cursor_mode = properties.cursor_mode.unwrap_or_default();
|
||||||
|
|
||||||
let target = StreamTarget::Output(output);
|
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 {
|
match server.at(&path, stream.clone()).await {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
let iface = server.interface(&path).await.unwrap();
|
let iface = server.interface(&path).await.unwrap();
|
||||||
@@ -237,10 +244,8 @@ impl Session {
|
|||||||
) -> fdo::Result<OwnedObjectPath> {
|
) -> fdo::Result<OwnedObjectPath> {
|
||||||
debug!(?properties, "record_window");
|
debug!(?properties, "record_window");
|
||||||
|
|
||||||
let path = format!(
|
let stream_id = STREAM_ID.fetch_add(1, Ordering::SeqCst);
|
||||||
"/org/gnome/Mutter/ScreenCast/Stream/u{}",
|
let path = format!("/org/gnome/Mutter/ScreenCast/Stream/u{stream_id}");
|
||||||
STREAM_ID.fetch_add(1, Ordering::SeqCst)
|
|
||||||
);
|
|
||||||
let path = OwnedObjectPath::try_from(path).unwrap();
|
let path = OwnedObjectPath::try_from(path).unwrap();
|
||||||
|
|
||||||
let cursor_mode = properties.cursor_mode.unwrap_or_default();
|
let cursor_mode = properties.cursor_mode.unwrap_or_default();
|
||||||
@@ -248,7 +253,13 @@ impl Session {
|
|||||||
let target = StreamTarget::Window {
|
let target = StreamTarget::Window {
|
||||||
id: properties.window_id,
|
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 {
|
match server.at(&path, stream.clone()).await {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
let iface = server.interface(&path).await.unwrap();
|
let iface = server.interface(&path).await.unwrap();
|
||||||
@@ -350,11 +361,15 @@ impl Drop for Session {
|
|||||||
|
|
||||||
impl Stream {
|
impl Stream {
|
||||||
fn new(
|
fn new(
|
||||||
|
id: usize,
|
||||||
|
session_id: usize,
|
||||||
target: StreamTarget,
|
target: StreamTarget,
|
||||||
cursor_mode: CursorMode,
|
cursor_mode: CursorMode,
|
||||||
to_niri: calloop::channel::Sender<ScreenCastToNiri>,
|
to_niri: calloop::channel::Sender<ScreenCastToNiri>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
id,
|
||||||
|
session_id,
|
||||||
target,
|
target,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
was_started: Arc::new(AtomicBool::new(false)),
|
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) {
|
if self.was_started.load(Ordering::SeqCst) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = ScreenCastToNiri::StartCast {
|
let msg = ScreenCastToNiri::StartCast {
|
||||||
session_id,
|
session_id: self.session_id,
|
||||||
|
stream_id: self.id,
|
||||||
target: self.target.make_id(),
|
target: self.target.make_id(),
|
||||||
cursor_mode: self.cursor_mode,
|
cursor_mode: self.cursor_mode,
|
||||||
signal_ctx: ctxt,
|
signal_ctx: ctxt,
|
||||||
|
|||||||
+65
-101
@@ -1592,20 +1592,7 @@ impl State {
|
|||||||
pub fn on_pw_msg(&mut self, msg: PwToNiri) {
|
pub fn on_pw_msg(&mut self, msg: PwToNiri) {
|
||||||
match msg {
|
match msg {
|
||||||
PwToNiri::StopCast { session_id } => self.niri.stop_cast(session_id),
|
PwToNiri::StopCast { session_id } => self.niri.stop_cast(session_id),
|
||||||
PwToNiri::Redraw(target) => match target {
|
PwToNiri::Redraw { stream_id } => self.redraw_cast(stream_id),
|
||||||
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::FatalError => {
|
PwToNiri::FatalError => {
|
||||||
warn!("stopping PipeWire due to fatal error");
|
warn!("stopping PipeWire due to fatal error");
|
||||||
if let Some(pw) = self.niri.pipewire.take() {
|
if let Some(pw) = self.niri.pipewire.take() {
|
||||||
@@ -1619,6 +1606,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")]
|
#[cfg(feature = "xdp-gnome-screencast")]
|
||||||
pub fn on_screen_cast_msg(&mut self, msg: ScreenCastToNiri) {
|
pub fn on_screen_cast_msg(&mut self, msg: ScreenCastToNiri) {
|
||||||
use smithay::reexports::gbm::Modifier;
|
use smithay::reexports::gbm::Modifier;
|
||||||
@@ -1628,13 +1676,14 @@ impl State {
|
|||||||
match msg {
|
match msg {
|
||||||
ScreenCastToNiri::StartCast {
|
ScreenCastToNiri::StartCast {
|
||||||
session_id,
|
session_id,
|
||||||
|
stream_id,
|
||||||
target,
|
target,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
signal_ctx,
|
signal_ctx,
|
||||||
} => {
|
} => {
|
||||||
let _span = tracy_client::span!("StartCast");
|
let _span = tracy_client::span!("StartCast");
|
||||||
|
|
||||||
debug!(session_id, "StartCast");
|
debug!(session_id, stream_id, "StartCast");
|
||||||
|
|
||||||
let Some(gbm) = self.backend.gbm_device() else {
|
let Some(gbm) = self.backend.gbm_device() else {
|
||||||
warn!("error starting screencast: no GBM device available");
|
warn!("error starting screencast: no GBM device available");
|
||||||
@@ -1726,6 +1775,7 @@ impl State {
|
|||||||
gbm,
|
gbm,
|
||||||
render_formats,
|
render_formats,
|
||||||
session_id,
|
session_id,
|
||||||
|
stream_id,
|
||||||
target,
|
target,
|
||||||
size,
|
size,
|
||||||
refresh,
|
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(
|
pub fn render_for_screencopy_with_damage(
|
||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut GlesRenderer,
|
renderer: &mut GlesRenderer,
|
||||||
|
|||||||
+5
-3
@@ -60,12 +60,13 @@ pub struct PipeWire {
|
|||||||
|
|
||||||
pub enum PwToNiri {
|
pub enum PwToNiri {
|
||||||
StopCast { session_id: usize },
|
StopCast { session_id: usize },
|
||||||
Redraw(CastTarget),
|
Redraw { stream_id: usize },
|
||||||
FatalError,
|
FatalError,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Cast {
|
pub struct Cast {
|
||||||
pub session_id: usize,
|
pub session_id: usize,
|
||||||
|
pub stream_id: usize,
|
||||||
pub stream: Stream,
|
pub stream: Stream,
|
||||||
_listener: StreamListener<()>,
|
_listener: StreamListener<()>,
|
||||||
pub is_active: Rc<Cell<bool>>,
|
pub is_active: Rc<Cell<bool>>,
|
||||||
@@ -189,6 +190,7 @@ impl PipeWire {
|
|||||||
gbm: GbmDevice<DrmDeviceFd>,
|
gbm: GbmDevice<DrmDeviceFd>,
|
||||||
formats: FormatSet,
|
formats: FormatSet,
|
||||||
session_id: usize,
|
session_id: usize,
|
||||||
|
stream_id: usize,
|
||||||
target: CastTarget,
|
target: CastTarget,
|
||||||
size: Size<i32, Physical>,
|
size: Size<i32, Physical>,
|
||||||
refresh: u32,
|
refresh: u32,
|
||||||
@@ -204,10 +206,9 @@ impl PipeWire {
|
|||||||
warn!("error sending StopCast to niri: {err:?}");
|
warn!("error sending StopCast to niri: {err:?}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let target_ = target.clone();
|
|
||||||
let to_niri_ = self.to_niri.clone();
|
let to_niri_ = self.to_niri.clone();
|
||||||
let redraw = move || {
|
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:?}");
|
warn!("error sending Redraw to niri: {err:?}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -651,6 +652,7 @@ impl PipeWire {
|
|||||||
|
|
||||||
let cast = Cast {
|
let cast = Cast {
|
||||||
session_id,
|
session_id,
|
||||||
|
stream_id,
|
||||||
stream,
|
stream,
|
||||||
_listener: listener,
|
_listener: listener,
|
||||||
is_active,
|
is_active,
|
||||||
|
|||||||
Reference in New Issue
Block a user