aboutsummaryrefslogtreecommitdiff
path: root/src/dbus
diff options
context:
space:
mode:
authorVal Packett <val@packett.cool>2025-01-01 03:07:47 -0300
committerIvan Molodetskikh <yalterz@gmail.com>2025-01-17 11:16:10 +0300
commit890bbff0077cddaa08d7d6c05c797c41b0b4c09e (patch)
tree15f3f825bcda7571763f699a8a55787e594ec31c /src/dbus
parentb853d5b1247fddfaeac0dbdfb9304c69c6de463a (diff)
downloadniri-890bbff0077cddaa08d7d6c05c797c41b0b4c09e.tar.gz
niri-890bbff0077cddaa08d7d6c05c797c41b0b4c09e.tar.bz2
niri-890bbff0077cddaa08d7d6c05c797c41b0b4c09e.zip
dbus: DisplayConfig: implement apply_monitors_config
This enables gnome-control-center to apply display configuration changes. Only temporarily, persistence is ignored currently.
Diffstat (limited to 'src/dbus')
-rw-r--r--src/dbus/mod.rs20
-rw-r--r--src/dbus/mutter_display_config.rs106
2 files changed, 122 insertions, 4 deletions
diff --git a/src/dbus/mod.rs b/src/dbus/mod.rs
index 347b16fd..f69dc1d9 100644
--- a/src/dbus/mod.rs
+++ b/src/dbus/mod.rs
@@ -50,7 +50,25 @@ impl DBusServers {
}
if is_session_instance || config.debug.dbus_interfaces_in_non_session_instances {
- let display_config = DisplayConfig::new(backend.ipc_outputs());
+ let (to_niri, from_display_config) = calloop::channel::channel();
+ let display_config = DisplayConfig::new(to_niri, backend.ipc_outputs());
+ niri.event_loop
+ .insert_source(from_display_config, move |event, _, state| match event {
+ calloop::channel::Event::Msg(new_conf) => {
+ for (name, conf) in new_conf {
+ state.modify_output_config(&name, move |output| {
+ if let Some(new_output) = conf {
+ *output = new_output;
+ } else {
+ output.off = true;
+ }
+ });
+ }
+ state.reload_output_config();
+ }
+ calloop::channel::Event::Closed => (),
+ })
+ .unwrap();
dbus.conn_display_config = try_start(display_config);
let screen_saver = ScreenSaver::new(niri.is_fdo_idle_inhibited.clone());
diff --git a/src/dbus/mutter_display_config.rs b/src/dbus/mutter_display_config.rs
index 2be37b5e..b8ab08f9 100644
--- a/src/dbus/mutter_display_config.rs
+++ b/src/dbus/mutter_display_config.rs
@@ -1,7 +1,8 @@
use std::collections::HashMap;
+use std::str::FromStr;
use std::sync::{Arc, Mutex};
-use serde::Serialize;
+use serde::{Deserialize, Serialize};
use smithay::utils::Size;
use zbus::fdo::RequestNameFlags;
use zbus::object_server::SignalEmitter;
@@ -14,6 +15,7 @@ use crate::utils::is_laptop_panel;
use crate::utils::scale::supported_scales;
pub struct DisplayConfig {
+ to_niri: calloop::channel::Sender<HashMap<String, Option<niri_config::Output>>>,
ipc_outputs: Arc<Mutex<IpcOutputMap>>,
}
@@ -46,6 +48,17 @@ pub struct LogicalMonitor {
properties: HashMap<String, OwnedValue>,
}
+// ApplyMonitorsConfig
+#[derive(Deserialize, Type)]
+pub struct LogicalMonitorConfiguration {
+ x: i32,
+ y: i32,
+ scale: f64,
+ transform: u32,
+ _is_primary: bool,
+ monitors: Vec<(String, String, HashMap<String, OwnedValue>)>,
+}
+
#[interface(name = "org.gnome.Mutter.DisplayConfig")]
impl DisplayConfig {
async fn get_current_state(
@@ -158,6 +171,87 @@ impl DisplayConfig {
Ok((0, monitors, logical_monitors, properties))
}
+ async fn apply_monitors_config(
+ &self,
+ _serial: u32,
+ method: u32,
+ logical_monitor_configs: Vec<LogicalMonitorConfiguration>,
+ _properties: HashMap<String, OwnedValue>,
+ ) -> fdo::Result<()> {
+ let current_conf = self.ipc_outputs.lock().unwrap();
+ let mut new_conf = HashMap::new();
+ for requested_config in logical_monitor_configs {
+ if requested_config.monitors.len() > 1 {
+ return Err(zbus::fdo::Error::Failed(
+ "Mirroring is not yet supported".to_owned(),
+ ));
+ }
+ for (connector, mode, _props) in requested_config.monitors {
+ if !current_conf.values().any(|o| o.name == connector) {
+ return Err(zbus::fdo::Error::Failed(format!(
+ "Connector '{}' not found",
+ connector
+ )));
+ }
+ new_conf.insert(
+ connector.clone(),
+ Some(niri_config::Output {
+ off: false,
+ name: connector,
+ scale: Some(niri_config::FloatOrInt(requested_config.scale)),
+ transform: match requested_config.transform {
+ 0 => niri_ipc::Transform::Normal,
+ 1 => niri_ipc::Transform::_90,
+ 2 => niri_ipc::Transform::_180,
+ 3 => niri_ipc::Transform::_270,
+ 4 => niri_ipc::Transform::Flipped,
+ 5 => niri_ipc::Transform::Flipped90,
+ 6 => niri_ipc::Transform::Flipped180,
+ 7 => niri_ipc::Transform::Flipped270,
+ x => {
+ return Err(zbus::fdo::Error::Failed(format!(
+ "Unknown transform {}",
+ x
+ )))
+ }
+ },
+ position: Some(niri_config::Position {
+ x: requested_config.x,
+ y: requested_config.y,
+ }),
+ mode: Some(niri_ipc::ConfiguredMode::from_str(&mode).map_err(|e| {
+ zbus::fdo::Error::Failed(format!(
+ "Could not parse mode '{}': {}",
+ mode, e
+ ))
+ })?),
+ // FIXME: VRR
+ ..Default::default()
+ }),
+ );
+ }
+ }
+ if new_conf.is_empty() {
+ return Err(zbus::fdo::Error::Failed(
+ "At least one output must be enabled".to_owned(),
+ ));
+ }
+ for output in current_conf.values() {
+ if !new_conf.contains_key(&output.name) {
+ new_conf.insert(output.name.clone(), None);
+ }
+ }
+ if method == 0 {
+ // 0 means "verify", so don't actually apply here
+ return Ok(());
+ }
+ if let Err(err) = self.to_niri.send(new_conf) {
+ warn!("error sending message to niri: {err:?}");
+ return Err(fdo::Error::Failed("internal error".to_owned()));
+ }
+ Ok(())
+ }
+
#[zbus(signal)]
pub async fn monitors_changed(ctxt: &SignalEmitter<'_>) -> zbus::Result<()>;
@@ -188,8 +282,14 @@ impl DisplayConfig {
}
impl DisplayConfig {
- pub fn new(ipc_outputs: Arc<Mutex<IpcOutputMap>>) -> Self {
- Self { ipc_outputs }
+ pub fn new(
+ to_niri: calloop::channel::Sender<HashMap<String, Option<niri_config::Output>>>,
+ ipc_outputs: Arc<Mutex<IpcOutputMap>>,
+ ) -> Self {
+ Self {
+ to_niri,
+ ipc_outputs,
+ }
}
}