diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-03-27 09:46:18 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-03-27 09:46:18 +0400 |
| commit | e276c906bf4bea27dc8173815ff373d04c20caaf (patch) | |
| tree | 6843e6ab8244f296b89d54d53b2ebfd6e1a16592 | |
| parent | 571768af433b0fdc653f44b7dee0ad2dda6fe344 (diff) | |
| download | niri-e276c906bf4bea27dc8173815ff373d04c20caaf.tar.gz niri-e276c906bf4bea27dc8173815ff373d04c20caaf.tar.bz2 niri-e276c906bf4bea27dc8173815ff373d04c20caaf.zip | |
Expose more info in DisplayConfig impl
Needed for the new xdp-gnome.
| -rw-r--r-- | src/backend/mod.rs | 12 | ||||
| -rw-r--r-- | src/backend/tty.rs | 49 | ||||
| -rw-r--r-- | src/backend/winit.rs | 47 | ||||
| -rw-r--r-- | src/dbus/mod.rs | 4 | ||||
| -rw-r--r-- | src/dbus/mutter_display_config.rs | 102 | ||||
| -rw-r--r-- | src/dbus/mutter_screen_cast.rs | 22 | ||||
| -rw-r--r-- | src/ipc/server.rs | 10 | ||||
| -rw-r--r-- | src/niri.rs | 18 |
8 files changed, 153 insertions, 111 deletions
diff --git a/src/backend/mod.rs b/src/backend/mod.rs index fe181714..786fdaaa 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -31,6 +31,8 @@ pub enum RenderResult { Skipped, } +pub type IpcOutputMap = HashMap<String, (niri_ipc::Output, Option<Output>)>; + impl Backend { pub fn init(&mut self, niri: &mut Niri) { match self { @@ -110,21 +112,13 @@ impl Backend { } } - pub fn ipc_outputs(&self) -> Arc<Mutex<HashMap<String, niri_ipc::Output>>> { + pub fn ipc_outputs(&self) -> Arc<Mutex<IpcOutputMap>> { match self { Backend::Tty(tty) => tty.ipc_outputs(), Backend::Winit(winit) => winit.ipc_outputs(), } } - #[cfg_attr(not(feature = "dbus"), allow(unused))] - pub fn enabled_outputs(&self) -> Arc<Mutex<HashMap<String, Output>>> { - match self { - Backend::Tty(tty) => tty.enabled_outputs(), - Backend::Winit(winit) => winit.enabled_outputs(), - } - } - #[cfg(feature = "xdp-gnome-screencast")] pub fn gbm_device( &self, diff --git a/src/backend/tty.rs b/src/backend/tty.rs index f9f4b19d..a90182a3 100644 --- a/src/backend/tty.rs +++ b/src/backend/tty.rs @@ -55,7 +55,7 @@ use smithay_drm_extras::edid::EdidInfo; use wayland_protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1::TrancheFlags; use wayland_protocols::wp::presentation_time::server::wp_presentation_feedback; -use super::RenderResult; +use super::{IpcOutputMap, RenderResult}; use crate::frame_clock::FrameClock; use crate::niri::{Niri, RedrawState, State}; use crate::render_helpers::renderer::AsGlesRenderer; @@ -84,8 +84,7 @@ pub struct Tty { update_output_config_on_resume: bool, // Whether the debug tinting is enabled. debug_tint: bool, - ipc_outputs: Arc<Mutex<HashMap<String, niri_ipc::Output>>>, - enabled_outputs: Arc<Mutex<HashMap<String, Output>>>, + ipc_outputs: Arc<Mutex<IpcOutputMap>>, } pub type TtyRenderer<'render> = MultiRenderer< @@ -293,7 +292,6 @@ impl Tty { update_output_config_on_resume: false, debug_tint: false, ipc_outputs: Arc::new(Mutex::new(HashMap::new())), - enabled_outputs: Arc::new(Mutex::new(HashMap::new())), }) } @@ -430,7 +428,7 @@ impl Tty { self.on_output_config_changed(niri); } - self.refresh_ipc_outputs(); + self.refresh_ipc_outputs(niri); niri.idle_notifier_state.notify_activity(&niri.seat); niri.monitors_active = true; @@ -580,7 +578,7 @@ impl Tty { } } - self.refresh_ipc_outputs(); + self.refresh_ipc_outputs(niri); } fn device_removed(&mut self, device_id: dev_t, niri: &mut Niri) { @@ -644,7 +642,7 @@ impl Tty { self.gpu_manager.as_mut().remove_node(&device.render_node); niri.event_loop.remove(device.token); - self.refresh_ipc_outputs(); + self.refresh_ipc_outputs(niri); } fn connector_connected( @@ -874,13 +872,6 @@ impl Tty { niri.add_output(output.clone(), Some(refresh_interval(mode))); - self.enabled_outputs - .lock() - .unwrap() - .insert(output_name, output.clone()); - #[cfg(feature = "dbus")] - niri.on_enabled_outputs_changed(); - // Power on all monitors if necessary and queue a redraw on the new one. niri.event_loop.insert_idle(move |state| { state.niri.activate_monitors(&mut state.backend); @@ -918,10 +909,6 @@ impl Tty { } else { error!("missing output for crtc {crtc:?}"); }; - - self.enabled_outputs.lock().unwrap().remove(&surface.name); - #[cfg(feature = "dbus")] - niri.on_enabled_outputs_changed(); } fn on_vblank( @@ -1341,12 +1328,12 @@ impl Tty { } } - fn refresh_ipc_outputs(&self) { + fn refresh_ipc_outputs(&self, niri: &mut Niri) { let _span = tracy_client::span!("Tty::refresh_ipc_outputs"); let mut ipc_outputs = HashMap::new(); - for device in self.devices.values() { + for (node, device) in &self.devices { for (connector, crtc) in device.drm_scanner.crtcs() { let connector_name = format!( "{}-{}", @@ -1397,7 +1384,16 @@ impl Tty { } } - let output = niri_ipc::Output { + let output = niri + .global_space + .outputs() + .find(|output| { + let tty_state: &TtyOutputState = output.user_data().get().unwrap(); + tty_state.node == *node && tty_state.crtc == crtc + }) + .cloned(); + + let ipc_output = niri_ipc::Output { name: connector_name.clone(), make, model, @@ -1406,22 +1402,19 @@ impl Tty { current_mode, }; - ipc_outputs.insert(connector_name, output); + ipc_outputs.insert(connector_name, (ipc_output, output)); } } let mut guard = self.ipc_outputs.lock().unwrap(); *guard = ipc_outputs; + niri.ipc_outputs_changed = true; } - pub fn ipc_outputs(&self) -> Arc<Mutex<HashMap<String, niri_ipc::Output>>> { + pub fn ipc_outputs(&self) -> Arc<Mutex<IpcOutputMap>> { self.ipc_outputs.clone() } - pub fn enabled_outputs(&self) -> Arc<Mutex<HashMap<String, Output>>> { - self.enabled_outputs.clone() - } - #[cfg(feature = "xdp-gnome-screencast")] pub fn primary_gbm_device(&self) -> Option<GbmDevice<DrmDeviceFd>> { self.devices.get(&self.primary_node).map(|d| d.gbm.clone()) @@ -1585,7 +1578,7 @@ impl Tty { } } - self.refresh_ipc_outputs(); + self.refresh_ipc_outputs(niri); } pub fn get_device_from_node(&mut self, node: DrmNode) -> Option<&mut OutputDevice> { diff --git a/src/backend/winit.rs b/src/backend/winit.rs index b2ab8c33..96c0cdf8 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -17,7 +17,7 @@ use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_pre use smithay::reexports::winit::dpi::LogicalSize; use smithay::reexports::winit::window::WindowBuilder; -use super::RenderResult; +use super::{IpcOutputMap, RenderResult}; use crate::niri::{Niri, RedrawState, State}; use crate::render_helpers::{shaders, RenderTarget}; use crate::utils::get_monotonic_time; @@ -27,8 +27,7 @@ pub struct Winit { output: Output, backend: WinitGraphicsBackend<GlesRenderer>, damage_tracker: OutputDamageTracker, - ipc_outputs: Arc<Mutex<HashMap<String, niri_ipc::Output>>>, - enabled_outputs: Arc<Mutex<HashMap<String, Output>>>, + ipc_outputs: Arc<Mutex<IpcOutputMap>>, } impl Winit { @@ -62,23 +61,21 @@ impl Winit { let physical_properties = output.physical_properties(); let ipc_outputs = Arc::new(Mutex::new(HashMap::from([( "winit".to_owned(), - niri_ipc::Output { - name: output.name(), - make: physical_properties.make, - model: physical_properties.model, - physical_size: None, - modes: vec![niri_ipc::Mode { - width: backend.window_size().w.clamp(0, u16::MAX as i32) as u16, - height: backend.window_size().h.clamp(0, u16::MAX as i32) as u16, - refresh_rate: 60_000, - }], - current_mode: Some(0), - }, - )]))); - - let enabled_outputs = Arc::new(Mutex::new(HashMap::from([( - "winit".to_owned(), - output.clone(), + ( + niri_ipc::Output { + name: output.name(), + make: physical_properties.make, + model: physical_properties.model, + physical_size: None, + modes: vec![niri_ipc::Mode { + width: backend.window_size().w.clamp(0, u16::MAX as i32) as u16, + height: backend.window_size().h.clamp(0, u16::MAX as i32) as u16, + refresh_rate: 60_000, + }], + current_mode: Some(0), + }, + Some(output.clone()), + ), )]))); let damage_tracker = OutputDamageTracker::from_output(&output); @@ -99,9 +96,10 @@ impl Winit { { let mut ipc_outputs = winit.ipc_outputs.lock().unwrap(); - let mode = &mut ipc_outputs.get_mut("winit").unwrap().modes[0]; + let mode = &mut ipc_outputs.get_mut("winit").unwrap().0.modes[0]; mode.width = size.w.clamp(0, u16::MAX as i32) as u16; mode.height = size.h.clamp(0, u16::MAX as i32) as u16; + state.niri.ipc_outputs_changed = true; } state.niri.output_resized(&winit.output); @@ -119,7 +117,6 @@ impl Winit { backend, damage_tracker, ipc_outputs, - enabled_outputs, }) } @@ -230,11 +227,7 @@ impl Winit { } } - pub fn ipc_outputs(&self) -> Arc<Mutex<HashMap<String, niri_ipc::Output>>> { + pub fn ipc_outputs(&self) -> Arc<Mutex<IpcOutputMap>> { self.ipc_outputs.clone() } - - pub fn enabled_outputs(&self) -> Arc<Mutex<HashMap<String, Output>>> { - self.enabled_outputs.clone() - } } diff --git a/src/dbus/mod.rs b/src/dbus/mod.rs index 6d8b81e6..7d63682d 100644 --- a/src/dbus/mod.rs +++ b/src/dbus/mod.rs @@ -47,7 +47,7 @@ impl DBusServers { } if is_session_instance || config.debug.dbus_interfaces_in_non_session_instances { - let display_config = DisplayConfig::new(backend.enabled_outputs()); + let display_config = DisplayConfig::new(backend.ipc_outputs()); dbus.conn_display_config = try_start(display_config); let screen_saver = ScreenSaver::new(niri.is_fdo_idle_inhibited.clone()); @@ -80,7 +80,7 @@ impl DBusServers { } }) .unwrap(); - let screen_cast = ScreenCast::new(backend.enabled_outputs(), to_niri); + let screen_cast = ScreenCast::new(backend.ipc_outputs(), to_niri); dbus.conn_screen_cast = try_start(screen_cast); } else { warn!("disabling screencast support because we couldn't start PipeWire"); diff --git a/src/dbus/mutter_display_config.rs b/src/dbus/mutter_display_config.rs index ea945653..2e29b923 100644 --- a/src/dbus/mutter_display_config.rs +++ b/src/dbus/mutter_display_config.rs @@ -2,15 +2,16 @@ use std::collections::HashMap; use std::sync::{Arc, Mutex}; use serde::Serialize; -use smithay::output::Output; +use smithay::utils::Transform; use zbus::fdo::RequestNameFlags; use zbus::zvariant::{self, OwnedValue, Type}; use zbus::{dbus_interface, fdo, SignalContext}; use super::Start; +use crate::backend::IpcOutputMap; pub struct DisplayConfig { - enabled_outputs: Arc<Mutex<HashMap<String, Output>>>, + ipc_outputs: Arc<Mutex<IpcOutputMap>>, } #[derive(Serialize, Type)] @@ -53,12 +54,17 @@ impl DisplayConfig { HashMap<String, OwnedValue>, )> { // Construct the DBus response. - let mut monitors: Vec<Monitor> = self - .enabled_outputs + let mut monitors: Vec<(Monitor, LogicalMonitor)> = self + .ipc_outputs .lock() .unwrap() - .keys() - .map(|c| { + .iter() + // Take only enabled outputs. + .filter_map(|(c, (ipc, output))| { + ipc.current_mode?; + output.as_ref().map(move |output| (c, (ipc, output))) + }) + .map(|(c, (ipc, output))| { // Loosely matches the check in Mutter. let is_laptop_panel = matches!(c.get(..4), Some("eDP-" | "LVDS" | "DSI-")); @@ -78,38 +84,78 @@ impl DisplayConfig { OwnedValue::from(is_laptop_panel), ); - Monitor { + let mut modes: Vec<Mode> = ipc + .modes + .iter() + .map(|m| { + let niri_ipc::Mode { + width, + height, + refresh_rate, + } = *m; + let refresh = refresh_rate as f64 / 1000.; + + Mode { + id: format!("{width}x{height}@{refresh:.3}"), + width: i32::from(width), + height: i32::from(height), + refresh_rate: refresh, + preferred_scale: 1., + supported_scales: vec![1., 2., 3.], + properties: HashMap::new(), + } + }) + .collect(); + modes[ipc.current_mode.unwrap()] + .properties + .insert(String::from("is-current"), OwnedValue::from(true)); + + let monitor = Monitor { names: (c.clone(), String::new(), String::new(), serial), - modes: vec![], + modes, properties, - } + }; + + let loc = output.current_location(); + + let transform = match output.current_transform() { + Transform::Normal => 0, + Transform::_90 => 1, + Transform::_180 => 2, + Transform::_270 => 3, + Transform::Flipped => 4, + Transform::Flipped90 => 5, + Transform::Flipped180 => 6, + Transform::Flipped270 => 7, + }; + + let logical_monitor = LogicalMonitor { + x: loc.x, + y: loc.y, + scale: output.current_scale().fractional_scale(), + transform, + is_primary: false, + monitors: vec![monitor.names.clone()], + properties: HashMap::new(), + }; + + (monitor, logical_monitor) }) .collect(); // Sort the built-in monitor first, then by connector name. monitors.sort_unstable_by(|a, b| { - let a_is_builtin = a.properties.contains_key("display-name"); - let b_is_builtin = b.properties.contains_key("display-name"); + let a_is_builtin = a.0.properties.contains_key("display-name"); + let b_is_builtin = b.0.properties.contains_key("display-name"); a_is_builtin .cmp(&b_is_builtin) .reverse() - .then_with(|| a.names.0.cmp(&b.names.0)) + .then_with(|| a.0.names.0.cmp(&b.0.names.0)) }); - let logical_monitors = monitors - .iter() - .map(|m| LogicalMonitor { - x: 0, - y: 0, - scale: 1., - transform: 0, - is_primary: false, - monitors: vec![m.names.clone()], - properties: HashMap::new(), - }) - .collect(); - - Ok((0, monitors, logical_monitors, HashMap::new())) + let (monitors, logical_monitors) = monitors.into_iter().unzip(); + let properties = HashMap::from([(String::from("layout-mode"), OwnedValue::from(1u32))]); + Ok((0, monitors, logical_monitors, properties)) } #[dbus_interface(signal)] @@ -117,8 +163,8 @@ impl DisplayConfig { } impl DisplayConfig { - pub fn new(enabled_outputs: Arc<Mutex<HashMap<String, Output>>>) -> Self { - Self { enabled_outputs } + pub fn new(ipc_outputs: Arc<Mutex<IpcOutputMap>>) -> Self { + Self { ipc_outputs } } } diff --git a/src/dbus/mutter_screen_cast.rs b/src/dbus/mutter_screen_cast.rs index 151a1c89..d9c6c28e 100644 --- a/src/dbus/mutter_screen_cast.rs +++ b/src/dbus/mutter_screen_cast.rs @@ -10,11 +10,12 @@ use zbus::zvariant::{DeserializeDict, OwnedObjectPath, SerializeDict, Type, Valu use zbus::{dbus_interface, fdo, InterfaceRef, ObjectServer, SignalContext}; use super::Start; +use crate::backend::IpcOutputMap; use crate::utils::output_size; #[derive(Clone)] pub struct ScreenCast { - enabled_outputs: Arc<Mutex<HashMap<String, Output>>>, + ipc_outputs: Arc<Mutex<IpcOutputMap>>, to_niri: calloop::channel::Sender<ScreenCastToNiri>, #[allow(clippy::type_complexity)] sessions: Arc<Mutex<Vec<(Session, InterfaceRef<Session>)>>>, @@ -23,7 +24,7 @@ pub struct ScreenCast { #[derive(Clone)] pub struct Session { id: usize, - enabled_outputs: Arc<Mutex<HashMap<String, Output>>>, + ipc_outputs: Arc<Mutex<IpcOutputMap>>, to_niri: calloop::channel::Sender<ScreenCastToNiri>, #[allow(clippy::type_complexity)] streams: Arc<Mutex<Vec<(Stream, InterfaceRef<Stream>)>>>, @@ -92,11 +93,7 @@ impl ScreenCast { let path = format!("/org/gnome/Mutter/ScreenCast/Session/u{}", session_id); let path = OwnedObjectPath::try_from(path).unwrap(); - let session = Session::new( - session_id, - self.enabled_outputs.clone(), - self.to_niri.clone(), - ); + let session = Session::new(session_id, self.ipc_outputs.clone(), self.to_niri.clone()); match server.at(&path, session.clone()).await { Ok(true) => { let iface = server.interface(&path).await.unwrap(); @@ -163,7 +160,8 @@ impl Session { ) -> fdo::Result<OwnedObjectPath> { debug!(connector, ?properties, "record_monitor"); - let Some(output) = self.enabled_outputs.lock().unwrap().get(connector).cloned() else { + let Some((_, Some(output))) = self.ipc_outputs.lock().unwrap().get(connector).cloned() + else { return Err(fdo::Error::Failed("no such monitor".to_owned())); }; @@ -212,11 +210,11 @@ impl Stream { impl ScreenCast { pub fn new( - enabled_outputs: Arc<Mutex<HashMap<String, Output>>>, + ipc_outputs: Arc<Mutex<IpcOutputMap>>, to_niri: calloop::channel::Sender<ScreenCastToNiri>, ) -> Self { Self { - enabled_outputs, + ipc_outputs, to_niri, sessions: Arc::new(Mutex::new(vec![])), } @@ -241,12 +239,12 @@ impl Start for ScreenCast { impl Session { pub fn new( id: usize, - enabled_outputs: Arc<Mutex<HashMap<String, Output>>>, + ipc_outputs: Arc<Mutex<IpcOutputMap>>, to_niri: calloop::channel::Sender<ScreenCastToNiri>, ) -> Self { Self { id, - enabled_outputs, + ipc_outputs, streams: Arc::new(Mutex::new(vec![])), to_niri, } diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 102fcb94..dc314734 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::os::unix::net::{UnixListener, UnixStream}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; @@ -14,6 +13,7 @@ use smithay::reexports::calloop::generic::Generic; use smithay::reexports::calloop::{Interest, LoopHandle, Mode, PostAction}; use smithay::reexports::rustix::fs::unlink; +use crate::backend::IpcOutputMap; use crate::niri::State; pub struct IpcServer { @@ -22,7 +22,7 @@ pub struct IpcServer { struct ClientCtx { event_loop: LoopHandle<'static, State>, - ipc_outputs: Arc<Mutex<HashMap<String, niri_ipc::Output>>>, + ipc_outputs: Arc<Mutex<IpcOutputMap>>, } impl IpcServer { @@ -125,7 +125,11 @@ fn process(ctx: &ClientCtx, buf: &str) -> anyhow::Result<Response> { let response = match request { Request::Outputs => { - let ipc_outputs = ctx.ipc_outputs.lock().unwrap().clone(); + let ipc_outputs = ctx.ipc_outputs.lock().unwrap(); + let ipc_outputs = ipc_outputs + .iter() + .map(|(name, (ipc, _))| (name.clone(), ipc.clone())) + .collect(); Response::Outputs(ipc_outputs) } Request::Action(action) => { diff --git a/src/niri.rs b/src/niri.rs index 02169a58..0cbd0cf3 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -228,6 +228,7 @@ pub struct Niri { pub inhibit_power_key_fd: Option<zbus::zvariant::OwnedFd>, pub ipc_server: Option<IpcServer>, + pub ipc_outputs_changed: bool, // Casts are dropped before PipeWire to prevent a double-free (yay). pub casts: Vec<Cast>, @@ -458,6 +459,7 @@ impl State { self.refresh_pointer_focus(); foreign_toplevel::refresh(self); self.niri.refresh_window_rules(); + self.niri.check_ipc_output_changed(); } pub fn move_cursor(&mut self, location: Point<f64, Logical>) { @@ -916,6 +918,7 @@ impl State { Some(output::Scale::Integer(scale)), None, ); + self.niri.ipc_outputs_changed = true; resized_outputs.push(output.clone()); } } @@ -1352,6 +1355,7 @@ impl Niri { inhibit_power_key_fd: None, ipc_server, + ipc_outputs_changed: false, pipewire, casts: vec![], @@ -1490,6 +1494,7 @@ impl Niri { new_position.x, new_position.y ); output.change_current_state(None, None, None, Some(new_position)); + self.ipc_outputs_changed = true; self.queue_redraw(&output); } } @@ -3433,9 +3438,18 @@ impl Niri { }); } + pub fn check_ipc_output_changed(&mut self) { + if self.ipc_outputs_changed { + self.ipc_outputs_changed = false; + + #[cfg(feature = "dbus")] + self.on_ipc_outputs_changed(); + } + } + #[cfg(feature = "dbus")] - pub fn on_enabled_outputs_changed(&self) { - let _span = tracy_client::span!("Niri::on_enabled_outputs_changed"); + pub fn on_ipc_outputs_changed(&self) { + let _span = tracy_client::span!("Niri::on_ipc_outputs_changed"); let Some(dbus) = &self.dbus else { return }; let Some(conn_display_config) = dbus.conn_display_config.clone() else { |
