mac: make display-names unique to allow specific selection

the Screen property localizedName returns a none unique dynamic name
that doesn't allow a specific selection of a Screen on every OS boot.
the name consists of the vendor name and model name (eg DELL U2723QE).
if the same model display is connected to the system several times,
macOS starts to add numbers to the localizedName (eg DELL U2723QE (1)),
that may not be associated to the same Screen on every OS boot or
connecting the display. it also changes the name of the first connected
display by adding that numeration. this makes it impossible specify the
proper screen with the screen-name option every time.

to circumvent this we remove the enumeration from the name and instead
add the serial number to the display-names property. this makes the
actual Screen unique and none dynamic. furthermore the selection of a
screen by name will check for equality for the old localizedName, simple
name without enumeration, serial number and the combined name with
serial number. this makes it possible to select the screen by either of
those names and identifiers, and keeps backwards compatibility with the
old behaviour.

Examples:
localized name (System Settings name): DELL U2723QE, DELL U2723QE (1)
simple name: DELL U2723QE
serial number: 123456789
combined name: DELL U2723QE (123456789)
This commit is contained in:
der richter 2024-04-20 15:21:31 +02:00
parent afae94cfbd
commit f7a32b5f29
3 changed files with 31 additions and 7 deletions

View File

@ -2711,11 +2711,11 @@ Property list
are the GDI names (\\.\DISPLAY1, \\.\DISPLAY2, etc.) and the first display
in the list will be the one that Windows considers associated with the
window (as determined by the MonitorFromWindow API.) On macOS these are the
Display Product Names as used in the System Information and only one display
name is returned since a window can only be on one screen. On Wayland, these
are the wl_output names if protocol version >= 4 is used
(LVDS-1, HDMI-A-1, X11-1, etc.), or the wl_output model reported by the
geometry event if protocol version < 4 is used.
Display Product Names as used in the System Information with a serial number
in brackets and only one display name is returned since a window can only be
on one screen. On Wayland, these are the wl_output names if protocol
version >= 4 is used (LVDS-1, HDMI-A-1, X11-1, etc.), or the wl_output model
reported by the geometry event if protocol version < 4 is used.
``display-fps``
The refresh rate of the current display. Currently, this is the lowest FPS

View File

@ -28,6 +28,30 @@ extension NSScreen {
return deviceDescription[.screenNumber] as? CGDirectDisplayID ?? 0
}
}
public var serialNumber: String {
get {
return String(CGDisplaySerialNumber(displayID))
}
}
public var name: String {
get {
// force unwrapping is fine here, regex is guaranteed to be valid
let regex = try! NSRegularExpression(pattern: " \\(\\d+\\)$", options: .caseInsensitive)
return regex.stringByReplacingMatches(
in: localizedName,
range: NSRange(location: 0, length: localizedName.count),
withTemplate: ""
)
}
}
public var uniqueName: String {
get {
return name + " (\(serialNumber))"
}
}
}
extension NSColor {

View File

@ -387,7 +387,7 @@ class Common: NSObject {
func getScreenBy(name screenName: String?) -> NSScreen? {
for screen in NSScreen.screens {
if screen.localizedName == screenName {
if [screen.localizedName, screen.name, screen.uniqueName, screen.serialNumber].contains(screenName) {
return screen
}
}
@ -622,7 +622,7 @@ class Common: NSObject {
let dnames = data!.assumingMemoryBound(to: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?.self)
var array: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>? = nil
var count: Int32 = 0
let displayName = getCurrentScreen()?.localizedName ?? "Unknown"
let displayName = getCurrentScreen()?.uniqueName ?? "Unknown"
app_bridge_tarray_append(nil, &array, &count, ta_xstrdup(nil, displayName))
app_bridge_tarray_append(nil, &array, &count, nil)