-
-
Notifications
You must be signed in to change notification settings - Fork 209
Commit
This commit begins to build on some of the knowledge shared by EBNull in allowing users to specify monitor index preferences using physical device identifiers. This does not presently go all the way to EDIDs, but the display model and what I believe is a port identifier on the display adapter(s) can be used to uniquely identify a display in most use cases. However, I believe I may have unfortunately run into a bug in either windows-rs or Rust itself, as when the code calling EnumDisplayDevices is called, it always fails when running a release build, and always succeeds when running a debug build. This needs to be investigated further. re #612
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,11 +30,13 @@ use windows::Win32::Graphics::Dwm::DWM_CLOAKED_APP; | |
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_INHERITED; | ||
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL; | ||
use windows::Win32::Graphics::Gdi::CreateSolidBrush; | ||
use windows::Win32::Graphics::Gdi::EnumDisplayDevicesA; | ||
use windows::Win32::Graphics::Gdi::EnumDisplayMonitors; | ||
use windows::Win32::Graphics::Gdi::GetMonitorInfoW; | ||
use windows::Win32::Graphics::Gdi::InvalidateRect; | ||
use windows::Win32::Graphics::Gdi::MonitorFromPoint; | ||
use windows::Win32::Graphics::Gdi::MonitorFromWindow; | ||
use windows::Win32::Graphics::Gdi::DISPLAY_DEVICEA; | ||
use windows::Win32::Graphics::Gdi::HBRUSH; | ||
use windows::Win32::Graphics::Gdi::HDC; | ||
use windows::Win32::Graphics::Gdi::HMONITOR; | ||
|
@@ -93,6 +95,7 @@ use windows::Win32::UI::WindowsAndMessaging::ShowWindow; | |
use windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW; | ||
use windows::Win32::UI::WindowsAndMessaging::WindowFromPoint; | ||
use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT; | ||
use windows::Win32::UI::WindowsAndMessaging::EDD_GET_DEVICE_INTERFACE_NAME; | ||
use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE; | ||
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE; | ||
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT; | ||
|
@@ -164,8 +167,8 @@ impl_from_integer_for_windows_result!(usize, isize, u16, u32, i32); | |
impl<T, E> From<WindowsResult<T, E>> for Result<T, E> { | ||
fn from(result: WindowsResult<T, E>) -> Self { | ||
match result { | ||
WindowsResult::Err(error) => Self::Err(error), | ||
WindowsResult::Ok(ok) => Self::Ok(ok), | ||
WindowsResult::Err(error) => Err(error), | ||
WindowsResult::Ok(ok) => Ok(ok), | ||
} | ||
} | ||
} | ||
|
@@ -221,7 +224,7 @@ impl WindowsApi { | |
let mut monitors: Vec<(String, isize)> = vec![]; | ||
let monitors_ref: &mut Vec<(String, isize)> = monitors.as_mut(); | ||
Self::enum_display_monitors( | ||
Option::Some(windows_callbacks::valid_display_monitors), | ||
Some(windows_callbacks::valid_display_monitors), | ||
monitors_ref as *mut Vec<(String, isize)> as isize, | ||
)?; | ||
|
||
|
@@ -230,9 +233,47 @@ impl WindowsApi { | |
|
||
pub fn load_monitor_information(monitors: &mut Ring<Monitor>) -> Result<()> { | ||
Self::enum_display_monitors( | ||
Option::Some(windows_callbacks::enum_display_monitor), | ||
Some(windows_callbacks::enum_display_monitor), | ||
monitors as *mut Ring<Monitor> as isize, | ||
) | ||
)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn enum_display_devices( | ||
index: u32, | ||
lp_device: Option<[u8; 32]>, | ||
) -> Result<DISPLAY_DEVICEA> { | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
LGUG2Z
Author
Owner
|
||
#[allow(clippy::option_if_let_else)] | ||
let lp_device = if let Some(lp_device) = lp_device { | ||
PCSTR::from_raw(lp_device.as_ptr()) | ||
} else { | ||
PCSTR::null() | ||
}; | ||
|
||
let mut display_device = DISPLAY_DEVICEA { | ||
cb: u32::try_from(std::mem::size_of::<DISPLAY_DEVICEA>())?, | ||
..Default::default() | ||
}; | ||
|
||
match unsafe { | ||
EnumDisplayDevicesA( | ||
lp_device, | ||
index, | ||
std::ptr::addr_of_mut!(display_device), | ||
EDD_GET_DEVICE_INTERFACE_NAME, | ||
) | ||
} | ||
.ok() | ||
{ | ||
Ok(_) => {} | ||
Err(error) => { | ||
tracing::error!("enum_display_devices: {}", error); | ||
return Err(error.into()); | ||
} | ||
} | ||
|
||
Ok(display_device) | ||
} | ||
|
||
pub fn enum_windows(callback: WNDENUMPROC, callback_data_address: isize) -> Result<()> { | ||
|
@@ -245,7 +286,7 @@ impl WindowsApi { | |
if let Some(workspace) = monitor.workspaces_mut().front_mut() { | ||
// EnumWindows will enumerate through windows on all monitors | ||
Self::enum_windows( | ||
Option::Some(windows_callbacks::enum_window), | ||
Some(windows_callbacks::enum_window), | ||
workspace.containers_mut() as *mut VecDeque<Container> as isize, | ||
)?; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,7 @@ use crate::winevent_listener::WINEVENT_CALLBACK_CHANNEL; | |
use crate::BORDER_COLOUR_CURRENT; | ||
use crate::BORDER_RECT; | ||
use crate::BORDER_WIDTH; | ||
use crate::DISPLAY_INDEX_PREFERENCES; | ||
use crate::MONITOR_INDEX_PREFERENCES; | ||
use crate::TRANSPARENCY_COLOUR; | ||
|
||
|
@@ -72,7 +73,32 @@ pub extern "system" fn enum_display_monitor( | |
} | ||
} | ||
|
||
if let Ok(m) = WindowsApi::monitor(hmonitor.0) { | ||
let current_index = monitors.elements().len(); | ||
|
||
if let Ok(mut m) = WindowsApi::monitor(hmonitor.0) { | ||
#[allow(clippy::cast_possible_truncation)] | ||
if let Ok(d) = WindowsApi::enum_display_devices(current_index as u32, None) { | ||
let name = String::from_utf8_lossy(&d.DeviceName); | ||
This comment has been minimized.
Sorry, something went wrong.
EBNull
|
||
let clean_name = name | ||
.replace('\u{0000}', "") | ||
This comment has been minimized.
Sorry, something went wrong. |
||
.trim_start_matches(r"\\.\") | ||
.to_string(); | ||
|
||
if clean_name.eq(m.name()) { | ||
if let Ok(device) = WindowsApi::enum_display_devices(0, Some(d.DeviceName)) { | ||
let id = String::from_utf8_lossy(&device.DeviceID); | ||
let clean_id = id.replace('\u{0000}', ""); | ||
|
||
let mut split: Vec<_> = clean_id.split('#').collect(); | ||
This comment has been minimized.
Sorry, something went wrong.
EBNull
|
||
split.remove(0); | ||
split.remove(split.len() - 1); | ||
|
||
m.set_device(Option::from(split[0].to_string())); | ||
m.set_device_id(Option::from(split.join("-"))); | ||
} | ||
} | ||
} | ||
|
||
let monitor_index_preferences = MONITOR_INDEX_PREFERENCES.lock(); | ||
let mut index_preference = None; | ||
for (index, monitor_size) in &*monitor_index_preferences { | ||
|
@@ -81,6 +107,15 @@ pub extern "system" fn enum_display_monitor( | |
} | ||
} | ||
|
||
let display_index_preferences = DISPLAY_INDEX_PREFERENCES.lock(); | ||
for (index, device) in &*display_index_preferences { | ||
if let Some(known_device) = m.device() { | ||
if device == known_device { | ||
index_preference = Option::from(index); | ||
} | ||
} | ||
} | ||
|
||
if let Some(preference) = index_preference { | ||
let current_len = monitors.elements().len(); | ||
if *preference > current_len { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -416,6 +416,14 @@ struct MonitorIndexPreference { | |
bottom: i32, | ||
} | ||
|
||
#[derive(Parser, AhkFunction)] | ||
struct DisplayIndexPreference { | ||
/// Preferred monitor index (zero-indexed) | ||
index_preference: usize, | ||
/// Display name as identified in komorebic state | ||
This comment has been minimized.
Sorry, something went wrong.
EBNull
|
||
display: String, | ||
} | ||
|
||
#[derive(Parser, AhkFunction)] | ||
struct EnsureWorkspaces { | ||
/// Monitor index (zero-indexed) | ||
|
@@ -930,6 +938,9 @@ enum SubCommand { | |
/// Set the monitor index preference for a monitor identified using its size | ||
#[clap(arg_required_else_help = true)] | ||
MonitorIndexPreference(MonitorIndexPreference), | ||
/// Set the display index preference for a monitor identified using its display name | ||
#[clap(arg_required_else_help = true)] | ||
DisplayIndexPreference(DisplayIndexPreference), | ||
/// Create at least this many workspaces for the specified monitor | ||
#[clap(arg_required_else_help = true)] | ||
EnsureWorkspaces(EnsureWorkspaces), | ||
|
@@ -1890,6 +1901,12 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue | |
.as_bytes()?, | ||
)?; | ||
} | ||
SubCommand::DisplayIndexPreference(arg) => { | ||
send_message( | ||
&SocketMessage::DisplayIndexPreference(arg.index_preference, arg.display) | ||
.as_bytes()?, | ||
)?; | ||
} | ||
SubCommand::EnsureWorkspaces(workspaces) => { | ||
send_message( | ||
&SocketMessage::EnsureWorkspaces(workspaces.monitor, workspaces.workspace_count) | ||
|
A quick note on the
A
orW
suffixes: in win32 there are often two APIs that do the same thing, with the only difference being the suffix. If this were in C and usingwindows.h
,#define
magic would automatically choose based on the compile time environment - namely,W
is "wide" andA
is "ascii". Using theA
functions is why thefrom_wide
thing I saw you try didn't work. If yous/A/W/g
across all function and struct names, you should be able to usefrom_wide
.