diff --git a/Cargo.lock b/Cargo.lock index ff0eb732b..ba0534dfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -803,7 +803,7 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.1.0" -source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#1425bd44ed2b318a552201cc752ae11f2f483ef5" +source = "git+https://github.com/pop-os//cosmic-protocols?branch=toplevel-info#f44f451088f2ea7e52665d956388663c40901b94" dependencies = [ "bitflags 2.9.1", "cosmic-protocols", @@ -929,7 +929,7 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.1.0" -source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#1425bd44ed2b318a552201cc752ae11f2f483ef5" +source = "git+https://github.com/pop-os//cosmic-protocols?branch=toplevel-info#f44f451088f2ea7e52665d956388663c40901b94" dependencies = [ "bitflags 2.9.1", "wayland-backend", diff --git a/Cargo.toml b/Cargo.toml index a364e3138..7a5e4604e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ xdg-user = "0.2.1" xkbcommon = "0.8" zbus = "5.7.1" profiling = { version = "1.0" } -rustix = { version = "0.38.32", features = ["process"] } +rustix = { version = "0.38.32", features = ["net", "process"] } smallvec = "1.13.2" rand = "0.9.0" reis = { version = "0.5", features = ["calloop"] } @@ -120,8 +120,10 @@ inherits = "release" lto = "fat" [patch."https://github.com/pop-os/cosmic-protocols"] -cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" } -cosmic-client-toolkit = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" } +# cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" } +# cosmic-client-toolkit = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" } +cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch = "toplevel-info" } +cosmic-client-toolkit = { git = "https://github.com/pop-os//cosmic-protocols", branch = "toplevel-info" } [patch.crates-io] smithay = { git = "https://github.com/smithay/smithay.git", rev = "776ba42" } diff --git a/src/backend/kms/socket.rs b/src/backend/kms/socket.rs index 88070161d..d2639f50b 100644 --- a/src/backend/kms/socket.rs +++ b/src/backend/kms/socket.rs @@ -82,13 +82,15 @@ impl State { .common .event_loop_handle .insert_source(listener, move |client_stream, _, state: &mut State| { - if let Err(err) = state.common.display_handle.insert_client( - client_stream, - Arc::new(ClientState { - advertised_drm_node: Some(render_node), - ..state.new_client_state() - }), - ) { + let client_state = ClientState { + advertised_drm_node: Some(render_node), + ..state.new_client_state(&client_stream) + }; + if let Err(err) = state + .common + .display_handle + .insert_client(client_stream, Arc::new(client_state)) + { warn!( socket_name = socket_name_clone, ?err, diff --git a/src/main.rs b/src/main.rs index 033ccd2a1..c2c369f95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -248,7 +248,7 @@ fn init_wayland_display( event_loop .handle() .insert_source(source, |client_stream, _, state| { - let client_state = state.new_client_state(); + let client_state = state.new_client_state(&client_stream); if let Err(err) = state .common .display_handle diff --git a/src/session.rs b/src/session.rs index 240e649b2..5fe59412c 100644 --- a/src/session.rs +++ b/src/session.rs @@ -147,7 +147,7 @@ pub fn setup_socket(handle: LoopHandle, common: &Common) -> Result<()> { let stream = unsafe { UnixStream::from_raw_fd(fd) }; let client_state = Arc::new(ClientState { privileged: true, - ..state.new_client_state() + ..state.new_client_state(&stream) }); if let Err(err) = state.common.display_handle.insert_client(stream, client_state) { warn!(?err, "Failed to add privileged client to display"); diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index 6b0bed11e..c19ef3d07 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -34,7 +34,7 @@ use smithay::{ }, }, wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::Mode as KdeMode, - wayland_server::protocol::wl_surface::WlSurface, + wayland_server::{protocol::wl_surface::WlSurface, Resource}, }, utils::{ user_data::UserDataMap, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, @@ -49,9 +49,10 @@ use smithay::{ use tracing::trace; use crate::{ - state::{State, SurfaceDmabufFeedback}, + state::{ClientState, State, SurfaceDmabufFeedback}, utils::prelude::*, wayland::handlers::decoration::{KdeDecorationData, PreferredDecorationMode}, + xwayland::X11SurfacePid, }; #[derive(Debug, Clone, PartialEq)] @@ -742,6 +743,16 @@ impl CosmicSurface { pub fn x11_surface(&self) -> Option<&X11Surface> { self.0.x11_surface() } + + pub fn pid(&self) -> Option { + match self.0.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + let surface = toplevel.wl_surface(); + surface.client()?.get_data::()?.pid + } + WindowSurface::X11(surface) => surface.user_data().get::().map(|x| x.0), + } + } } impl IsAlive for CosmicSurface { diff --git a/src/state.rs b/src/state.rs index 1a7de6fc4..75d91a6d2 100644 --- a/src/state.rs +++ b/src/state.rs @@ -117,6 +117,7 @@ use std::{ cmp::min, collections::HashSet, ffi::OsString, + os::unix::net::UnixStream, process::Child, sync::{atomic::AtomicBool, Arc, Mutex, Once}, time::{Duration, Instant}, @@ -145,6 +146,7 @@ pub struct ClientState { pub privileged: bool, pub evls: LoopSignal, pub security_context: Option, + pub pid: Option, } impl ClientData for ClientState { fn initialized(&self, _client_id: ClientId) {} @@ -667,7 +669,14 @@ impl State { } } - pub fn new_client_state(&self) -> ClientState { + pub fn new_client_state(&self, unix_stream: &UnixStream) -> ClientState { + let pid = match rustix::net::sockopt::get_socket_peercred(&unix_stream) { + Ok(cred) => Some(rustix::process::Pid::as_raw(Some(cred.pid)) as u32), + Err(err) => { + tracing::warn!(?err, "Failed to get PID for Wayland client"); + None + } + }; ClientState { compositor_client_state: CompositorClientState::default(), advertised_drm_node: match &self.backend { @@ -677,6 +686,7 @@ impl State { privileged: !enable_wayland_security(), evls: self.common.event_loop_signal.clone(), security_context: None, + pid, } } } diff --git a/src/wayland/handlers/security_context.rs b/src/wayland/handlers/security_context.rs index e564f1bf6..88c4abeda 100644 --- a/src/wayland/handlers/security_context.rs +++ b/src/wayland/handlers/security_context.rs @@ -32,7 +32,7 @@ impl SecurityContextHandler for State { .map(|data| data.privileged) .unwrap_or(false); - let new_state = state.new_client_state(); + let new_state = state.new_client_state(&client_stream); let drm_node = client_data .as_ref() diff --git a/src/wayland/handlers/toplevel_info.rs b/src/wayland/handlers/toplevel_info.rs index 37033f4fc..dee391cc4 100644 --- a/src/wayland/handlers/toplevel_info.rs +++ b/src/wayland/handlers/toplevel_info.rs @@ -59,6 +59,10 @@ impl Window for CosmicSurface { CosmicSurface::global_geometry(self) } + fn pid(&self) -> Option { + CosmicSurface::pid(self) + } + fn user_data(&self) -> &UserDataMap { CosmicSurface::user_data(self) } diff --git a/src/wayland/protocols/toplevel_info.rs b/src/wayland/protocols/toplevel_info.rs index 9d55af3b1..fb5d2ff70 100644 --- a/src/wayland/protocols/toplevel_info.rs +++ b/src/wayland/protocols/toplevel_info.rs @@ -38,6 +38,7 @@ pub trait Window: IsAlive + Clone + PartialEq + Send { fn is_sticky(&self) -> bool; fn is_resizing(&self) -> bool; fn global_geometry(&self) -> Option>; + fn pid(&self) -> Option; fn user_data(&self) -> &UserDataMap; } @@ -312,7 +313,7 @@ where F: for<'a> Fn(&'a Client) -> bool + Send + Sync + Clone + 'static, { let global = dh.create_global::( - 3, + 4, ToplevelInfoGlobalData { filter: Box::new(client_filter.clone()), }, @@ -610,6 +611,12 @@ where } handle_state.workspaces = state.workspaces.clone(); + if instance.version() >= zcosmic_toplevel_handle_v1::EVT_PID_SINCE { + if let Some(pid) = window.pid() { + instance.pid(pid); + } + } + if changed { if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE { instance.done(); diff --git a/src/xwayland.rs b/src/xwayland.rs index 251020b5f..d7f94ca45 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -694,6 +694,8 @@ impl Common { } } +pub struct X11SurfacePid(pub u32); + impl XwmHandler for State { fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm { self.common @@ -703,7 +705,18 @@ impl XwmHandler for State { .unwrap() } - fn new_window(&mut self, _xwm: XwmId, _window: X11Surface) {} + fn new_window(&mut self, _xwm: XwmId, window: X11Surface) { + match window.get_client_pid() { + Ok(pid) => { + window + .user_data() + .insert_if_missing_threadsafe(|| X11SurfacePid(pid)); + } + Err(err) => { + warn!(?window, ?err, "Failed to get pid for XWayland window"); + } + }; + } fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {} fn destroyed_window(&mut self, _xwm: XwmId, _window: X11Surface) {}