Allo wmatching outputs by EDID serial

Note that EDID serials are not totally unique across all monitors. Also some monitors don't have an EDID serial number. Also this hasn't been tested yet
This commit is contained in:
Ottatop 2024-04-18 11:04:15 -05:00
parent 0284a70c10
commit d2445afe10
5 changed files with 69 additions and 25 deletions

View file

@ -167,6 +167,19 @@ function output.connect_for_all(callback)
})
end
---@param id_str string
---@param op OutputHandle
---
---@return boolean
local function output_id_matches(id_str, op)
if id_str:match("^serial:") then
local serial = tonumber(id_str:sub(8))
return serial and serial == op:serial() or false
else
return id_str == op.name
end
end
---@class OutputSetup
---@field filter (fun(output: OutputHandle): boolean)?
---@field mode Mode?
@ -242,7 +255,9 @@ function output.setup(setups)
if op_id:match("^%d+:") then
---@type string
local index = op_id:match("^%d+")
---@diagnostic disable-next-line: redefined-local
local op_id = op_id:sub(index:len() + 2)
---@diagnostic disable-next-line: redefined-local
local index = tonumber(index)
---@cast index number
@ -280,7 +295,7 @@ function output.setup(setups)
---@param op OutputHandle
local function apply_setups(op)
for _, op_setup in ipairs(op_setups) do
if op_setup[1] == op.name or op_setup[1] == "*" then
if output_id_matches(op_setup[1], op) or op_setup[1] == "*" then
local setup = op_setup.setup
if setup.filter and not setup.filter(op) then
@ -380,7 +395,9 @@ function output.setup_locs(update_locs_on, locs)
if op_id:match("^%d+:") then
---@type string
local index = op_id:match("^%d+")
---@diagnostic disable-next-line: redefined-local
local op_id = op_id:sub(index:len() + 2)
---@diagnostic disable-next-line: redefined-local
local index = tonumber(index)
---@cast index number
@ -417,7 +434,7 @@ function output.setup_locs(update_locs_on, locs)
---@diagnostic disable-next-line: redefined-local
for _, setup in ipairs(setups) do
for _, op in ipairs(outputs) do
if op.name == setup[1] then
if output_id_matches(setup[1], op) then
if type(setup.loc[1]) == "number" then
local loc = { x = setup.loc[1], y = setup.loc[2] }
op:set_location(loc)
@ -445,7 +462,7 @@ function output.setup_locs(update_locs_on, locs)
end
end
if op.name ~= setup[1] or type(setup.loc[1]) == "number" then
if not output_id_matches(setup[1], op) or type(setup.loc[1]) == "number" then
goto continue
end
@ -1028,7 +1045,7 @@ function OutputHandle:transform()
return self:props().transform
end
---Get this output's serial.
---Get this output's EDID serial number.
---
---Shorthand for `handle:props().serial`.
---

View file

