mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-11 02:49:56 -06:00
LR-PREF-DISPLAY: an unreadable Windows advanced-colour state leaves previews sRGB
When the display configuration, the window's display path or its advanced-colour state can't be read, `monitor_color` answered with the monitor's profile as if Windows weren't colour-managing the desktop. If it was (HDR, Auto Color Management), previews were converted twice. It now answers `Unknown`, as the crate's other failures do, so previews stay sRGB (Windows 10 before 1709 and drivers that don't report the state included). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GfjNkJiMUagz3DN3zoV2rV
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e7577a16b9
commit
0b610c8307
@@ -61,6 +61,19 @@ fn managed(flags: u32) -> bool {
|
||||
flags & 0b110 != 0
|
||||
}
|
||||
|
||||
/// The answer Windows' own colour management settles, `None` when the monitor's profile decides:
|
||||
/// [`MonitorColor::ManagedByWindows`] while it colour-manages the desktop, and
|
||||
/// [`MonitorColor::Unknown`] when its state can't be read (`managed` is `None`), since applying the
|
||||
/// monitor's profile on top of Windows' conversion would convert twice.
|
||||
#[cfg(any(windows, test))]
|
||||
fn settled_by_windows(managed: Option<bool>) -> Option<MonitorColor> {
|
||||
match managed {
|
||||
Some(true) => Some(MonitorColor::ManagedByWindows),
|
||||
Some(false) => None,
|
||||
None => Some(MonitorColor::Unknown),
|
||||
}
|
||||
}
|
||||
|
||||
/// The text of a NUL-terminated UTF-16 buffer (all of it without a NUL).
|
||||
#[cfg(any(windows, test))]
|
||||
fn until_nul(units: &[u16]) -> &[u16] {
|
||||
@@ -70,7 +83,7 @@ fn until_nul(units: &[u16]) -> &[u16] {
|
||||
#[cfg(windows)]
|
||||
#[allow(unsafe_code)]
|
||||
mod win32 {
|
||||
use super::{MonitorColor, managed, until_nul};
|
||||
use super::{MonitorColor, managed, settled_by_windows, until_nul};
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use std::path::PathBuf;
|
||||
@@ -100,11 +113,11 @@ mod win32 {
|
||||
|
||||
pub fn monitor_color(hwnd: isize) -> MonitorColor {
|
||||
let Some(device) = monitor_device(hwnd) else { return MonitorColor::Unknown };
|
||||
if managed_by_windows(&device) == Some(true) {
|
||||
return MonitorColor::ManagedByWindows;
|
||||
// (an advanced-colour state that can't be read, as on Windows before 10 1709 or with a
|
||||
// driver that doesn't say, is unknown: previews then stay sRGB, as before profiles were read)
|
||||
if let Some(answer) = settled_by_windows(managed_by_windows(&device)) {
|
||||
return answer;
|
||||
}
|
||||
// (an unknown advanced-colour state, as on Windows before 10 1709 or with a driver that
|
||||
// doesn't say, counts as not managed)
|
||||
match monitor_id(&device) {
|
||||
Some(id) => wcs_profile(&id),
|
||||
None => icm_profile(&device).map_or(MonitorColor::Unknown, MonitorColor::Profile),
|
||||
@@ -323,6 +336,14 @@ mod tests {
|
||||
assert!(!managed(0b1000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_unreadable_advanced_colour_state_is_unknown_rather_than_a_profile() {
|
||||
assert_eq!(settled_by_windows(Some(true)), Some(MonitorColor::ManagedByWindows));
|
||||
assert_eq!(settled_by_windows(Some(false)), None, "an SDR desktop: the monitor's profile decides");
|
||||
// Windows may be converting already: a profile on top would convert twice
|
||||
assert_eq!(settled_by_windows(None), Some(MonitorColor::Unknown));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn utf16_text_stops_at_its_nul() {
|
||||
assert_eq!(until_nul(&[65, 66, 0, 67]), &[65, 66]);
|
||||
|
||||
@@ -26,7 +26,8 @@ a restart. (GDI's `GetICMProfileW` keeps answering the profile a process first s
|
||||
monitor's device can't be found.) With no profile assigned, previews are sRGB. **While Windows colour-manages the
|
||||
desktop itself** (HDR on, or Auto Color Management on Windows 11: its advanced-colour state, from
|
||||
`DisplayConfigGetDeviceInfo`), it treats an ordinary app's output as sRGB and converts it for the monitor, so previews
|
||||
stay sRGB rather than be converted twice. The log says which applies (`screen profile: …`) whenever it changes.
|
||||
stay sRGB rather than be converted twice. So do they when that state can't be read (Windows 10 before 1709, a driver
|
||||
that doesn't report it). The log says which applies (`screen profile: …`) whenever it changes.
|
||||
|
||||
## Using it
|
||||
|
||||
|
||||
Reference in New Issue
Block a user