aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-03-27 09:46:18 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-03-27 09:46:18 +0400
commite276c906bf4bea27dc8173815ff373d04c20caaf (patch)
tree6843e6ab8244f296b89d54d53b2ebfd6e1a16592
parent571768af433b0fdc653f44b7dee0ad2dda6fe344 (diff)
downloadniri-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.rs12
-rw-r--r--src/backend/tty.rs49
-rw-r--r--src/backend/winit.rs47
-rw-r--r--src/dbus/mod.rs4
-rw-r--r--src/dbus/mutter_display_config.rs102
-rw-r--r--src/dbus/mutter_screen_cast.rs22
-rw-r--r--src/ipc/server.rs10
-rw-r--r--src/niri.rs18
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 {