Add display identification overlays

This commit is contained in:
Gabriel Brown
2026-08-18 15:00:18 -04:00
parent 70a9d27c98
commit 0c3935f818
7 changed files with 142 additions and 1 deletions
@@ -3,8 +3,11 @@ import Quickshell.Io
import QtQuick
import qs.modules.settings
import qs.services
ShellRoot {
DisplayIdentify {}
QtObject {
id: fixtureService
@@ -71,5 +74,8 @@ ShellRoot {
name: record.name, x: record.x, y: record.y, primary: record.primary
})));
}
function identify(): void { Displays.identify(); }
function identifying(): bool { return Displays.identifying; }
}
}
@@ -279,7 +279,8 @@ Item {
spacing: 8
Text {
width: Math.max(0, parent.width - primaryButton.width - applyButton.width - 16)
width: Math.max(0, parent.width - identifyButton.width
- primaryButton.width - applyButton.width - 24)
anchors.verticalCenter: parent.verticalCenter
text: root.width >= 600
? "Drag to arrange · arrows move 10 px · Shift moves 100 px"
@@ -290,6 +291,13 @@ Item {
elide: Text.ElideRight
}
SettingsButton {
id: identifyButton
text: "Identify"
enabled: root.interactionEnabled
onClicked: root.displayService.identify()
}
SettingsButton {
id: primaryButton
text: "Make primary"
@@ -0,0 +1,85 @@
import Quickshell
import Quickshell.Wayland
import QtQuick
import qs.config
import qs.services
import qs.widgets
Variants {
model: Quickshell.screens
PanelWindow {
id: win
property var modelData: null
readonly property string connector: win.modelData?.name ?? "Display"
readonly property int number: Math.max(1,
Displays.monitors.findIndex(monitor => monitor.name === win.connector) + 1)
readonly property string description: Displays.monitorNamed(win.connector)?.description ?? "Connected display"
screen: win.modelData
visible: Displays.identifying
implicitWidth: 260
implicitHeight: 172
color: "transparent"
exclusiveZone: 0
exclusionMode: ExclusionMode.Ignore
mask: Region {}
WlrLayershell.namespace: "qs-display-identify"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
Rectangle {
anchors.fill: parent
radius: Theme.popoverRadius
color: Theme.alpha(Theme.bgPopover, 0.96)
border.width: 1
border.color: Theme.alpha(Theme.fg, 0.14)
PrismEdge {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
inset: parent.radius
}
Column {
anchors.centerIn: parent
width: parent.width - 32
spacing: 4
Text {
width: parent.width
horizontalAlignment: Text.AlignHCenter
text: String(win.number)
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: 68
font.weight: Font.DemiBold
}
Text {
width: parent.width
horizontalAlignment: Text.AlignHCenter
text: win.connector
color: Theme.accentAlt
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
elide: Text.ElideRight
}
Text {
width: parent.width
horizontalAlignment: Text.AlignHCenter
text: win.description
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
elide: Text.ElideRight
}
}
}
}
}
@@ -43,6 +43,7 @@ ShortcutCapture 1.0 ShortcutCapture.qml
ChoiceGrid 1.0 ChoiceGrid.qml
DisplayModePicker 1.0 DisplayModePicker.qml
DisplayArrangement 1.0 DisplayArrangement.qml
DisplayIdentify 1.0 DisplayIdentify.qml
WifiPanel 1.0 WifiPanel.qml
BluetoothPanel 1.0 BluetoothPanel.qml
PasswordField 1.0 PasswordField.qml
@@ -43,6 +43,7 @@ Singleton {
property int revertGeneration: -1
property bool externalChangeBlocked: false
property int secondsLeft: 0
property bool identifying: false
readonly property bool awaitingConfirmation: root.pendingRequestedLayout !== null
readonly property bool canConfirm: root.awaitingConfirmation
@@ -123,6 +124,11 @@ Singleton {
return false;
}
function identify(): void {
root.identifying = true;
identifyTimer.restart();
}
function parse(text: string, generation: int): void {
try {
const raw = JSON.parse(text);
@@ -520,6 +526,13 @@ Singleton {
root.lastError = "The previous display setting could not be verified. Open Displays and restore it manually.";
}
Timer {
id: identifyTimer
interval: 3000
repeat: false
onTriggered: root.identifying = false
}
Timer {
id: verifyTimer
property int attempts: 0
+2
View File
@@ -86,6 +86,8 @@ ShellRoot {
Osd {}
}
DisplayIdentify {}
// ── Single-instance overlays ────────────────────────────────────────────
// These are always constructed but only *visible* when ShellState says so.
// They're cheap while hidden, and keeping them alive means opening the