Skip to content

Commit

Permalink
feat(CompositeDeviceConfig): add 'maximum_sources' to define max sour…
Browse files Browse the repository at this point in the history
…ce devices per composite device
  • Loading branch information
ShadowApex committed Nov 21, 2024
1 parent 4c095a1 commit 962da19
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@
"type": "string"
},
"single_source": {
"description": "If true, this composite device should only use one source device. Defaults to false.",
"description": "DEPRECATED: use 'maximum_sources' instead. If true, this composite device should only use one source device. Defaults to false.",
"type": "boolean",
"default": false
},
"maximum_sources": {
"description": "Maximum number of source devices that this composite device can manage. When this composite device reaches this maximum and a new matching source device is detected, a new composite device will be created instead of adding the source device to the existing one. Any value less than 1 indicates no maximum. Defaults to 0 (unlimited).",
"type": "integer",
"default": 0
},
"matches": {
"description": "Only use this profile if *any* of the given DMI system matches match. If this list is empty, then the source devices will *always* be checked.",
"type": "array",
Expand Down
3 changes: 2 additions & 1 deletion src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,8 @@ pub struct CompositeDeviceConfig {
pub kind: String,
pub name: String,
pub matches: Vec<Match>,
pub single_source: Option<bool>,
pub single_source: Option<bool>, // DEPRECATED; use 'maximum_sources' instead
pub maximum_sources: Option<i32>,
pub capability_map_id: Option<String>,
pub source_devices: Vec<SourceDevice>,
pub target_devices: Option<Vec<String>>,
Expand Down
42 changes: 39 additions & 3 deletions src/input/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -706,11 +706,36 @@ impl Manager {
log::trace!("{:?} is a single source device. Skipping.", config.name);
continue;
}
if config.maximum_sources.unwrap_or(0) == 1 {
log::trace!("{:?} is a single source device. Skipping.", config.name);
continue;
}
log::trace!(
"Composite device has {} source devices defined",
config.source_devices.len()
);

// If the CompositeDevice only allows a maximum number of source devices,
// check to see if that limit has been reached. If that limit is reached,
// then a new CompositeDevice will be created for the source device.
if let Some(max_sources) = config.maximum_sources {
// If maximum_sources is less than 1 (e.g. 0, -1) then consider
// the maximum to be 'unlimited'.
if max_sources > 0 {
// Check to see how many source devices this composite device is
// currently managing.
if let Some(sources) = self.composite_device_sources.get(composite_device) {
let sources_count = sources.len() as i32;
if sources_count >= max_sources {
log::trace!(
"{composite_device:?} maximum source devices reached: {max_sources}. Skipping."
);
continue;
}
}
}
}

// Check if this device matches any source udev configs of the running
// CompositeDevice.
for source_device in config.source_devices.iter() {
Expand Down Expand Up @@ -1650,17 +1675,27 @@ impl Manager {
};

// Wait until the device has initialized with udev
// TODO: Add max wait time for udev initialization
const MAX_TRIES: u8 = 80;
let mut attempt: u8 = 0;
loop {
// Break after max attempts reached
if attempt > MAX_TRIES {
log::warn!("Unable to create initialized UdevDevice for {base_path}/{name} after {MAX_TRIES} attempts.");
continue 'outer;
}

// Try to get the device from udev to check its initialization state
{
let Ok(device) = ::udev::Device::from_subsystem_sysname(
subsystem.to_string(),
name.clone(),
) else {
log::warn!(
log::debug!(
"Unable to create UdevDevice from {base_path}/{name} to check initialization"
);
continue 'outer;
attempt += 1;
tokio::time::sleep(Duration::from_millis(10)).await;
continue;
};

if device.is_initialized() {
Expand All @@ -1670,6 +1705,7 @@ impl Manager {
log::trace!("{base_path}/{name} is not yet initialized by udev");

tokio::time::sleep(Duration::from_millis(10)).await;
attempt += 1;
}

// Create a udev device for the device
Expand Down
5 changes: 5 additions & 0 deletions src/udev/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,11 @@ impl UdevDevice {
self.sysname.clone()
}

/// Returns the syspath of the device.
///
/// The path is an absolute path and includes the sys mount point. For example, the syspath for
/// `tty0` could be `/sys/devices/virtual/tty/tty0`, which includes the sys mount point,
/// `/sys`.
pub fn syspath(&self) -> String {
self.syspath.clone()
}
Expand Down

0 comments on commit 962da19

Please sign in to comment.