quickshell: shared controls under one cog dropdown

Screen recorder was desktop-only, caffeine laptop-only, nightlight in
both places. Cog dropdown now holds recorder + nightlight on every host;
battery dropdown keeps the laptop-only power profile and brightness.
Caffeine stays gated: hypridle is mkIf isMacbook.
This commit is contained in:
rope 2026-08-30 13:20:49 +01:00
parent 9b8e0b5242
commit ba4c32d852

View file

@ -4703,7 +4703,6 @@ in
let pos = batteryWidget.mapToItem(bar.contentItem, 0, batteryWidget.height / 2); let pos = batteryWidget.mapToItem(bar.contentItem, 0, batteryWidget.height / 2);
batteryDropdown.dropdownY = pos.y; batteryDropdown.dropdownY = pos.y;
brightRead.running = true; // refresh sliders on open brightRead.running = true; // refresh sliders on open
caffRead.running = true; // and the caffeine state
}); });
} }
@ -4720,9 +4719,8 @@ in
} }
''} ''}
${lib.optionalString (!isMacbook) '' // Quick settings present on every host, so the shared
// Quick settings (night light) no battery widget on the // controls sit in the same place on all of them.
// desktop, so the card gets its own bar icon.
Item { Item {
id: qsWidget id: qsWidget
width: Theme.barWidth width: Theme.barWidth
@ -4736,7 +4734,7 @@ in
// Doubles as the recording indicator: with the // Doubles as the recording indicator: with the
// dropdown shut, this dot is the only sign that // dropdown shut, this dot is the only sign that
// wf-recorder is still running. // wf-recorder is still running.
text: recCard.recording ? "circle-dot" : "moon" text: recCard.recording ? "circle-dot" : "cog"
color: recCard.recording ? Theme.err : Theme.base05 color: recCard.recording ? Theme.err : Theme.base05
font.pixelSize: 18 font.pixelSize: 18
} }
@ -4745,6 +4743,8 @@ in
bar.toggleDropdown(qsDropdown, function() { bar.toggleDropdown(qsDropdown, function() {
let pos = qsWidget.mapToItem(bar.contentItem, 0, qsWidget.height / 2); let pos = qsWidget.mapToItem(bar.contentItem, 0, qsWidget.height / 2);
qsDropdown.dropdownY = pos.y; qsDropdown.dropdownY = pos.y;
${lib.optionalString isMacbook
"caffRead.running = true; // hypridle may have been restarted"}
}); });
} }
@ -4759,7 +4759,6 @@ in
} }
} }
} }
''}
// Group separator: status icons / tray / power read // Group separator: status icons / tray / power read
// as three clusters instead of one clump. // as three clusters instead of one clump.
@ -6141,56 +6140,6 @@ in
} }
} }
// Caffeine card parks hypridle so nothing locks,
// blanks or suspends. State is re-read on open, so a
// hypridle restart can't leave the switch lying.
Card {
id: caffCard
width: parent.width
property bool on: false
Item {
width: parent.width
height: 20
Row {
spacing: 6
anchors.verticalCenter: parent.verticalCenter
SIcon {
anchors.verticalCenter: parent.verticalCenter
text: "coffee"
color: caffCard.on ? Theme.base0D : Theme.base05
font.pixelSize: 15
}
SText {
anchors.verticalCenter: parent.verticalCenter
text: "Caffeine"
font.weight: Font.Medium
}
}
ToggleSwitch {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
on: caffCard.on
onToggled: (v) => {
caffCard.on = v;
caffSet.command = [Commands.systemctl, "--user", v ? "stop" : "start", "hypridle.service"];
caffSet.running = true;
}
}
}
Process { id: caffSet }
Process {
id: caffRead
command: [Commands.systemctl, "--user", "is-active", "hypridle.service"]
stdout: StdioCollector {
// is-active exits non-zero when stopped; the
// word on stdout is what matters here.
onStreamFinished: caffCard.on = text.trim() !== "active"
}
}
}
// Brightness card screen + keyboard backlight. // Brightness card screen + keyboard backlight.
// Values are read on dropdown open (brightRead); writes // Values are read on dropdown open (brightRead); writes
// are debounced latest-wins so a drag doesn't spawn a // are debounced latest-wins so a drag doesn't spawn a
@ -6252,14 +6201,12 @@ in
} }
} }
} }
NightlightCard { width: parent.width }
} }
} }
''} ''}
${lib.optionalString (!isMacbook) '' // Quick settings dropdown everything supported on both
// Quick settings dropdown (desktop) just the night light. // hosts. Laptop-only controls stay in the battery dropdown.
BarDropdown { BarDropdown {
id: qsDropdown id: qsDropdown
fullWidth: qsCol.width + 2 * Theme.panelGap fullWidth: qsCol.width + 2 * Theme.panelGap
@ -6484,10 +6431,65 @@ in
} }
} }
${lib.optionalString isMacbook ''
// Caffeine card parks hypridle so nothing locks,
// blanks or suspends. State is re-read on open, so a
// hypridle restart can't leave the switch lying.
// Macbook only: hypridle is mkIf isMacbook in
// settings/hyprland.nix, so on a host without it the
// switch would toggle a unit that isn't there and sit
// permanently "on".
Card {
id: caffCard
width: parent.width
property bool on: false
Item {
width: parent.width
height: 20
Row {
spacing: 6
anchors.verticalCenter: parent.verticalCenter
SIcon {
anchors.verticalCenter: parent.verticalCenter
text: "coffee"
color: caffCard.on ? Theme.base0D : Theme.base05
font.pixelSize: 15
}
SText {
anchors.verticalCenter: parent.verticalCenter
text: "Caffeine"
font.weight: Font.Medium
}
}
ToggleSwitch {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
on: caffCard.on
onToggled: (v) => {
caffCard.on = v;
caffSet.command = [Commands.systemctl, "--user", v ? "stop" : "start", "hypridle.service"];
caffSet.running = true;
}
}
}
Process { id: caffSet }
Process {
id: caffRead
command: [Commands.systemctl, "--user", "is-active", "hypridle.service"]
stdout: StdioCollector {
// is-active exits non-zero when stopped; the
// word on stdout is what matters here.
onStreamFinished: caffCard.on = text.trim() !== "active"
}
}
}
''}
NightlightCard { width: parent.width } NightlightCard { width: parent.width }
} }
} }
''}
// Calendar popup GNOME-style two-pane panel. // Calendar popup GNOME-style two-pane panel.
// Left: navigable month calendar + 7-day weather strip. // Left: navigable month calendar + 7-day weather strip.