@ -9,7 +9,7 @@
//! This module provides [`Output`], which allows you to get [`OutputHandle`]s for different
//! connected monitors and set them up.
use std::sync::OnceLock;
use std::{num::NonZeroU32, sync::OnceLock};
use futures::FutureExt;
use pinnacle_api_defs::pinnacle::output::{
@ -516,7 +516,13 @@ pub enum OutputLoc {
pub enum OutputId {
/// Identify using the output's name.
Name(String),
// TODO: serial
/// Identify using the output's EDID serial number.
///
/// Note: some displays (like laptop screens) don't have a serial number, in which case this won't match it.
/// Additionally the Rust API assumes monitor serial numbers are unique.
/// If you're unlucky enough to have two monitors with the same serial number,
/// use [`OutputId::Name`] instead.
Serial(NonZeroU32),
}
impl OutputId {
@ -532,6 +538,7 @@ impl OutputId {
pub fn matches(&self, output: &OutputHandle) -> bool {
match self {
OutputId::Name(name) => name == output.name(),
OutputId::Serial(serial) => Some(serial.get()) == output.serial(),
}
}
}
@ -1111,6 +1118,30 @@ impl OutputHandle {
self.props_async().await.scale
}
/// Get this output's transform.
///
/// Shorthand for `self.props().transform`
pub fn transform(&self) -> Option<Transform> {
self.props().transform
}
/// The async version of [`OutputHandle::transform`].
pub async fn transform_async(&self) -> Option<Transform> {
self.props_async().await.transform
}
/// Get this output's EDID serial number.
///
/// Shorthand for `self.props().serial`
pub fn serial(&self) -> Option<u32> {
self.props().serial
}
/// The async version of [`OutputHandle::serial`].
pub async fn serial_async(&self) -> Option<u32> {
self.props_async().await.serial
}
/// Get this output's unique name (the name of its connector).
pub fn name(&self) -> &str {
&self.name

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
use std::{num::NonZeroU32, sync::RwLock};
use std::{cell::RefCell, num::NonZeroU32};
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{OutputMoveResponse, OutputResizeResponse};
use smithay::{
@ -53,9 +53,9 @@ impl WithState for Output {
{
let state = self
.user_data()
.get_or_insert_threadsafe(RwLock::<Self::State>::default);
.get_or_insert(RefCell::<Self::State>::default);
func(&state.read().expect("with_state already locked"))
func(&state.borrow())
}
fn with_state_mut<F, T>(&self, func: F) -> T
@ -64,9 +64,9 @@ impl WithState for Output {
{
let state = self
.user_data()
.get_or_insert_threadsafe(RwLock::<Self::State>::default);
.get_or_insert(RefCell::<Self::State>::default);
func(&mut state.write().expect("with_state already locked"))
func(&mut state.borrow_mut())
}
}

View file

@ -40,11 +40,7 @@ use smithay::{
},
xwayland::{X11Wm, XWayland, XWaylandEvent},
};
use std::{
path::PathBuf,
sync::{Arc, RwLock},
time::Duration,
};
use std::{cell::RefCell, path::PathBuf, sync::Arc, time::Duration};
use sysinfo::{ProcessRefreshKind, RefreshKind};
use tracing::{error, info};
use xdg::BaseDirectories;
@ -382,9 +378,9 @@ impl WithState for WlSurface {
compositor::with_states(self, |states| {
let state = states
.data_map
.get_or_insert_threadsafe(RwLock::<Self::State>::default);
.get_or_insert(RefCell::<Self::State>::default);
func(&state.read().expect("with_state already locked"))
func(&state.borrow())
})
}
@ -395,9 +391,9 @@ impl WithState for WlSurface {
compositor::with_states(self, |states| {
let state = states
.data_map
.get_or_insert_threadsafe(RwLock::<Self::State>::default);
.get_or_insert(RefCell::<Self::State>::default);
func(&mut state.write().expect("with_state already locked"))
func(&mut state.borrow_mut())
})
}
}

View file

@ -2,7 +2,7 @@
pub mod rules;
use std::{ops::Deref, sync::RwLock};
use std::{cell::RefCell, ops::Deref};
use smithay::{
desktop::{space::SpaceElement, Window, WindowSurface},
@ -192,9 +192,9 @@ impl WithState for WindowElement {
{
let state = self
.user_data()
.get_or_insert_threadsafe(|| RwLock::new(WindowElementState::new()));
.get_or_insert(|| RefCell::new(WindowElementState::new()));
func(&state.read().expect("with_state already locked"))
func(&state.borrow())
}
fn with_state_mut<F, T>(&self, func: F) -> T
@ -203,9 +203,9 @@ impl WithState for WindowElement {
{
let state = self
.user_data()
.get_or_insert(|| RwLock::new(WindowElementState::new()));
.get_or_insert(|| RefCell::new(WindowElementState::new()));
func(&mut state.write().expect("with_state already locked"))
func(&mut state.borrow_mut())
}
}