diff --git a/komorebi/src/lib.rs b/komorebi/src/lib.rs index 8d87e90a..587666fe 100644 --- a/komorebi/src/lib.rs +++ b/komorebi/src/lib.rs @@ -173,6 +173,8 @@ lazy_static! { matching_strategy: Option::from(MatchingStrategy::Equals), }), ])); + static ref DUPLICATE_MONITOR_SERIAL_IDS: Arc>> = + Arc::new(Mutex::new(Vec::new())); static ref SUBSCRIPTION_PIPES: Arc>> = Arc::new(Mutex::new(HashMap::new())); pub static ref SUBSCRIPTION_SOCKETS: Arc>> = diff --git a/komorebi/src/monitor_reconciliator/mod.rs b/komorebi/src/monitor_reconciliator/mod.rs index b9d57816..cb099744 100644 --- a/komorebi/src/monitor_reconciliator/mod.rs +++ b/komorebi/src/monitor_reconciliator/mod.rs @@ -13,6 +13,7 @@ use crate::State; use crate::WindowManager; use crate::WindowsApi; use crate::DISPLAY_INDEX_PREFERENCES; +use crate::DUPLICATE_MONITOR_SERIAL_IDS; use crate::WORKSPACE_MATCHING_RULES; use crossbeam_channel::Receiver; use crossbeam_channel::Sender; @@ -84,9 +85,32 @@ pub fn insert_in_monitor_cache(serial_or_device_id: &str, monitor: Monitor) { } pub fn attached_display_devices() -> color_eyre::Result> { - Ok(win32_display_data::connected_displays_all() + let all_displays = win32_display_data::connected_displays_all() .flatten() - .map(|display| { + .collect::>(); + + let mut serial_id_map = HashMap::new(); + + for d in &all_displays { + if let Some(id) = &d.serial_number_id { + *serial_id_map.entry(id.clone()).or_insert(0) += 1; + } + } + + for d in &all_displays { + if let Some(id) = &d.serial_number_id { + if serial_id_map.get(id).copied().unwrap_or_default() > 1 { + let mut dupes = DUPLICATE_MONITOR_SERIAL_IDS.lock(); + if !dupes.contains(id) { + dupes.push(id.clone()); + } + } + } + } + + Ok(all_displays + .into_iter() + .map(|mut display| { let path = display.device_path; let (device, device_id) = if path.is_empty() { @@ -103,6 +127,13 @@ pub fn attached_display_devices() -> color_eyre::Result> { let name = display.device_name.trim_start_matches(r"\\.\").to_string(); let name = name.split('\\').collect::>()[0].to_string(); + if let Some(id) = &display.serial_number_id { + let dupes = DUPLICATE_MONITOR_SERIAL_IDS.lock(); + if dupes.contains(id) { + display.serial_number_id = None; + } + } + monitor::new( display.hmonitor, display.size.into(), @@ -270,9 +301,15 @@ pub fn handle_notifications(wm: Arc>) -> color_eyre::Result // Make sure that in our state any attached displays have the latest Win32 data for monitor in wm.monitors_mut() { for attached in &attached_devices { - if attached.serial_number_id().eq(monitor.serial_number_id()) - || attached.device_id().eq(monitor.device_id()) + let serial_number_ids_match = if let (Some(attached_snid), Some(m_snid)) = + (attached.serial_number_id(), monitor.serial_number_id()) { + attached_snid.eq(m_snid) + } else { + false + }; + + if serial_number_ids_match || attached.device_id().eq(monitor.device_id()) { monitor.set_id(attached.id()); monitor.set_device(attached.device().clone()); monitor.set_device_id(attached.device_id().clone()); diff --git a/komorebi/src/windows_api.rs b/komorebi/src/windows_api.rs index c25526cb..43dbe987 100644 --- a/komorebi/src/windows_api.rs +++ b/komorebi/src/windows_api.rs @@ -153,6 +153,7 @@ use crate::windows_callbacks; use crate::Window; use crate::WindowManager; use crate::DISPLAY_INDEX_PREFERENCES; +use crate::DUPLICATE_MONITOR_SERIAL_IDS; use crate::MONITOR_INDEX_PREFERENCES; macro_rules! as_ptr { @@ -258,7 +259,30 @@ impl WindowsApi { let monitors = &mut wm.monitors; let monitor_usr_idx_map = &mut wm.monitor_usr_idx_map; - 'read: for display in win32_display_data::connected_displays_all().flatten() { + let all_displays = win32_display_data::connected_displays_all() + .flatten() + .collect::>(); + + let mut serial_id_map = HashMap::new(); + + for d in &all_displays { + if let Some(id) = &d.serial_number_id { + *serial_id_map.entry(id.clone()).or_insert(0) += 1; + } + } + + for d in &all_displays { + if let Some(id) = &d.serial_number_id { + if serial_id_map.get(id).copied().unwrap_or_default() > 1 { + let mut dupes = DUPLICATE_MONITOR_SERIAL_IDS.lock(); + if !dupes.contains(id) { + dupes.push(id.clone()); + } + } + } + } + + 'read: for mut display in all_displays { let path = display.device_path.clone(); let (device, device_id) = if path.is_empty() { @@ -281,6 +305,13 @@ impl WindowsApi { } } + if let Some(id) = &display.serial_number_id { + let dupes = DUPLICATE_MONITOR_SERIAL_IDS.lock(); + if dupes.contains(id) { + display.serial_number_id = None; + } + } + let m = monitor::new( display.hmonitor, display.size.into(), @@ -972,7 +1003,7 @@ impl WindowsApi { } pub fn monitor(hmonitor: isize) -> Result { - for display in win32_display_data::connected_displays_all().flatten() { + for mut display in win32_display_data::connected_displays_all().flatten() { if display.hmonitor == hmonitor { let path = display.device_path; @@ -990,6 +1021,13 @@ impl WindowsApi { let name = display.device_name.trim_start_matches(r"\\.\").to_string(); let name = name.split('\\').collect::>()[0].to_string(); + if let Some(id) = &display.serial_number_id { + let dupes = DUPLICATE_MONITOR_SERIAL_IDS.lock(); + if dupes.contains(id) { + display.serial_number_id = None; + } + } + let monitor = monitor::new( hmonitor, display.size.into(),