diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs index 6041181f..8eba86e6 100644 --- a/niri-ipc/src/lib.rs +++ b/niri-ipc/src/lib.rs @@ -1505,6 +1505,10 @@ pub struct Cast { /// This can be `false` for example when switching away to a different scene in OBS, which /// pauses the stream. pub is_active: bool, + /// Process ID of the screencast consumer, if known. + /// + /// Currently, only wlr-screencopy screencasts can have a pid. + pub pid: Option, } /// Kind of screencast. diff --git a/src/ipc/client.rs b/src/ipc/client.rs index 22bf15cf..923cfd0a 100644 --- a/src/ipc/client.rs +++ b/src/ipc/client.rs @@ -764,6 +764,10 @@ fn print_cast(cast: &Cast) { if cast.is_dynamic_target { println!(" Dynamic cast target"); } + + if let Some(pid) = cast.pid { + println!(" PID: {pid}"); + } } fn fmt_rounded(x: f64) -> String { diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 662287e0..ee7d9e02 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -829,6 +829,7 @@ impl State { target: niri_ipc::CastTarget::Nothing {}, is_dynamic_target: true, is_active: false, + pid: None, }; events.push(Event::CastStartedOrChanged { cast }); } @@ -850,6 +851,7 @@ impl State { target: cast.target.make_ipc(), is_dynamic_target: cast.dynamic_target, is_active: cast.is_active(), + pid: None, }; events.push(Event::CastStartedOrChanged { cast }); } @@ -883,6 +885,7 @@ impl State { }, is_dynamic_target: false, is_active: true, + pid: queue.credentials().map(|creds| creds.pid), }; events.push(Event::CastStartedOrChanged { cast }); } diff --git a/src/protocols/screencopy.rs b/src/protocols/screencopy.rs index 5560b8fc..ccb550d6 100644 --- a/src/protocols/screencopy.rs +++ b/src/protocols/screencopy.rs @@ -20,10 +20,11 @@ use smithay::reexports::wayland_server::{ }; use smithay::utils::{Physical, Point, Rectangle, Size, Transform}; use smithay::wayland::{dmabuf, shm}; +use wayland_backend::server::Credentials; use zwlr_screencopy_frame_v1::{Flags, ZwlrScreencopyFrameV1}; use zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1; -use crate::utils::{get_monotonic_time, CastSessionId, CastStreamId}; +use crate::utils::{get_credentials_for_client, get_monotonic_time, CastSessionId, CastStreamId}; const VERSION: u32 = 3; @@ -35,6 +36,8 @@ const VERSION: u32 = 3; const CAST_TIMEOUT: Duration = Duration::from_secs(10); pub struct ScreencopyQueue { + /// Credentials of this wlr-screencopy client, if known. + credentials: Option, damage_tracker: OutputDamageTracker, /// Frames waiting for the client to call copy or destroy. pending_frames: HashSet, @@ -83,19 +86,14 @@ impl ScreencopyCast { } } -impl Default for ScreencopyQueue { - fn default() -> Self { - Self::new() - } -} - impl ScreencopyQueue { - pub fn new() -> Self { + pub fn new(credentials: Option) -> Self { Self { damage_tracker: OutputDamageTracker::new((0, 0), 1.0, Transform::Normal), pending_frames: HashSet::new(), screencopies: Vec::new(), cast: None, + credentials, } } @@ -108,6 +106,10 @@ impl ScreencopyQueue { self.cast.as_ref() } + pub fn credentials(&self) -> Option { + self.credentials + } + pub fn split(&mut self) -> (&mut OutputDamageTracker, Option<&Screencopy>) { let ScreencopyQueue { damage_tracker, @@ -287,8 +289,8 @@ where { fn bind( state: &mut D, - _display: &DisplayHandle, - _client: &Client, + dh: &DisplayHandle, + client: &Client, manager: New, _manager_state: &ScreencopyManagerGlobalData, data_init: &mut DataInit<'_, D>, @@ -296,7 +298,9 @@ where let manager = data_init.init(manager, ()); let state = state.screencopy_state(); - state.queues.insert(manager.clone(), ScreencopyQueue::new()); + let credentials = get_credentials_for_client(dh, client); + let queue = ScreencopyQueue::new(credentials); + state.queues.insert(manager.clone(), queue); } fn can_view(client: Client, global_data: &ScreencopyManagerGlobalData) -> bool { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d15628ce..659c3823 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -21,7 +21,7 @@ use smithay::reexports::rustix::time::{clock_gettime, ClockId}; use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; -use smithay::reexports::wayland_server::{DisplayHandle, Resource as _}; +use smithay::reexports::wayland_server::{Client, DisplayHandle, Resource as _}; use smithay::utils::{Coordinate, Logical, Point, Rectangle, Size, Transform}; use smithay::wayland::compositor::{send_surface_state, with_states, SurfaceData}; use smithay::wayland::fractional_scale::with_fractional_scale; @@ -457,12 +457,16 @@ pub fn get_credentials_for_surface(surface: &WlSurface) -> Option { let dh = DisplayHandle::from(handle); let client = dh.get_client(surface.id()).ok()?; + get_credentials_for_client(&dh, &client) +} + +pub fn get_credentials_for_client(dh: &DisplayHandle, client: &Client) -> Option { let data = client.get_data::().unwrap(); if data.credentials_unknown { return None; } - client.get_credentials(&dh).ok() + client.get_credentials(dh).ok() } pub fn ensure_min_max_size(mut x: i32, min_size: i32, max_size: i32) -> i32 {