mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
@@ -11,6 +11,8 @@ require (
|
|||||||
github.com/fsnotify/fsnotify v1.9.0
|
github.com/fsnotify/fsnotify v1.9.0
|
||||||
github.com/godbus/dbus/v5 v5.2.0
|
github.com/godbus/dbus/v5 v5.2.0
|
||||||
github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83
|
github.com/holoplot/go-evdev v0.0.0-20250804134636-ab1d56a1fe83
|
||||||
|
github.com/pilebones/go-udev v0.9.1
|
||||||
|
github.com/sblinch/kdl-go v0.0.0-20250930225324-bf4099d4614a
|
||||||
github.com/spf13/cobra v1.10.1
|
github.com/spf13/cobra v1.10.1
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39
|
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39
|
||||||
@@ -32,7 +34,6 @@ require (
|
|||||||
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
github.com/kevinburke/ssh_config v1.4.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
github.com/pjbgf/sha1cd v0.5.0 // indirect
|
||||||
github.com/sblinch/kdl-go v0.0.0-20250930225324-bf4099d4614a // indirect
|
|
||||||
github.com/sergi/go-diff v1.4.0 // indirect
|
github.com/sergi/go-diff v1.4.0 // indirect
|
||||||
github.com/stretchr/objx v0.5.3 // indirect
|
github.com/stretchr/objx v0.5.3 // indirect
|
||||||
golang.org/x/crypto v0.45.0 // indirect
|
golang.org/x/crypto v0.45.0 // indirect
|
||||||
|
|||||||
20
core/go.sum
20
core/go.sum
@@ -24,16 +24,12 @@ github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoF
|
|||||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||||
github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
|
github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
|
||||||
github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
|
github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
|
||||||
github.com/charmbracelet/x/ansi v0.11.0 h1:uuIVK7GIplwX6UBIz8S2TF8nkr7xRlygSsBRjSJqIvA=
|
|
||||||
github.com/charmbracelet/x/ansi v0.11.0/go.mod h1:uQt8bOrq/xgXjlGcFMc8U2WYbnxyjrKhnvTQluvfCaE=
|
|
||||||
github.com/charmbracelet/x/ansi v0.11.2 h1:XAG3FSjiVtFvgEgGrNBkCNNYrsucAt8c6bfxHyROLLs=
|
github.com/charmbracelet/x/ansi v0.11.2 h1:XAG3FSjiVtFvgEgGrNBkCNNYrsucAt8c6bfxHyROLLs=
|
||||||
github.com/charmbracelet/x/ansi v0.11.2/go.mod h1:9tY2bzX5SiJCU0iWyskjBeI2BRQfvPqI+J760Mjf+Rg=
|
github.com/charmbracelet/x/ansi v0.11.2/go.mod h1:9tY2bzX5SiJCU0iWyskjBeI2BRQfvPqI+J760Mjf+Rg=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4=
|
github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA=
|
github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA=
|
||||||
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
|
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
|
||||||
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||||
github.com/clipperhouse/displaywidth v0.5.0 h1:AIG5vQaSL2EKqzt0M9JMnvNxOCRTKUc4vUnLWGgP89I=
|
|
||||||
github.com/clipperhouse/displaywidth v0.5.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
|
|
||||||
github.com/clipperhouse/displaywidth v0.6.0 h1:k32vueaksef9WIKCNcoqRNyKbyvkvkysNYnAWz2fN4s=
|
github.com/clipperhouse/displaywidth v0.6.0 h1:k32vueaksef9WIKCNcoqRNyKbyvkvkysNYnAWz2fN4s=
|
||||||
github.com/clipperhouse/displaywidth v0.6.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
|
github.com/clipperhouse/displaywidth v0.6.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
|
||||||
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
|
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
|
||||||
@@ -43,8 +39,6 @@ github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsV
|
|||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/cyphar/filepath-securejoin v0.6.0 h1:BtGB77njd6SVO6VztOHfPxKitJvd/VPT+OFBFMOi1Is=
|
|
||||||
github.com/cyphar/filepath-securejoin v0.6.0/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
|
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
|
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
|
||||||
github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
|
github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -62,19 +56,14 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
|||||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||||
github.com/go-git/gcfg/v2 v2.0.2 h1:MY5SIIfTGGEMhdA7d7JePuVVxtKL7Hp+ApGDJAJ7dpo=
|
github.com/go-git/gcfg/v2 v2.0.2 h1:MY5SIIfTGGEMhdA7d7JePuVVxtKL7Hp+ApGDJAJ7dpo=
|
||||||
github.com/go-git/gcfg/v2 v2.0.2/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs=
|
github.com/go-git/gcfg/v2 v2.0.2/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs=
|
||||||
github.com/go-git/go-billy/v6 v6.0.0-20251111123000-fb5ff8f3f0b0 h1:EC9n6hr6yKDoVJ6g7Ko523LbbceJfR0ohbOp809Fyf4=
|
|
||||||
github.com/go-git/go-billy/v6 v6.0.0-20251111123000-fb5ff8f3f0b0/go.mod h1:E3VhlS+AKkrq6ZNn1axE2/nDRJ87l1FJk9r5HT2vPX0=
|
|
||||||
github.com/go-git/go-billy/v6 v6.0.0-20251126203821-7f9c95185ee0 h1:eY5aB2GXiVdgTueBcqsBt53WuJTRZAuCdIS/86Pcq5c=
|
github.com/go-git/go-billy/v6 v6.0.0-20251126203821-7f9c95185ee0 h1:eY5aB2GXiVdgTueBcqsBt53WuJTRZAuCdIS/86Pcq5c=
|
||||||
github.com/go-git/go-billy/v6 v6.0.0-20251126203821-7f9c95185ee0/go.mod h1:0NjwVNrwtVFZBReAp5OoGklGJIgJFEbVyHneAr4lc8k=
|
github.com/go-git/go-billy/v6 v6.0.0-20251126203821-7f9c95185ee0/go.mod h1:0NjwVNrwtVFZBReAp5OoGklGJIgJFEbVyHneAr4lc8k=
|
||||||
github.com/go-git/go-git-fixtures/v5 v5.1.1 h1:OH8i1ojV9bWfr0ZfasfpgtUXQHQyVS8HXik/V1C099w=
|
github.com/go-git/go-git-fixtures/v5 v5.1.1 h1:OH8i1ojV9bWfr0ZfasfpgtUXQHQyVS8HXik/V1C099w=
|
||||||
github.com/go-git/go-git-fixtures/v5 v5.1.1/go.mod h1:Altk43lx3b1ks+dVoAG2300o5WWUnktvfY3VI6bcaXU=
|
github.com/go-git/go-git-fixtures/v5 v5.1.1/go.mod h1:Altk43lx3b1ks+dVoAG2300o5WWUnktvfY3VI6bcaXU=
|
||||||
github.com/go-git/go-git/v6 v6.0.0-20251112161705-8cc3e21f07a9 h1:SOFrnF9LCssC6q6Rb0084Bzg2aBYbe8QXv9xKGXmt/w=
|
|
||||||
github.com/go-git/go-git/v6 v6.0.0-20251112161705-8cc3e21f07a9/go.mod h1:0wtvm/JfPC9RFVEAP3ks0ec5h64/qmZkTTUE3pjz7Hc=
|
|
||||||
github.com/go-git/go-git/v6 v6.0.0-20251128074608-48f817f57805 h1:jxQ3BzYeErNRvlI/4+0mpwqMzvB4g97U+ksfgvrUEbY=
|
github.com/go-git/go-git/v6 v6.0.0-20251128074608-48f817f57805 h1:jxQ3BzYeErNRvlI/4+0mpwqMzvB4g97U+ksfgvrUEbY=
|
||||||
github.com/go-git/go-git/v6 v6.0.0-20251128074608-48f817f57805/go.mod h1:dIwT3uWK1ooHInyVnK2JS5VfQ3peVGYaw2QPqX7uFvs=
|
github.com/go-git/go-git/v6 v6.0.0-20251128074608-48f817f57805/go.mod h1:dIwT3uWK1ooHInyVnK2JS5VfQ3peVGYaw2QPqX7uFvs=
|
||||||
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
|
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
|
||||||
github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=
|
github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk=
|
||||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
|
||||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=
|
github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=
|
||||||
github.com/godbus/dbus/v5 v5.2.0/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
github.com/godbus/dbus/v5 v5.2.0/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
||||||
@@ -95,8 +84,9 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
|
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
|
||||||
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
@@ -111,6 +101,8 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
|
|||||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||||
|
github.com/pilebones/go-udev v0.9.1 h1:uN72M1C1fgzhsVmBGEM8w9RD1JY4iVsPZpr+Z6rb3O8=
|
||||||
|
github.com/pilebones/go-udev v0.9.1/go.mod h1:Bgcl07crebF3JSeS4+nuaRvhWFdCeFoBhXXeAp93XNo=
|
||||||
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
|
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
|
||||||
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
|
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -139,12 +131,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
|||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
|
||||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
|
||||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0=
|
|
||||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
|
|
||||||
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY=
|
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY=
|
||||||
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
|
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ func (m *Manager) initSysfs() {
|
|||||||
m.sysfsBackend = sysfs
|
m.sysfsBackend = sysfs
|
||||||
m.sysfsReady = true
|
m.sysfsReady = true
|
||||||
m.updateState()
|
m.updateState()
|
||||||
|
m.initUdev()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +66,11 @@ func (m *Manager) initSysfs() {
|
|||||||
m.sysfsBackend = sysfs
|
m.sysfsBackend = sysfs
|
||||||
m.sysfsReady = true
|
m.sysfsReady = true
|
||||||
m.updateState()
|
m.updateState()
|
||||||
|
m.initUdev()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) initUdev() {
|
||||||
|
m.udevMonitor = NewUdevMonitor(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) initDDC() {
|
func (m *Manager) initDDC() {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ type Manager struct {
|
|||||||
logindBackend *LogindBackend
|
logindBackend *LogindBackend
|
||||||
sysfsBackend *SysfsBackend
|
sysfsBackend *SysfsBackend
|
||||||
ddcBackend *DDCBackend
|
ddcBackend *DDCBackend
|
||||||
|
udevMonitor *UdevMonitor
|
||||||
|
|
||||||
logindReady bool
|
logindReady bool
|
||||||
sysfsReady bool
|
sysfsReady bool
|
||||||
@@ -181,6 +182,10 @@ func (m *Manager) Close() {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if m.udevMonitor != nil {
|
||||||
|
m.udevMonitor.Close()
|
||||||
|
}
|
||||||
|
|
||||||
if m.logindBackend != nil {
|
if m.logindBackend != nil {
|
||||||
m.logindBackend.Close()
|
m.logindBackend.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
148
core/internal/server/brightness/udev.go
Normal file
148
core/internal/server/brightness/udev.go
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
package brightness
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||||
|
"github.com/pilebones/go-udev/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UdevMonitor struct {
|
||||||
|
stop chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUdevMonitor(manager *Manager) *UdevMonitor {
|
||||||
|
m := &UdevMonitor{
|
||||||
|
stop: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
go m.run(manager)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UdevMonitor) run(manager *Manager) {
|
||||||
|
conn := &netlink.UEventConn{}
|
||||||
|
if err := conn.Connect(netlink.UdevEvent); err != nil {
|
||||||
|
log.Errorf("Failed to connect to udev netlink: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
matcher := &netlink.RuleDefinitions{
|
||||||
|
Rules: []netlink.RuleDefinition{
|
||||||
|
{Env: map[string]string{"SUBSYSTEM": "backlight"}},
|
||||||
|
{Env: map[string]string{"SUBSYSTEM": "leds"}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := matcher.Compile(); err != nil {
|
||||||
|
log.Errorf("Failed to compile udev matcher: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
events := make(chan netlink.UEvent)
|
||||||
|
errs := make(chan error)
|
||||||
|
conn.Monitor(events, errs, matcher)
|
||||||
|
|
||||||
|
log.Info("Udev monitor started for backlight/leds events")
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-m.stop:
|
||||||
|
return
|
||||||
|
case err := <-errs:
|
||||||
|
log.Errorf("Udev monitor error: %v", err)
|
||||||
|
return
|
||||||
|
case event := <-events:
|
||||||
|
m.handleEvent(manager, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UdevMonitor) handleEvent(manager *Manager, event netlink.UEvent) {
|
||||||
|
subsystem := event.Env["SUBSYSTEM"]
|
||||||
|
devpath := event.Env["DEVPATH"]
|
||||||
|
|
||||||
|
if subsystem == "" || devpath == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sysname := filepath.Base(devpath)
|
||||||
|
action := string(event.Action)
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case "change":
|
||||||
|
m.handleChange(manager, subsystem, sysname)
|
||||||
|
case "add", "remove":
|
||||||
|
log.Debugf("Udev %s event: %s:%s - triggering rescan", action, subsystem, sysname)
|
||||||
|
manager.Rescan()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UdevMonitor) handleChange(manager *Manager, subsystem, sysname string) {
|
||||||
|
deviceID := subsystem + ":" + sysname
|
||||||
|
|
||||||
|
if manager.sysfsBackend == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
brightnessPath := filepath.Join(manager.sysfsBackend.basePath, subsystem, sysname, "brightness")
|
||||||
|
data, err := os.ReadFile(brightnessPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Udev change event for %s but failed to read brightness: %v", deviceID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
brightness, err := strconv.Atoi(strings.TrimSpace(string(data)))
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Failed to parse brightness for %s: %v", deviceID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.handleUdevBrightnessChange(deviceID, brightness)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UdevMonitor) Close() {
|
||||||
|
close(m.stop)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) handleUdevBrightnessChange(deviceID string, rawBrightness int) {
|
||||||
|
if m.sysfsBackend == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dev, err := m.sysfsBackend.GetDevice(deviceID)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf("Udev event for unknown device %s: %v", deviceID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
percent := m.sysfsBackend.ValueToPercent(rawBrightness, dev, false)
|
||||||
|
|
||||||
|
m.stateMutex.Lock()
|
||||||
|
var found bool
|
||||||
|
for i, d := range m.state.Devices {
|
||||||
|
if d.ID != deviceID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
found = true
|
||||||
|
if d.Current == rawBrightness {
|
||||||
|
m.stateMutex.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.state.Devices[i].Current = rawBrightness
|
||||||
|
m.state.Devices[i].CurrentPercent = percent
|
||||||
|
break
|
||||||
|
}
|
||||||
|
m.stateMutex.Unlock()
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
log.Debugf("Udev event for device not in state: %s", deviceID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Udev brightness change: %s -> %d (%d%%)", deviceID, rawBrightness, percent)
|
||||||
|
m.broadcastDeviceUpdate(deviceID)
|
||||||
|
}
|
||||||
260
core/internal/server/brightness/udev_test.go
Normal file
260
core/internal/server/brightness/udev_test.go
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
package brightness
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pilebones/go-udev/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupTestManager(t *testing.T) (*Manager, string) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
backlightDir := filepath.Join(tmpDir, "backlight", "intel_backlight")
|
||||||
|
if err := os.MkdirAll(backlightDir, 0755); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(filepath.Join(backlightDir, "max_brightness"), []byte("1000\n"), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(filepath.Join(backlightDir, "brightness"), []byte("500\n"), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sysfs := &SysfsBackend{
|
||||||
|
basePath: tmpDir,
|
||||||
|
classes: []string{"backlight"},
|
||||||
|
}
|
||||||
|
if err := sysfs.scanDevices(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &Manager{
|
||||||
|
sysfsBackend: sysfs,
|
||||||
|
sysfsReady: true,
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
m.state = State{
|
||||||
|
Devices: []Device{
|
||||||
|
{
|
||||||
|
Class: ClassBacklight,
|
||||||
|
ID: "backlight:intel_backlight",
|
||||||
|
Name: "intel_backlight",
|
||||||
|
Current: 500,
|
||||||
|
Max: 1000,
|
||||||
|
CurrentPercent: 50,
|
||||||
|
Backend: "sysfs",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, tmpDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleUdevBrightnessChange_UpdatesState(t *testing.T) {
|
||||||
|
m, _ := setupTestManager(t)
|
||||||
|
|
||||||
|
m.handleUdevBrightnessChange("backlight:intel_backlight", 750)
|
||||||
|
|
||||||
|
state := m.GetState()
|
||||||
|
if len(state.Devices) != 1 {
|
||||||
|
t.Fatalf("expected 1 device, got %d", len(state.Devices))
|
||||||
|
}
|
||||||
|
|
||||||
|
dev := state.Devices[0]
|
||||||
|
if dev.Current != 750 {
|
||||||
|
t.Errorf("expected Current=750, got %d", dev.Current)
|
||||||
|
}
|
||||||
|
if dev.CurrentPercent != 75 {
|
||||||
|
t.Errorf("expected CurrentPercent=75, got %d", dev.CurrentPercent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleUdevBrightnessChange_NoChangeWhenSameValue(t *testing.T) {
|
||||||
|
m, _ := setupTestManager(t)
|
||||||
|
|
||||||
|
updateCh := m.SubscribeUpdates("test")
|
||||||
|
defer m.UnsubscribeUpdates("test")
|
||||||
|
|
||||||
|
m.handleUdevBrightnessChange("backlight:intel_backlight", 500)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-updateCh:
|
||||||
|
t.Error("should not broadcast when brightness unchanged")
|
||||||
|
case <-time.After(50 * time.Millisecond):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleUdevBrightnessChange_BroadcastsOnChange(t *testing.T) {
|
||||||
|
m, _ := setupTestManager(t)
|
||||||
|
|
||||||
|
updateCh := m.SubscribeUpdates("test")
|
||||||
|
defer m.UnsubscribeUpdates("test")
|
||||||
|
|
||||||
|
m.handleUdevBrightnessChange("backlight:intel_backlight", 750)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case update := <-updateCh:
|
||||||
|
if update.Device.Current != 750 {
|
||||||
|
t.Errorf("broadcast had wrong Current: got %d, want 750", update.Device.Current)
|
||||||
|
}
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
t.Error("expected broadcast on brightness change")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleUdevBrightnessChange_UnknownDevice(t *testing.T) {
|
||||||
|
m, _ := setupTestManager(t)
|
||||||
|
|
||||||
|
m.handleUdevBrightnessChange("backlight:unknown_device", 500)
|
||||||
|
|
||||||
|
state := m.GetState()
|
||||||
|
if len(state.Devices) != 1 {
|
||||||
|
t.Errorf("state should be unchanged, got %d devices", len(state.Devices))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleUdevBrightnessChange_NilSysfsBackend(t *testing.T) {
|
||||||
|
m := &Manager{
|
||||||
|
sysfsBackend: nil,
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
m.handleUdevBrightnessChange("backlight:test", 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleUdevBrightnessChange_DeviceNotInState(t *testing.T) {
|
||||||
|
m, _ := setupTestManager(t)
|
||||||
|
|
||||||
|
m.sysfsBackend.deviceCache.Store("backlight:other_device", &sysfsDevice{
|
||||||
|
class: ClassBacklight,
|
||||||
|
id: "backlight:other_device",
|
||||||
|
name: "other_device",
|
||||||
|
maxBrightness: 100,
|
||||||
|
minValue: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
m.handleUdevBrightnessChange("backlight:other_device", 50)
|
||||||
|
|
||||||
|
state := m.GetState()
|
||||||
|
for _, d := range state.Devices {
|
||||||
|
if d.ID == "backlight:other_device" {
|
||||||
|
t.Error("device should not be added to state via udev change event")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleEvent_ChangeAction(t *testing.T) {
|
||||||
|
m, tmpDir := setupTestManager(t)
|
||||||
|
um := &UdevMonitor{stop: make(chan struct{})}
|
||||||
|
|
||||||
|
brightnessPath := filepath.Join(tmpDir, "backlight", "intel_backlight", "brightness")
|
||||||
|
if err := os.WriteFile(brightnessPath, []byte("800\n"), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
event := netlink.UEvent{
|
||||||
|
Action: netlink.CHANGE,
|
||||||
|
Env: map[string]string{
|
||||||
|
"SUBSYSTEM": "backlight",
|
||||||
|
"DEVPATH": "/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
um.handleEvent(m, event)
|
||||||
|
|
||||||
|
state := m.GetState()
|
||||||
|
if state.Devices[0].Current != 800 {
|
||||||
|
t.Errorf("expected Current=800 after change event, got %d", state.Devices[0].Current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleEvent_MissingEnvVars(t *testing.T) {
|
||||||
|
m, _ := setupTestManager(t)
|
||||||
|
um := &UdevMonitor{stop: make(chan struct{})}
|
||||||
|
|
||||||
|
event := netlink.UEvent{
|
||||||
|
Action: netlink.CHANGE,
|
||||||
|
Env: map[string]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
um.handleEvent(m, event)
|
||||||
|
|
||||||
|
state := m.GetState()
|
||||||
|
if state.Devices[0].Current != 500 {
|
||||||
|
t.Error("state should be unchanged with missing env vars")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleEvent_MissingSubsystem(t *testing.T) {
|
||||||
|
m, _ := setupTestManager(t)
|
||||||
|
um := &UdevMonitor{stop: make(chan struct{})}
|
||||||
|
|
||||||
|
event := netlink.UEvent{
|
||||||
|
Action: netlink.CHANGE,
|
||||||
|
Env: map[string]string{
|
||||||
|
"DEVPATH": "/devices/foo/bar",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
um.handleEvent(m, event)
|
||||||
|
|
||||||
|
state := m.GetState()
|
||||||
|
if state.Devices[0].Current != 500 {
|
||||||
|
t.Error("state should be unchanged with missing SUBSYSTEM")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleChange_BrightnessFileNotFound(t *testing.T) {
|
||||||
|
m, _ := setupTestManager(t)
|
||||||
|
um := &UdevMonitor{stop: make(chan struct{})}
|
||||||
|
|
||||||
|
um.handleChange(m, "backlight", "nonexistent_device")
|
||||||
|
|
||||||
|
state := m.GetState()
|
||||||
|
if state.Devices[0].Current != 500 {
|
||||||
|
t.Error("state should be unchanged when brightness file not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleChange_InvalidBrightnessValue(t *testing.T) {
|
||||||
|
m, tmpDir := setupTestManager(t)
|
||||||
|
um := &UdevMonitor{stop: make(chan struct{})}
|
||||||
|
|
||||||
|
brightnessPath := filepath.Join(tmpDir, "backlight", "intel_backlight", "brightness")
|
||||||
|
if err := os.WriteFile(brightnessPath, []byte("not_a_number\n"), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
um.handleChange(m, "backlight", "intel_backlight")
|
||||||
|
|
||||||
|
state := m.GetState()
|
||||||
|
if state.Devices[0].Current != 500 {
|
||||||
|
t.Error("state should be unchanged with invalid brightness value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUdevMonitor_Close(t *testing.T) {
|
||||||
|
um := &UdevMonitor{stop: make(chan struct{})}
|
||||||
|
|
||||||
|
um.Close()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-um.stop:
|
||||||
|
default:
|
||||||
|
t.Error("stop channel should be closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleChange_NilSysfsBackend(t *testing.T) {
|
||||||
|
m := &Manager{
|
||||||
|
sysfsBackend: nil,
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
}
|
||||||
|
um := &UdevMonitor{stop: make(chan struct{})}
|
||||||
|
|
||||||
|
um.handleChange(m, "backlight", "test_device")
|
||||||
|
}
|
||||||
@@ -856,6 +856,13 @@ Singleton {
|
|||||||
return brightnessUserSetValues[deviceName];
|
return brightnessUserSetValues[deviceName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearBrightnessUserSetValue(deviceName) {
|
||||||
|
var newValues = Object.assign({}, brightnessUserSetValues);
|
||||||
|
delete newValues[deviceName];
|
||||||
|
brightnessUserSetValues = newValues;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
function setBrightnessExponent(deviceName, exponent) {
|
function setBrightnessExponent(deviceName, exponent) {
|
||||||
var newValues = Object.assign({}, brightnessExponentValues);
|
var newValues = Object.assign({}, brightnessExponentValues);
|
||||||
if (exponent !== undefined && exponent !== null) {
|
if (exponent !== undefined && exponent !== null) {
|
||||||
|
|||||||
@@ -159,7 +159,6 @@ Row {
|
|||||||
}
|
}
|
||||||
return targetDevice.displayMax || 100;
|
return targetDevice.displayMax || 100;
|
||||||
}
|
}
|
||||||
value: !isDragging ? targetBrightness : value
|
|
||||||
showValue: true
|
showValue: true
|
||||||
unit: {
|
unit: {
|
||||||
if (!targetDevice)
|
if (!targetDevice)
|
||||||
@@ -177,5 +176,10 @@ Row {
|
|||||||
}
|
}
|
||||||
thumbOutlineColor: Theme.surfaceContainer
|
thumbOutlineColor: Theme.surfaceContainer
|
||||||
trackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
trackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||||
|
|
||||||
|
Binding on value {
|
||||||
|
value: root.targetBrightness
|
||||||
|
when: !brightnessSlider.isDragging
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,11 +134,12 @@ BasePill {
|
|||||||
|
|
||||||
function handleBrightnessWheel(delta) {
|
function handleBrightnessWheel(delta) {
|
||||||
const deviceName = getPinnedBrightnessDevice();
|
const deviceName = getPinnedBrightnessDevice();
|
||||||
if (!deviceName)
|
if (!deviceName) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
const currentBrightness = DisplayService.getDeviceBrightness(deviceName);
|
const currentBrightness = DisplayService.getDeviceBrightness(deviceName);
|
||||||
const newBrightness = delta > 0 ? Math.min(100, currentBrightness + 5) : Math.max(1, currentBrightness - 5);
|
const newBrightness = delta > 0 ? Math.min(100, currentBrightness + 5) : Math.max(1, currentBrightness - 5);
|
||||||
DisplayService.setBrightness(newBrightness, deviceName, false);
|
DisplayService.setBrightness(newBrightness, deviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBatteryIconColor() {
|
function getBatteryIconColor() {
|
||||||
|
|||||||
@@ -107,7 +107,6 @@ DankOSD {
|
|||||||
}
|
}
|
||||||
thumbOutlineColor: Theme.surfaceContainer
|
thumbOutlineColor: Theme.surfaceContainer
|
||||||
alwaysShowValue: SettingsData.osdAlwaysShowValue
|
alwaysShowValue: SettingsData.osdAlwaysShowValue
|
||||||
value: !isDragging ? root.targetBrightness : value
|
|
||||||
|
|
||||||
onSliderValueChanged: newValue => {
|
onSliderValueChanged: newValue => {
|
||||||
if (DisplayService.brightnessAvailable) {
|
if (DisplayService.brightnessAvailable) {
|
||||||
@@ -119,6 +118,11 @@ DankOSD {
|
|||||||
onContainsMouseChanged: {
|
onContainsMouseChanged: {
|
||||||
setChildHovered(containsMouse);
|
setChildHovered(containsMouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binding on value {
|
||||||
|
value: root.targetBrightness
|
||||||
|
when: !brightnessSlider.isDragging
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +167,12 @@ DankOSD {
|
|||||||
y: gap * 2 + Theme.iconSize
|
y: gap * 2 + Theme.iconSize
|
||||||
|
|
||||||
property bool dragging: false
|
property bool dragging: false
|
||||||
property int value: !dragging ? root.targetBrightness : value
|
property int value: 50
|
||||||
|
|
||||||
|
Binding on value {
|
||||||
|
value: root.targetBrightness
|
||||||
|
when: !vertSlider.dragging
|
||||||
|
}
|
||||||
|
|
||||||
readonly property int minimum: {
|
readonly property int minimum: {
|
||||||
const deviceInfo = DisplayService.getCurrentDeviceInfo();
|
const deviceInfo = DisplayService.getCurrentDeviceInfo();
|
||||||
@@ -255,12 +264,14 @@ DankOSD {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateBrightness(mouse) {
|
function updateBrightness(mouse) {
|
||||||
if (DisplayService.brightnessAvailable) {
|
if (!DisplayService.brightnessAvailable) {
|
||||||
const ratio = 1.0 - (mouse.y / height);
|
return;
|
||||||
const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum));
|
|
||||||
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true);
|
|
||||||
resetHideTimer();
|
|
||||||
}
|
}
|
||||||
|
const ratio = 1.0 - (mouse.y / height);
|
||||||
|
const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum));
|
||||||
|
vertSlider.value = newValue;
|
||||||
|
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true);
|
||||||
|
resetHideTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ Singleton {
|
|||||||
property var deviceBrightness: ({})
|
property var deviceBrightness: ({})
|
||||||
property var deviceBrightnessUserSet: ({})
|
property var deviceBrightnessUserSet: ({})
|
||||||
property var deviceMaxCache: ({})
|
property var deviceMaxCache: ({})
|
||||||
|
property var userControlledDevices: ({})
|
||||||
|
property var pendingOsdDevices: ({})
|
||||||
property int brightnessVersion: 0
|
property int brightnessVersion: 0
|
||||||
property string currentDevice: ""
|
property string currentDevice: ""
|
||||||
property string lastIpcDevice: ""
|
property string lastIpcDevice: ""
|
||||||
@@ -28,6 +30,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
property int maxBrightness: 100
|
property int maxBrightness: 100
|
||||||
property bool brightnessInitialized: false
|
property bool brightnessInitialized: false
|
||||||
|
property bool suppressOsd: true
|
||||||
|
|
||||||
signal brightnessChanged(bool showOsd)
|
signal brightnessChanged(bool showOsd)
|
||||||
signal deviceSwitched
|
signal deviceSwitched
|
||||||
@@ -38,11 +41,47 @@ Singleton {
|
|||||||
property bool automationAvailable: false
|
property bool automationAvailable: false
|
||||||
property bool gammaControlAvailable: false
|
property bool gammaControlAvailable: false
|
||||||
|
|
||||||
|
function markDeviceUserControlled(deviceId) {
|
||||||
|
const newControlled = Object.assign({}, userControlledDevices);
|
||||||
|
newControlled[deviceId] = Date.now();
|
||||||
|
userControlledDevices = newControlled;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDeviceUserControlled(deviceId) {
|
||||||
|
const controlTime = userControlledDevices[deviceId];
|
||||||
|
if (!controlTime) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (Date.now() - controlTime) < 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDeviceUserControlled(deviceId) {
|
||||||
|
const newControlled = Object.assign({}, userControlledDevices);
|
||||||
|
delete newControlled[deviceId];
|
||||||
|
userControlledDevices = newControlled;
|
||||||
|
}
|
||||||
|
|
||||||
|
function markDevicePendingOsd(deviceId) {
|
||||||
|
const newPending = Object.assign({}, pendingOsdDevices);
|
||||||
|
newPending[deviceId] = true;
|
||||||
|
pendingOsdDevices = newPending;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDevicePendingOsd(deviceId) {
|
||||||
|
const newPending = Object.assign({}, pendingOsdDevices);
|
||||||
|
delete newPending[deviceId];
|
||||||
|
pendingOsdDevices = newPending;
|
||||||
|
}
|
||||||
|
|
||||||
function updateSingleDevice(device) {
|
function updateSingleDevice(device) {
|
||||||
|
const isUserControlled = isDeviceUserControlled(device.id);
|
||||||
|
if (isUserControlled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const deviceIndex = devices.findIndex(d => d.id === device.id);
|
const deviceIndex = devices.findIndex(d => d.id === device.id);
|
||||||
if (deviceIndex !== -1) {
|
if (deviceIndex !== -1) {
|
||||||
const newDevices = [...devices];
|
const newDevices = [...devices];
|
||||||
const existingDevice = devices[deviceIndex];
|
|
||||||
const cachedMax = deviceMaxCache[device.id];
|
const cachedMax = deviceMaxCache[device.id];
|
||||||
|
|
||||||
let displayMax = cachedMax || (device.class === "ddc" ? device.max : 100);
|
let displayMax = cachedMax || (device.class === "ddc" ? device.max : 100);
|
||||||
@@ -71,7 +110,17 @@ Singleton {
|
|||||||
let displayValue = device.currentPercent;
|
let displayValue = device.currentPercent;
|
||||||
if (isExponential) {
|
if (isExponential) {
|
||||||
if (userSetValue !== undefined) {
|
if (userSetValue !== undefined) {
|
||||||
displayValue = userSetValue;
|
const exponent = SessionData.getBrightnessExponent(device.id);
|
||||||
|
const expectedHardware = Math.round(Math.pow(userSetValue / 100.0, exponent) * 100.0);
|
||||||
|
if (Math.abs(device.currentPercent - expectedHardware) > 2) {
|
||||||
|
const newUserSet = Object.assign({}, deviceBrightnessUserSet);
|
||||||
|
delete newUserSet[device.id];
|
||||||
|
deviceBrightnessUserSet = newUserSet;
|
||||||
|
SessionData.clearBrightnessUserSetValue(device.id);
|
||||||
|
displayValue = linearToExponential(device.currentPercent, device.id);
|
||||||
|
} else {
|
||||||
|
displayValue = userSetValue;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
displayValue = linearToExponential(device.currentPercent, device.id);
|
displayValue = linearToExponential(device.currentPercent, device.id);
|
||||||
}
|
}
|
||||||
@@ -83,9 +132,22 @@ Singleton {
|
|||||||
deviceBrightness = newBrightness;
|
deviceBrightness = newBrightness;
|
||||||
brightnessVersion++;
|
brightnessVersion++;
|
||||||
|
|
||||||
if (oldValue !== undefined && oldValue !== displayValue && brightnessInitialized) {
|
const isPendingOsd = pendingOsdDevices[device.id] === true;
|
||||||
brightnessChanged(true);
|
if (isPendingOsd) {
|
||||||
|
clearDevicePendingOsd(device.id);
|
||||||
|
if (!suppressOsd) {
|
||||||
|
brightnessChanged(true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!brightnessInitialized || oldValue === displayValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (suppressOsd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
brightnessChanged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFromBrightnessState(state) {
|
function updateFromBrightnessState(state) {
|
||||||
@@ -167,13 +229,12 @@ Singleton {
|
|||||||
|
|
||||||
function setBrightness(percentage, device, suppressOsd) {
|
function setBrightness(percentage, device, suppressOsd) {
|
||||||
const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice());
|
const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice());
|
||||||
|
|
||||||
if (!actualDevice) {
|
if (!actualDevice) {
|
||||||
console.warn("DisplayService: No device selected for brightness change");
|
console.warn("DisplayService: No device selected for brightness change");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actualDevice && actualDevice !== lastIpcDevice) {
|
if (actualDevice !== lastIpcDevice) {
|
||||||
lastIpcDevice = actualDevice;
|
lastIpcDevice = actualDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,12 +244,15 @@ Singleton {
|
|||||||
let minValue = 0;
|
let minValue = 0;
|
||||||
let maxValue = 100;
|
let maxValue = 100;
|
||||||
|
|
||||||
if (isExponential) {
|
switch (true) {
|
||||||
|
case isExponential:
|
||||||
minValue = 1;
|
minValue = 1;
|
||||||
maxValue = 100;
|
maxValue = 100;
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0;
|
minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0;
|
||||||
maxValue = deviceInfo?.displayMax || 100;
|
maxValue = deviceInfo?.displayMax || 100;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxValue <= 0) {
|
if (maxValue <= 0) {
|
||||||
@@ -203,6 +267,12 @@ Singleton {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (suppressOsd) {
|
||||||
|
markDeviceUserControlled(actualDevice);
|
||||||
|
} else {
|
||||||
|
markDevicePendingOsd(actualDevice);
|
||||||
|
}
|
||||||
|
|
||||||
const newBrightness = Object.assign({}, deviceBrightness);
|
const newBrightness = Object.assign({}, deviceBrightness);
|
||||||
newBrightness[actualDevice] = clampedValue;
|
newBrightness[actualDevice] = clampedValue;
|
||||||
deviceBrightness = newBrightness;
|
deviceBrightness = newBrightness;
|
||||||
@@ -215,10 +285,6 @@ Singleton {
|
|||||||
SessionData.setBrightnessUserSetValue(actualDevice, clampedValue);
|
SessionData.setBrightnessUserSetValue(actualDevice, clampedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!suppressOsd) {
|
|
||||||
brightnessChanged(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
"device": actualDevice,
|
"device": actualDevice,
|
||||||
"percent": clampedValue
|
"percent": clampedValue
|
||||||
@@ -634,6 +700,13 @@ Singleton {
|
|||||||
brightnessChanged();
|
brightnessChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: osdSuppressTimer
|
||||||
|
interval: 2000
|
||||||
|
running: true
|
||||||
|
onTriggered: suppressOsd = false
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
nightModeEnabled = SessionData.nightModeEnabled;
|
nightModeEnabled = SessionData.nightModeEnabled;
|
||||||
deviceBrightnessUserSet = Object.assign({}, SessionData.brightnessUserSetValues);
|
deviceBrightnessUserSet = Object.assign({}, SessionData.brightnessUserSetValues);
|
||||||
@@ -674,6 +747,13 @@ Singleton {
|
|||||||
function onBrightnessDeviceUpdate(device) {
|
function onBrightnessDeviceUpdate(device) {
|
||||||
updateSingleDevice(device);
|
updateSingleDevice(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onLoginctlEvent(event) {
|
||||||
|
if (event.event === "unlock" || event.event === "resume") {
|
||||||
|
suppressOsd = true;
|
||||||
|
osdSuppressTimer.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session Data Connections
|
// Session Data Connections
|
||||||
@@ -746,7 +826,7 @@ Singleton {
|
|||||||
if (targetDevice && targetDevice !== root.currentDevice) {
|
if (targetDevice && targetDevice !== root.currentDevice) {
|
||||||
root.setCurrentDevice(targetDevice, false);
|
root.setCurrentDevice(targetDevice, false);
|
||||||
}
|
}
|
||||||
root.setBrightness(clampedValue, targetDevice, false);
|
root.setBrightness(clampedValue, targetDevice);
|
||||||
|
|
||||||
if (targetDevice) {
|
if (targetDevice) {
|
||||||
return "Brightness set to " + clampedValue + "% on " + targetDevice;
|
return "Brightness set to " + clampedValue + "% on " + targetDevice;
|
||||||
@@ -787,7 +867,7 @@ Singleton {
|
|||||||
|
|
||||||
const newBrightness = Math.min(maxValue, currentBrightness + stepValue);
|
const newBrightness = Math.min(maxValue, currentBrightness + stepValue);
|
||||||
|
|
||||||
root.setBrightness(newBrightness, actualDevice, false);
|
root.setBrightness(newBrightness, actualDevice);
|
||||||
|
|
||||||
return "Brightness increased by " + stepValue + "%" + (targetDevice ? " on " + targetDevice : "");
|
return "Brightness increased by " + stepValue + "%" + (targetDevice ? " on " + targetDevice : "");
|
||||||
}
|
}
|
||||||
@@ -824,7 +904,7 @@ Singleton {
|
|||||||
|
|
||||||
const newBrightness = Math.max(minValue, currentBrightness - stepValue);
|
const newBrightness = Math.max(minValue, currentBrightness - stepValue);
|
||||||
|
|
||||||
root.setBrightness(newBrightness, actualDevice, false);
|
root.setBrightness(newBrightness, actualDevice);
|
||||||
|
|
||||||
return "Brightness decreased by " + stepValue + "%" + (targetDevice ? " on " + targetDevice : "");
|
return "Brightness decreased by " + stepValue + "%" + (targetDevice ? " on " + targetDevice : "");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user