Compare commits

..

No commits in common. "e45f412930edeedfc39f9df0da93ce54d64454f2" and "608854ba03932e7e79e45707509422a637d3deb1" have entirely different histories.

20 changed files with 146 additions and 63 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View file

@ -1,4 +0,0 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" height="512px" viewBox="0 -960 960 960" width="512px" fill="#787c99">
<path d="M560-360q17 0 29.5-12.5T602-402q0-17-12.5-29.5T560-444q-17 0-29.5 12.5T518-402q0 17 12.5 29.5T560-360Zm-30-128h60q0-29 6-42.5t28-35.5q30-30 40-48.5t10-43.5q0-45-31.5-73.5T560-760q-41 0-71.5 23T446-676l54 22q9-25 24.5-37.5T560-704q24 0 39 13.5t15 36.5q0 14-8 26.5T578-596q-33 29-40.5 45.5T530-488ZM320-240q-33 0-56.5-23.5T240-320v-480q0-33 23.5-56.5T320-880h480q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H320Zm0-80h480v-480H320v480ZM160-80q-33 0-56.5-23.5T80-160v-560h80v560h560v80H160Zm160-720v480-480Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 663 B

View file

@ -161,8 +161,6 @@ Singleton {
} }
readonly property QtObject services: QtObject { readonly property QtObject services: QtObject {
readonly property real batteryWarning: 0.15
readonly property string weatherLocation: "" readonly property string weatherLocation: ""
readonly property bool useFahrenheit: [Locale.ImperialUSSystem, Locale.ImperialSystem].includes(Qt.locale().measurementSystem) readonly property bool useFahrenheit: [Locale.ImperialUSSystem, Locale.ImperialSystem].includes(Qt.locale().measurementSystem)
@ -171,8 +169,6 @@ Singleton {
readonly property string sunsetFrom: "21:00" readonly property string sunsetFrom: "21:00"
readonly property string sunsetTo: "9:00" readonly property string sunsetTo: "9:00"
readonly property int sunsetTemperature: 4500 readonly property int sunsetTemperature: 4500
readonly property real brightnessExp: 4.0
} }
readonly property QtObject session: QtObject { readonly property QtObject session: QtObject {

View file

@ -95,7 +95,7 @@ Container {
readonly property bool hasBattery: UPower.displayDevice.isLaptopBattery readonly property bool hasBattery: UPower.displayDevice.isLaptopBattery
readonly property real percentage: UPower.displayDevice.percentage readonly property real percentage: UPower.displayDevice.percentage
readonly property bool charging: !UPower.onBattery && batteryText.text !== "100" readonly property bool charging: !UPower.onBattery && batteryText.text !== "100"
readonly property bool warning: UPower.onBattery && percentage < Config.services.batteryWarning + 0.01 readonly property bool warning: UPower.onBattery && percentage < 0.15
text: { text: {
if (!hasBattery) { if (!hasBattery) {
@ -142,7 +142,7 @@ Container {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 0.5 anchors.verticalCenterOffset: 0.5
text: Math.floor(battery.percentage * 100) text: Math.round(battery.percentage * 100)
color: battery.warning ? Config.colors.batteryWarning : Config.colors.bg color: battery.warning ? Config.colors.batteryWarning : Config.colors.bg
font.family: Config.font.family.mono font.family: Config.font.family.mono
font.pointSize: 6 font.pointSize: 6

View file

@ -73,13 +73,6 @@ Item {
property: "scale" property: "scale"
to: 1 to: 1
} }
// Fixes really weird transition bug
NumberAnimation {
targets: header
property: "height"
to: Config.font.size.normal
duration: 20
}
} }
// Reveal on window title change // Reveal on window title change
@ -118,7 +111,6 @@ Item {
anchors.right: infobox.right anchors.right: infobox.right
anchors.top: infobox.top anchors.top: infobox.top
anchors.margins: 12 anchors.margins: 12
anchors.topMargin: 11
} }
} }

View file

@ -13,15 +13,14 @@ ColumnLayout {
spacing: 4 spacing: 4
readonly property bool hasBattery: UPower.displayDevice.isLaptopBattery readonly property color color: UPower.onBattery && UPower.displayDevice.percentage < 0.15 ?
readonly property real percentage: UPower.displayDevice.percentage Config.colors.batteryWarning :
readonly property bool warning: UPower.onBattery && percentage < Config.services.batteryWarning + 0.01 Config.colors.battery
readonly property color color: warning ? Config.colors.batteryWarning : Config.colors.battery
Loader { Loader {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
active: root.hasBattery active: UPower.displayDevice.isLaptopBattery
asynchronous: true asynchronous: true
height: active ? (item?.implicitHeight ?? 0) : 0 height: active ? (item?.implicitHeight ?? 0) : 0
@ -77,7 +76,7 @@ ColumnLayout {
radiusX: (meter.size + meter.thickness) / 2 + meter.padding radiusX: (meter.size + meter.thickness) / 2 + meter.padding
radiusY: radiusX radiusY: radiusX
startAngle: -90 - meter.angle / 2 startAngle: -90 - meter.angle / 2
sweepAngle: meter.angle * root.percentage sweepAngle: meter.angle * UPower.displayDevice.percentage
} }
Behavior on strokeColor { Behavior on strokeColor {
@ -99,7 +98,7 @@ ColumnLayout {
CustomText { CustomText {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: Math.floor(root.percentage * 100) + "%" text: Math.round(UPower.displayDevice.percentage * 100) + "%"
font.pointSize: Config.font.size.largest font.pointSize: Config.font.size.largest
} }

View file

@ -67,7 +67,7 @@ Item {
name: "battery" name: "battery"
source: "Battery.qml" source: "Battery.qml"
color: UPower.displayDevice.isLaptopBattery && color: UPower.displayDevice.isLaptopBattery &&
UPower.onBattery && UPower.displayDevice.percentage < Config.services.batteryWarning + 0.01 ? UPower.onBattery && UPower.displayDevice.percentage < 0.15 ?
Config.colors.batteryWarning : Config.colors.batteryWarning :
Config.colors.battery Config.colors.battery
} }

View file

@ -13,6 +13,7 @@ Item {
id: root id: root
required property PersistentProperties uiState required property PersistentProperties uiState
required property ShellScreen screen
readonly property real nonAnimWidth: content.implicitWidth readonly property real nonAnimWidth: content.implicitWidth
readonly property real nonAnimHeight: y > 0 || hasCurrent ? content.implicitHeight : 0 readonly property real nonAnimHeight: y > 0 || hasCurrent ? content.implicitHeight : 0

View file

@ -110,8 +110,8 @@ Item {
source: { source: {
const icon = entry.modelData.properties["application.icon-name"]; const icon = entry.modelData.properties["application.icon-name"];
if (icon) if (icon)
return Icons.getAppIcon(icon, "icon-missing"); return Icons.getAppIcon(icon, "image-missing");
Icons.getAppIcon(entry.modelData.name, "icon-missing") Icons.getAppIcon(entry.modelData.name, "image-missing")
} }
} }

View file

@ -290,7 +290,6 @@ Item {
property var ipc: modelData.lastIpcObject property var ipc: modelData.lastIpcObject
opacity: ipc && ipc.at && !ipc.hidden ? 1 : 0 opacity: ipc && ipc.at && !ipc.hidden ? 1 : 0
visible: opacity > 0
property real nonAnimX: ipc?.at ? (ipc.at[0] - preview.monX) * preview.sizeRatio : 0 property real nonAnimX: ipc?.at ? (ipc.at[0] - preview.monX) * preview.sizeRatio : 0
property real nonAnimY: ipc?.at ? (ipc.at[1] - preview.monY) * preview.sizeRatio : 0 property real nonAnimY: ipc?.at ? (ipc.at[1] - preview.monY) * preview.sizeRatio : 0

View file

@ -83,6 +83,7 @@ Item {
anchors.left: parent.right anchors.left: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.bottomMargin: 1
animate: true animate: true
text: Weather.feelsLike text: Weather.feelsLike

View file

@ -37,7 +37,7 @@ Item {
IconImage { IconImage {
id: icon id: icon
source: Quickshell.iconPath(root.modelData?.icon, "icon-missing") source: Quickshell.iconPath(root.modelData?.icon, "image-missing")
implicitSize: parent.height * 0.9 implicitSize: parent.height * 0.9
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter

View file

@ -11,6 +11,7 @@ Item {
id: root id: root
required property var uiState required property var uiState
required property Brightness.Monitor monitor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
@ -94,10 +95,13 @@ Item {
implicitHeight: Config.osd.sliderLength implicitHeight: Config.osd.sliderLength
function onWheel(event: WheelEvent) { function onWheel(event: WheelEvent) {
const monitor = root.monitor;
if (!monitor)
return;
if (event.angleDelta.y > 0) if (event.angleDelta.y > 0)
Brightness.setBrightness(Brightness.brightness + 0.1); monitor.setBrightness(monitor.brightness + 0.1);
else if (event.angleDelta.y < 0) else if (event.angleDelta.y < 0)
Brightness.setBrightness(Brightness.brightness - 0.1); monitor.setBrightness(monitor.brightness - 0.1);
} }
CustomFilledSlider { CustomFilledSlider {
@ -105,8 +109,8 @@ Item {
color: Config.colors.brightness color: Config.colors.brightness
icon: Icons.getBrightnessIcon(value) icon: Icons.getBrightnessIcon(value)
value: Brightness.brightness value: root.monitor?.brightness ?? 0
onMoved: Brightness.setBrightness(value) onMoved: root.monitor?.setBrightness(value)
} }
} }
} }

View file

@ -7,8 +7,10 @@ Scope {
id: root id: root
required property PersistentProperties uiState required property PersistentProperties uiState
required property ShellScreen screen
required property bool hovered required property bool hovered
required property bool suppressed required property bool suppressed
readonly property Brightness.Monitor monitor: Brightness.getMonitorForScreen(screen)
function show(): void { function show(): void {
if (!root.suppressed) { if (!root.suppressed) {
@ -32,7 +34,7 @@ Scope {
} }
Connections { Connections {
target: Brightness target: root.monitor
function onBrightnessChanged(): void { function onBrightnessChanged(): void {
if (root.uiState.osdBrightnessReact) if (root.uiState.osdBrightnessReact)

View file

@ -8,6 +8,7 @@ Item {
id: root id: root
required property var uiState required property var uiState
required property ShellScreen screen
visible: width > 0 visible: width > 0
implicitWidth: 0 implicitWidth: 0
@ -60,5 +61,6 @@ Item {
id: content id: content
uiState: root.uiState uiState: root.uiState
monitor: Brightness.getMonitorForScreen(root.screen)
} }
} }

View file

@ -62,10 +62,6 @@ CustomMouseArea {
if (y < Config.bar.height && !popoutsSuppressed && !popouts.persistent) { if (y < Config.bar.height && !popoutsSuppressed && !popouts.persistent) {
bar.checkPopout(x); bar.checkPopout(x);
} }
// Hide bar popouts (if user moves mouse along edge)
if (y > popouts.nonAnimHeight + Config.bar.height) {
popouts.hasCurrent = false;
}
// Show osd on hover // Show osd on hover
const showOsd = inRightPanel(panels.osd, x, y); const showOsd = inRightPanel(panels.osd, x, y);
@ -120,6 +116,7 @@ CustomMouseArea {
Osd.Interactions { Osd.Interactions {
uiState: root.uiState uiState: root.uiState
screen: root.screen
hovered: root.osdHovered hovered: root.osdHovered
suppressed: root.osdSuppressed suppressed: root.osdSuppressed
} }

View file

@ -13,6 +13,7 @@ Item {
id: root id: root
required property PersistentProperties uiState required property PersistentProperties uiState
required property ShellScreen screen
required property Item bar required property Item bar
readonly property alias popouts: popouts readonly property alias popouts: popouts
@ -30,12 +31,14 @@ Item {
id: popouts id: popouts
uiState: root.uiState uiState: root.uiState
screen: root.screen
} }
Osd.Wrapper { Osd.Wrapper {
id: osd id: osd
uiState: root.uiState uiState: root.uiState
screen: root.screen
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right

View file

@ -110,6 +110,7 @@ Variants {
visible: !uiState.uiState.hidden visible: !uiState.uiState.hidden
uiState: uiState.uiState uiState: uiState.uiState
screen: scope.modelData
bar: bar bar: bar
} }
} }

View file

@ -55,9 +55,6 @@ in stdenv.mkDerivation {
cp -R . $out/share/${pname} cp -R . $out/share/${pname}
mkdir -p $out/share/icons/hicolor/512x512/apps/
cp assets/icon-missing.png $out/share/icons/hicolor/512x512/apps/
makeWrapper ${quickshell}/bin/qs $out/bin/${pname} \ makeWrapper ${quickshell}/bin/qs $out/bin/${pname} \
--prefix PATH : "${lib.makeBinPath runtimeDeps}" \ --prefix PATH : "${lib.makeBinPath runtimeDeps}" \
--set FONTCONFIG_FILE "${fontconfig}" \ --set FONTCONFIG_FILE "${fontconfig}" \

View file

@ -12,39 +12,59 @@ Singleton {
reloadableId: "brightness" reloadableId: "brightness"
property real brightness: 1.0 property list<var> ddcMonitors: []
property real maxBrightness: 0.0 readonly property list<Monitor> monitors: variants.instances
property bool appleDisplayPresent: false
function getMonitorForScreen(screen: ShellScreen): var {
return monitors.find(m => m.modelData === screen);
}
function increaseBrightness(): void { function increaseBrightness(): void {
setBrightness(brightness + Config.osd.brightnessIncrement); const focusedName = Hypr.focusedMonitor.name;
const monitor = monitors.find(m => focusedName === m.modelData.name);
if (monitor)
monitor.setBrightness(monitor.brightness + Config.osd.brightnessIncrement);
} }
function decreaseBrightness(): void { function decreaseBrightness(): void {
setBrightness(brightness - Config.osd.brightnessIncrement); const focusedName = Hypr.focusedMonitor.name;
const monitor = monitors.find(m => focusedName === m.modelData.name);
if (monitor)
monitor.setBrightness(monitor.brightness - Config.osd.brightnessIncrement);
} }
function setBrightness(value: real): void { onMonitorsChanged: {
value = Math.max(0, Math.min(1, value)); ddcMonitors = [];
if (Math.abs(brightness - value) < 0.01) return; ddcProc.running = true;
brightness = value; }
const exp = Config.services.brightnessExp; Variants {
const raw = Math.round((value ** exp) * maxBrightness); id: variants
Quickshell.execDetached(["brightnessctl", "s", `${raw}`]);
model: Quickshell.screens
Monitor {}
} }
Component.onCompleted: initProc.running = true
Process { Process {
id: initProc running: true
command: ["sh", "-c", "echo $(brightnessctl g) $(brightnessctl m)"] command: ["sh", "-c", "asdbctl get"] // To avoid warnings if asdbctl is not installed
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: root.appleDisplayPresent = text.trim().length > 0
const exp = Config.services.brightnessExp;
const [cur, max] = text.split(" ");
root.maxBrightness = parseInt(max);
root.brightness = (parseInt(cur) / root.maxBrightness) ** (1 / exp);
} }
} }
Process {
id: ddcProc
command: ["ddcutil", "detect", "--brief"]
stdout: StdioCollector {
onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({
model: d.match(/Monitor:.*:(.*):.*/)[1],
busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1]
}))
}
} }
CustomShortcut { CustomShortcut {
@ -90,4 +110,77 @@ Singleton {
root.decreaseBrightness(); root.decreaseBrightness();
} }
} }
component Monitor: QtObject {
id: monitor
required property ShellScreen modelData
readonly property bool isDdc: root.ddcMonitors.some(m => m.model === modelData.model)
readonly property string busNum: root.ddcMonitors.find(m => m.model === modelData.model)?.busNum ?? ""
readonly property bool isAppleDisplay: root.appleDisplayPresent && modelData.model.startsWith("StudioDisplay")
property real brightness
property real queuedBrightness: NaN
readonly property Process initProc: Process {
stdout: StdioCollector {
onStreamFinished: {
if (monitor.isAppleDisplay) {
const val = parseInt(text.trim());
monitor.brightness = val / 101;
} else {
const [, , , cur, max] = text.split(" ");
monitor.brightness = parseInt(cur) / parseInt(max);
}
}
}
}
readonly property Timer timer: Timer {
interval: 500
onTriggered: {
if (!isNaN(monitor.queuedBrightness)) {
monitor.setBrightness(monitor.queuedBrightness);
monitor.queuedBrightness = NaN;
}
}
}
function setBrightness(value: real): void {
value = Math.max(0, Math.min(1, value));
const rounded = Math.round(value * 100);
if (Math.round(brightness * 100) === rounded)
return;
if (isDdc && timer.running) {
queuedBrightness = value;
return;
}
brightness = value;
if (isAppleDisplay)
Quickshell.execDetached(["asdbctl", "set", rounded]);
else if (isDdc)
Quickshell.execDetached(["ddcutil", "-b", busNum, "setvcp", "10", rounded]);
else
Quickshell.execDetached(["brightnessctl", "s", `${rounded}%`]);
if (isDdc)
timer.restart();
}
function initBrightness(): void {
if (isAppleDisplay)
initProc.command = ["asdbctl", "get"];
else if (isDdc)
initProc.command = ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"];
else
initProc.command = ["sh", "-c", "echo a b c $(brightnessctl g) $(brightnessctl m)"];
initProc.running = true;
}
onBusNumChanged: initBrightness()
Component.onCompleted: initBrightness()
}
} }