mirror of
https://github.com/ItsDrike/dotfiles.git
synced 2025-09-13 18:44:49 +00:00
Compare commits
2 commits
aedbfed456
...
18bd1701ba
Author | SHA1 | Date | |
---|---|---|---|
18bd1701ba | |||
4dcf5244cf |
49 changed files with 1737 additions and 1 deletions
43
home/.config/eww/css/_colors.scss
Normal file
43
home/.config/eww/css/_colors.scss
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
$rosewater: #f5e0dc;
|
||||||
|
$flamingo: #f2cdcd;
|
||||||
|
$pink: #f5c2e7;
|
||||||
|
$mauve: #cba6f7;
|
||||||
|
$red: #f38ba8;
|
||||||
|
$maroon: #eba0ac;
|
||||||
|
$peach: #fab387;
|
||||||
|
$yellow: #f9e2af;
|
||||||
|
$gold: #efcb10;
|
||||||
|
$green: #a6e3a1;
|
||||||
|
$lime: #78db32;
|
||||||
|
$teal: #94e2d5;
|
||||||
|
$sky: #89dceb;
|
||||||
|
$sapphire: #74c7ec;
|
||||||
|
$blue: #89b4fa;
|
||||||
|
$lavender: #b4befe;
|
||||||
|
$orange: #ffa500;
|
||||||
|
|
||||||
|
$text: #cdd6f4;
|
||||||
|
$subtext1: #bac2de;
|
||||||
|
$subtext0: #a6adc8;
|
||||||
|
$overlay2: #9399b2;
|
||||||
|
$overlay1: #7f849c;
|
||||||
|
$overlay0: #6c7086;
|
||||||
|
|
||||||
|
$surface2: #585b70;
|
||||||
|
$surface1: #45475a;
|
||||||
|
$surface0: #313244;
|
||||||
|
|
||||||
|
$base-a: rgba(30, 30, 40, 0.65);
|
||||||
|
$base: rgba(30, 30, 40, 1);
|
||||||
|
$base1-a: rgba(49, 50, 68, 0.85);
|
||||||
|
$base1: rgba(49, 50, 68, 1);
|
||||||
|
$mantle: #181825;
|
||||||
|
$crust: #11111b;
|
||||||
|
|
||||||
|
$fg: $text;
|
||||||
|
$bg-a: $base-a;
|
||||||
|
$bg: $base;
|
||||||
|
$bg1: $base1;
|
||||||
|
$bg1-a: $base1-a;
|
||||||
|
$border: #28283d;
|
||||||
|
$shadow: $crust;
|
55
home/.config/eww/css/modules/_battery.scss
Normal file
55
home/.config/eww/css/modules/_battery.scss
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
@keyframes blink {
|
||||||
|
0%{
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
50%{
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
100%{
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// .unplugged.low {
|
||||||
|
// color: #0000ff;
|
||||||
|
// }
|
||||||
|
|
||||||
|
.battery {
|
||||||
|
|
||||||
|
.icon, .icon label {
|
||||||
|
font-family: "Material Symbols Outlined";
|
||||||
|
|
||||||
|
.extra, .extra label {
|
||||||
|
font-family: "Font Awesome 6 Free";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.critical {
|
||||||
|
.unplugged {
|
||||||
|
color: #f00;
|
||||||
|
.extra { animation: blink 1.2s linear infinite; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugged {
|
||||||
|
.icon { color: $orange }
|
||||||
|
.extra { color: $green; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.normal {
|
||||||
|
.unplugged {
|
||||||
|
.icon { color: $orange }
|
||||||
|
}
|
||||||
|
.plugged {
|
||||||
|
.icon { color: $green; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.full {
|
||||||
|
.icon { color: $green; }
|
||||||
|
.extra { color: $lime; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.extra { margin-right: 5px; }
|
||||||
|
.icon { margin-right: 5px; }
|
||||||
|
}
|
3
home/.config/eww/css/modules/_bitcoin.scss
Normal file
3
home/.config/eww/css/modules/_bitcoin.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.bitcoin {
|
||||||
|
.icon { margin-right: 6px; color: $gold; }
|
||||||
|
}
|
4
home/.config/eww/css/modules/_clock.scss
Normal file
4
home/.config/eww/css/modules/_clock.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.clock {
|
||||||
|
// color: $sapphire;
|
||||||
|
.icon { margin-right: 6px; color: $sapphire; }
|
||||||
|
}
|
3
home/.config/eww/css/modules/_cpu.scss
Normal file
3
home/.config/eww/css/modules/_cpu.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.cpu {
|
||||||
|
.icon { color: $lime; }
|
||||||
|
}
|
7
home/.config/eww/css/modules/_gammarelay.scss
Normal file
7
home/.config/eww/css/modules/_gammarelay.scss
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.gammarelay {
|
||||||
|
.icon {
|
||||||
|
color: $peach;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
}
|
3
home/.config/eww/css/modules/_kernel.scss
Normal file
3
home/.config/eww/css/modules/_kernel.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.kernel {
|
||||||
|
.icon { color: $lavender; }
|
||||||
|
}
|
3
home/.config/eww/css/modules/_memory.scss
Normal file
3
home/.config/eww/css/modules/_memory.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.memory {
|
||||||
|
.icon { color: $maroon; }
|
||||||
|
}
|
3
home/.config/eww/css/modules/_uptime.scss
Normal file
3
home/.config/eww/css/modules/_uptime.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.uptime {
|
||||||
|
.icon { color: $green; }
|
||||||
|
}
|
15
home/.config/eww/css/modules/_volume.scss
Normal file
15
home/.config/eww/css/modules/_volume.scss
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
.volume {
|
||||||
|
.icon { color: $peach; }
|
||||||
|
.speaker {
|
||||||
|
.icon {
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.microphone {
|
||||||
|
.icon {
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
home/.config/eww/css/modules/_window_name.scss
Normal file
4
home/.config/eww/css/modules/_window_name.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.window_name {
|
||||||
|
font-family: "Monaspace Krypton";
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
29
home/.config/eww/css/modules/_workspaces.scss
Normal file
29
home/.config/eww/css/modules/_workspaces.scss
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
.workspaces {
|
||||||
|
background-color: $bg1-a;
|
||||||
|
border-radius: 25px;
|
||||||
|
|
||||||
|
.icon,
|
||||||
|
.icon label {
|
||||||
|
font-family: "JetBrainsMono Nerd Font", "Material Symbols Outlined";
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.focused {
|
||||||
|
// text-decoration: underline;
|
||||||
|
// text-decoration-color: red;
|
||||||
|
// text-decoration-style: double;
|
||||||
|
color: $fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inactive {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
}
|
32
home/.config/eww/css/windows/_calendar.scss
Normal file
32
home/.config/eww/css/windows/_calendar.scss
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
.calendar-win {
|
||||||
|
@include window;
|
||||||
|
background-color: $bg;
|
||||||
|
border: 1px solid $border;
|
||||||
|
color: $fg;
|
||||||
|
padding: .2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
calendar {
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
:selected {
|
||||||
|
color: $mauve;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
color: $subtext1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
color: $maroon;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
color: $sapphire;
|
||||||
|
}
|
||||||
|
|
||||||
|
:indeterminate {
|
||||||
|
color: $overlay0;
|
||||||
|
}
|
||||||
|
}
|
46
home/.config/eww/css/windows/_radio_menu.scss
Normal file
46
home/.config/eww/css/windows/_radio_menu.scss
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
.radio-menu-box {
|
||||||
|
@include window;
|
||||||
|
background-color: $bg;
|
||||||
|
border: 1px solid $border;
|
||||||
|
color: $text;
|
||||||
|
font-family: "Jost *", "JetBrains Mono", "Font Awesome 6 Free", sans-serif;
|
||||||
|
|
||||||
|
.icon, .icon label {
|
||||||
|
font-family: "Material Symbols Outlined";
|
||||||
|
font-size: 1.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-row {
|
||||||
|
margin: 1rem 1.5rem 0;
|
||||||
|
|
||||||
|
.title { font-size: 1.2rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-row {
|
||||||
|
margin: .5rem .7rem;
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin: 0 .1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.element {
|
||||||
|
@include rounding;
|
||||||
|
background-color: $surface0;
|
||||||
|
margin: .3rem;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include rounding;
|
||||||
|
padding: .5rem;
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $overlay0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
home/.config/eww/eww.scss
Normal file
114
home/.config/eww/eww.scss
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
@import "css/colors";
|
||||||
|
|
||||||
|
@mixin rounding {
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin window {
|
||||||
|
border: 1px solid $border;
|
||||||
|
box-shadow: 0 2px 3px $shadow;
|
||||||
|
margin: 5px 5px 10px;
|
||||||
|
@include rounding;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
all: unset;
|
||||||
|
transition: 200ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "css/windows/calendar";
|
||||||
|
@import "css/windows/radio_menu";
|
||||||
|
@import "css/modules/clock";
|
||||||
|
@import "css/modules/volume";
|
||||||
|
@import "css/modules/bitcoin";
|
||||||
|
@import "css/modules/cpu";
|
||||||
|
@import "css/modules/memory";
|
||||||
|
@import "css/modules/uptime";
|
||||||
|
@import "css/modules/kernel";
|
||||||
|
@import "css/modules/battery";
|
||||||
|
@import "css/modules/workspaces";
|
||||||
|
@import "css/modules/gammarelay";
|
||||||
|
@import "css/modules/window_name";
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
background-color: $bg-a;
|
||||||
|
color: $fg;
|
||||||
|
|
||||||
|
font-family: "JetBrains Mono";
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Use percentages (for some reason it fails now)
|
||||||
|
min-width: 1900px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip {
|
||||||
|
background: $bg;
|
||||||
|
border: 1px solid $border;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon,
|
||||||
|
.icon label {
|
||||||
|
font-family: "Font Awesome 6 Free", "Material Symbols Outlined";
|
||||||
|
}
|
||||||
|
|
||||||
|
.module {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separ {
|
||||||
|
color: $surface0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
scale trough {
|
||||||
|
background-color: $bg1-a;
|
||||||
|
border-radius: 24px;
|
||||||
|
margin: 0 1rem;
|
||||||
|
min-height: 10px;
|
||||||
|
min-width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tray {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu {
|
||||||
|
background: $bg1;
|
||||||
|
border-bottom-left-radius: 12px;
|
||||||
|
border-bottom-right-radius: 12px;
|
||||||
|
border: 2px solid rgba($crust, 0.5);
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu menu {
|
||||||
|
border-top-left-radius: 12px;
|
||||||
|
border-top-right-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu > menuitem {
|
||||||
|
padding: 0.4em 1rem;
|
||||||
|
background: transparent;
|
||||||
|
transition: 0.2s ease background;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu > menuitem:hover {
|
||||||
|
background: rgba($overlay1, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu > menuitem check:checked ~ label {
|
||||||
|
color: $bg1-a;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
menubar > menuitem {
|
||||||
|
margin-left: 0.6rem;
|
||||||
|
}
|
90
home/.config/eww/eww.yuck
Normal file
90
home/.config/eww/eww.yuck
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
(defvar terminal "kitty -e")
|
||||||
|
|
||||||
|
(include "./modules/variables.yuck")
|
||||||
|
|
||||||
|
(include "./modules/clock.yuck")
|
||||||
|
(include "./modules/volume.yuck")
|
||||||
|
(include "./modules/cpu.yuck")
|
||||||
|
(include "./modules/memory.yuck")
|
||||||
|
(include "./modules/uptime.yuck")
|
||||||
|
; (include "./modules/kernel.yuck")
|
||||||
|
(include "./modules/battery.yuck")
|
||||||
|
(include "./modules/window_name.yuck")
|
||||||
|
(include "./modules/workspaces.yuck")
|
||||||
|
(include "./modules/gammarelay.yuck")
|
||||||
|
|
||||||
|
(include "./windows/calendar.yuck")
|
||||||
|
(include "./windows/radio-menu.yuck")
|
||||||
|
|
||||||
|
(defwidget sep []
|
||||||
|
(label :class "separ module" :text "|"))
|
||||||
|
|
||||||
|
(defwidget left []
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
:halign "start"
|
||||||
|
(gammarelay_module)
|
||||||
|
(sep)
|
||||||
|
(window_name_module)
|
||||||
|
))
|
||||||
|
|
||||||
|
(defwidget right []
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
:halign "end"
|
||||||
|
; (kernel_module)
|
||||||
|
; (sep)
|
||||||
|
(volume_module)
|
||||||
|
(sep)
|
||||||
|
(battery_module)
|
||||||
|
(sep)
|
||||||
|
(cpu_module)
|
||||||
|
(sep)
|
||||||
|
(memory_module)
|
||||||
|
(sep)
|
||||||
|
; (uptime_module)
|
||||||
|
; (sep)
|
||||||
|
(clock_module)
|
||||||
|
(sep)
|
||||||
|
(systray
|
||||||
|
:class "module tray"
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
(defwidget center []
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
:halign "center"
|
||||||
|
(workspaces_module)
|
||||||
|
))
|
||||||
|
|
||||||
|
(defwidget bar []
|
||||||
|
(centerbox
|
||||||
|
:class "bar"
|
||||||
|
:orientation "horizontal"
|
||||||
|
(left)
|
||||||
|
(center)
|
||||||
|
(right)))
|
||||||
|
|
||||||
|
(defwindow bar0
|
||||||
|
:monitor 0
|
||||||
|
:geometry (geometry :x "0%"
|
||||||
|
:y "0%"
|
||||||
|
:width: "100%"
|
||||||
|
:height "32px"
|
||||||
|
:anchor "top center")
|
||||||
|
:stacking "fg"
|
||||||
|
:exclusive true
|
||||||
|
(bar))
|
||||||
|
|
||||||
|
|
||||||
|
(defwindow bar1
|
||||||
|
:monitor 1
|
||||||
|
:geometry (geometry :x "0%"
|
||||||
|
:y "0%"
|
||||||
|
:width: "100%"
|
||||||
|
:height "32px"
|
||||||
|
:anchor "top center")
|
||||||
|
:stacking "fg"
|
||||||
|
:exclusive true
|
||||||
|
(bar))
|
24
home/.config/eww/modules/battery.yuck
Normal file
24
home/.config/eww/modules/battery.yuck
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
(defwidget battery_module []
|
||||||
|
(eventbox
|
||||||
|
:class "module battery"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:class {battery.critical ? "critical" : battery.full ? "full" : "normal"}
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
:class {battery.plugged ? "plugged" : "unplugged" }
|
||||||
|
|
||||||
|
(box
|
||||||
|
:class "icon"
|
||||||
|
:space-evenly false
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "extra"
|
||||||
|
:text {battery.extra_icon})
|
||||||
|
(label
|
||||||
|
:text {battery.capacity_icon}))
|
||||||
|
(label
|
||||||
|
:class "value"
|
||||||
|
:text "${battery.percent}%"
|
||||||
|
)
|
||||||
|
))))
|
14
home/.config/eww/modules/bitcoin.yuck
Normal file
14
home/.config/eww/modules/bitcoin.yuck
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
(defwidget bitcoin_module []
|
||||||
|
(eventbox
|
||||||
|
:onclick "bitcoin | xargs -I{} ${EWW_CMD} update bitcoin={}"
|
||||||
|
:class "module bitcoin"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text "")
|
||||||
|
(label :text {bitcoin}))
|
||||||
|
)
|
||||||
|
)
|
18
home/.config/eww/modules/clock.yuck
Normal file
18
home/.config/eww/modules/clock.yuck
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
(defwidget clock_module []
|
||||||
|
|
||||||
|
(eventbox
|
||||||
|
:tooltip {time.day}
|
||||||
|
:class "module clock"
|
||||||
|
:onclick "${EWW_CMD} open --toggle calendar"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text " ")
|
||||||
|
(label
|
||||||
|
:class "value"
|
||||||
|
:text "${time.date} ${time.hour}:${time.minute}")
|
||||||
|
)))
|
||||||
|
|
15
home/.config/eww/modules/cpu.yuck
Normal file
15
home/.config/eww/modules/cpu.yuck
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
(defwidget cpu_module []
|
||||||
|
(eventbox
|
||||||
|
:class "module cpu"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text " ")
|
||||||
|
(label
|
||||||
|
:class "value"
|
||||||
|
:text "${round(EWW_CPU.avg,2)}%"
|
||||||
|
)
|
||||||
|
)))
|
41
home/.config/eww/modules/gammarelay.yuck
Normal file
41
home/.config/eww/modules/gammarelay.yuck
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
(defwidget gammarelay_module []
|
||||||
|
(box
|
||||||
|
:class "module gammarelay"
|
||||||
|
|
||||||
|
(eventbox
|
||||||
|
:onscroll "scripts/gammarelay temperature scroll {}"
|
||||||
|
:onclick "scripts/gammarelay temperature set toggle"
|
||||||
|
:onrightclick "scripts/gammarelay temperature set off"
|
||||||
|
:tooltip "${temperature} K"
|
||||||
|
:class "temperature"
|
||||||
|
(box
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text "")
|
||||||
|
))
|
||||||
|
|
||||||
|
(eventbox
|
||||||
|
:onscroll "scripts/gammarelay brightness scroll {}"
|
||||||
|
:onclick "scripts/gammarelay brightness set toggle"
|
||||||
|
:onrightclick "scripts/gammarelay brightness set off"
|
||||||
|
:tooltip "${brightness}%"
|
||||||
|
:class "brightness"
|
||||||
|
(box
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text "")
|
||||||
|
))
|
||||||
|
|
||||||
|
; (eventbox
|
||||||
|
; :onscroll "scripts/gammarelay gamma scroll {}"
|
||||||
|
; :onclick "scripts/gammarelay gamma set toggle"
|
||||||
|
; :onrightclick "scripts/gammarelay gamma set off"
|
||||||
|
; :tooltip "${gamma}%"
|
||||||
|
; :class "gamma"
|
||||||
|
; :valign "top"
|
||||||
|
; (box
|
||||||
|
; (label
|
||||||
|
; :class "icon"
|
||||||
|
; :text "γ")
|
||||||
|
; ))
|
||||||
|
))
|
15
home/.config/eww/modules/kernel.yuck
Normal file
15
home/.config/eww/modules/kernel.yuck
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
(defwidget kernel_module []
|
||||||
|
(eventbox
|
||||||
|
:class "module kernel"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text " ")
|
||||||
|
(label
|
||||||
|
:class "value"
|
||||||
|
:text {kernel}
|
||||||
|
)
|
||||||
|
)))
|
15
home/.config/eww/modules/memory.yuck
Normal file
15
home/.config/eww/modules/memory.yuck
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
(defwidget memory_module []
|
||||||
|
(eventbox
|
||||||
|
:class "module memory"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text " ")
|
||||||
|
(label
|
||||||
|
:class "value"
|
||||||
|
:text "${round(EWW_RAM.used_mem / 1000000000,1)}G: ${round(EWW_RAM.used_mem_perc,0)}%"
|
||||||
|
)
|
||||||
|
)))
|
3
home/.config/eww/modules/nightlight.yuck
Normal file
3
home/.config/eww/modules/nightlight.yuck
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
(deflisten nightlight
|
||||||
|
:initial `{"running": false,"temperature": 0}`
|
||||||
|
`scripts/nightlight --state`)
|
15
home/.config/eww/modules/uptime.yuck
Normal file
15
home/.config/eww/modules/uptime.yuck
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
(defwidget uptime_module []
|
||||||
|
(eventbox
|
||||||
|
:class "module uptime"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:space-evenly false
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text " ")
|
||||||
|
(label
|
||||||
|
:class "value"
|
||||||
|
:text {uptime}
|
||||||
|
)
|
||||||
|
)))
|
60
home/.config/eww/modules/variables.yuck
Normal file
60
home/.config/eww/modules/variables.yuck
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
(defpoll time
|
||||||
|
:interval "5s"
|
||||||
|
:initial '{"date": "01 Jan", "hour": "00", "minute": "00", "day": "Monday"}'
|
||||||
|
`date +'{"date": "%d %b", "hour": "%H", "minute": "%M", "day": "%A"}'`)
|
||||||
|
|
||||||
|
(deflisten volume
|
||||||
|
:initial '{ "speaker_vol": "100", "speaker_mute": false, "speaker_icon": "", "microphone_mute": false, "microphone_vol": "100", "microphone_icon": "" }'
|
||||||
|
`scripts/volume loop`)
|
||||||
|
|
||||||
|
(deflisten window_name
|
||||||
|
:initial `{"class":"","name":"","formatted_name":""}`
|
||||||
|
`scripts/window_name`)
|
||||||
|
|
||||||
|
(deflisten workspaces
|
||||||
|
:initial `[{"id": 1,"name": "N/A","monitor": "N/A","windows": 1,"hasfullscreen": false,"lastwindow": "N/A","lastwindowtitle": "N/A","format_name": "N/A","active": true}]`
|
||||||
|
`scripts/workspaces --loop`)
|
||||||
|
|
||||||
|
(defpoll battery
|
||||||
|
:interval "1s"
|
||||||
|
:initial '{"percent":"0","plugged":"false","status":"N/A","capacity_icon":"","extra_icon":"","manufacturer":"N/A","model_name":"N/A","technology":"N/A","energy_now":"0","enerfy_full":"0","enerfy_full_design":"0","cycle_count":"0","critical":"false","full":"false"}'
|
||||||
|
`scripts/battery`)
|
||||||
|
|
||||||
|
(defpoll uptime
|
||||||
|
:interval "1m"
|
||||||
|
:initial 'N/A'
|
||||||
|
`uptime -p | sed \\
|
||||||
|
-e 's/^up //' \\
|
||||||
|
-e 's/ years\\?,\\?/y/' \\
|
||||||
|
-e 's/ months\\?,\\?/m/' \\
|
||||||
|
-e 's/ weeks\\?,\\?/w/' \\
|
||||||
|
-e 's/ days\\?,\\?/d/' \\
|
||||||
|
-e 's/ hours\\?,\\?/h/' \\
|
||||||
|
-e 's/ minutes\\?,\\?/m/' \\
|
||||||
|
-e 's/ seconds\\?,\\?/s/' \\
|
||||||
|
| cut -d' ' -f-2`)
|
||||||
|
|
||||||
|
(defpoll bitcoin
|
||||||
|
:interval "5m"
|
||||||
|
:initial "$N/A"
|
||||||
|
`bitcoin`)
|
||||||
|
|
||||||
|
; TODO: Figure out how to store this one-time
|
||||||
|
(defpoll kernel
|
||||||
|
:interval "10000h"
|
||||||
|
:initial 'N/A'
|
||||||
|
; `uname -r | sed -r 's/(.+)-arch(.+)/\\1/'`
|
||||||
|
`uname -r`)
|
||||||
|
|
||||||
|
(deflisten temperature `scripts/gammarelay temperature watch`)
|
||||||
|
(deflisten brightness `scripts/gammarelay brightness watch`)
|
||||||
|
(deflisten gamma `scripts/gammarelay gamma watch`)
|
||||||
|
|
||||||
|
(defpoll net
|
||||||
|
:interval "3s"
|
||||||
|
:initial '{"essid":"N/A","icon":"","state":"unknown","signal":"0"}'
|
||||||
|
`scripts/net status`)
|
||||||
|
(defpoll bluetooth
|
||||||
|
:interval "3s"
|
||||||
|
:initial '{"icon":"","status":"unknown","name":"","mac":"","battery":""}'
|
||||||
|
`scripts/bluetooth status`)
|
40
home/.config/eww/modules/volume.yuck
Normal file
40
home/.config/eww/modules/volume.yuck
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
(defvar mic_rev false)
|
||||||
|
|
||||||
|
(defwidget volume_module []
|
||||||
|
(box
|
||||||
|
:class "module volume"
|
||||||
|
:space-evenly false
|
||||||
|
|
||||||
|
(eventbox
|
||||||
|
:onscroll "scripts/volume setvol SOURCE 0.5 {}"
|
||||||
|
:onclick "scripts/volume togglemute SOURCE"
|
||||||
|
:onrightclick "${terminal} pulsemixer &"
|
||||||
|
:onhover "${EWW_CMD} update mic_rev=true"
|
||||||
|
:onhoverlost "${EWW_CMD} update mic_rev=false"
|
||||||
|
:class "microphone"
|
||||||
|
(box
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text {volume.microphone_icon})
|
||||||
|
(label
|
||||||
|
:visible {mic_rev && !volume.microphone_mute}
|
||||||
|
:class "value"
|
||||||
|
:text "${volume.microphone_vol}%")
|
||||||
|
))
|
||||||
|
|
||||||
|
(eventbox
|
||||||
|
:onscroll "scripts/volume setvol SINK 0.5 {}"
|
||||||
|
:onclick "scripts/volume togglemute SINK"
|
||||||
|
:onrightclick "${terminal} pulsemixer &"
|
||||||
|
:class "speaker"
|
||||||
|
(box
|
||||||
|
(label
|
||||||
|
:class "icon"
|
||||||
|
:text {volume.speaker_icon})
|
||||||
|
(label
|
||||||
|
:visible {!volume.speaker_mute}
|
||||||
|
:class "value"
|
||||||
|
:text "${volume.speaker_vol}%")
|
||||||
|
))
|
||||||
|
|
||||||
|
))
|
11
home/.config/eww/modules/window_name.yuck
Normal file
11
home/.config/eww/modules/window_name.yuck
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
; Consider making the window name clickable, opening up a full window that's showing
|
||||||
|
; the selected window details (class, unformatted name, and perhaps even more, like
|
||||||
|
; xwayland status, ...)
|
||||||
|
(defwidget window_name_module []
|
||||||
|
(box
|
||||||
|
:class "module window_name"
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "value"
|
||||||
|
:text "${window_name.formatted_name}")
|
||||||
|
))
|
21
home/.config/eww/modules/workspaces.yuck
Normal file
21
home/.config/eww/modules/workspaces.yuck
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
; (defwidget sep []
|
||||||
|
; (label :class "separ module" :text "|"))
|
||||||
|
|
||||||
|
|
||||||
|
; Consider making the window name clickable, opening up a full window that's showing
|
||||||
|
; the selected window details (class, unformatted name, and perhaps even more, like
|
||||||
|
; xwayland status, ...)
|
||||||
|
(defwidget workspaces_module []
|
||||||
|
(box
|
||||||
|
:class "module workspaces"
|
||||||
|
|
||||||
|
(for workspace in workspaces
|
||||||
|
(eventbox
|
||||||
|
:class {workspace.active ? 'focused' : workspace.windows > 0 ? 'active' : 'inactive'}
|
||||||
|
:onclick `scripts/workspaces --switch ${workspace.id}`
|
||||||
|
|
||||||
|
(label
|
||||||
|
:class "value icon"
|
||||||
|
:text {workspace.format_name}))
|
||||||
|
)
|
||||||
|
))
|
11
home/.config/eww/scripts/.flake8
Normal file
11
home/.config/eww/scripts/.flake8
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[flake8]
|
||||||
|
max-line-length=119
|
||||||
|
extend-ignore=E203
|
||||||
|
extend-select=B902,B904
|
||||||
|
exclude=.venv,.git,.cache
|
||||||
|
ignore=
|
||||||
|
ANN002, # *args annotation
|
||||||
|
ANN003, # **kwargs annotation
|
||||||
|
ANN101, # self param annotation
|
||||||
|
ANN102, # cls param annotation
|
||||||
|
ANN204, # return type annotation for special methods
|
85
home/.config/eww/scripts/battery
Executable file
85
home/.config/eww/scripts/battery
Executable file
|
@ -0,0 +1,85 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# shellcheck source=include
|
||||||
|
source "./scripts/include"
|
||||||
|
|
||||||
|
# $BATTERY and $ADAPTER env vars can be set manually, being the names of the
|
||||||
|
# devices (in /sys/class/power_supply/) i.e. BATTERY=BAT0 ADAPTER=ADP0
|
||||||
|
# or, if left unset, they will be automatically picked.
|
||||||
|
|
||||||
|
CAPACITY_ICONS=("" "" "" "" "" "" "" "" "" "")
|
||||||
|
CHARGING_ICON=""
|
||||||
|
DISCHARGING_ICON=""
|
||||||
|
FULL_ICON="" # Plugged in, but no longer charging (fully charged)
|
||||||
|
CRITICAL_ICON=""
|
||||||
|
CRITICAL_PERCENTAGE=15
|
||||||
|
|
||||||
|
if [ -z "$BATTERY" ]; then
|
||||||
|
# shellcheck disable=SC2010
|
||||||
|
BATTERY="$(\ls -t /sys/class/power_supply | grep "BAT" | head -n 1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$ADAPTER" ]; then
|
||||||
|
# shellcheck disable=SC2010
|
||||||
|
ADAPTER="$(\ls -t /sys/class/power_supply | grep -E "ADP|AC" | head -n 1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
get_bat_info() {
|
||||||
|
cat /sys/class/power_supply/"$BATTERY"/"$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_adp_info() {
|
||||||
|
cat /sys/class/power_supply/"$ADAPTER"/"$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
manufacturer="$(get_bat_info manufacturer)"
|
||||||
|
model_name="$(get_bat_info model_name)"
|
||||||
|
technology="$(get_bat_info technology)"
|
||||||
|
energy_now="$(get_bat_info energy_now)"
|
||||||
|
energy_full="$(get_bat_info energy_full)"
|
||||||
|
energy_full_design="$(get_bat_info energy_full_design)"
|
||||||
|
cycle_count="$(get_bat_info cycle_count)"
|
||||||
|
|
||||||
|
capacity="$(get_bat_info capacity)"
|
||||||
|
status="$(get_bat_info status)"
|
||||||
|
[ "$(get_adp_info online)" -eq 1 ] && adp_connected="true" || adp_connected="false"
|
||||||
|
|
||||||
|
# Quick overrides to showcase how battery works
|
||||||
|
# capacity=100
|
||||||
|
# adp_connected="true"
|
||||||
|
# status="Charging"
|
||||||
|
# status="Not charging"
|
||||||
|
# status="Discharging"
|
||||||
|
|
||||||
|
full="false"
|
||||||
|
capacity_icon="$(pick_icon "$capacity" 0 100 "${CAPACITY_ICONS[@]}")"
|
||||||
|
|
||||||
|
if [ "$status" = "Not charging" ] || [ "$status" = "Full" ] && [ "$adp_connected" = "true" ]; then
|
||||||
|
extra_icon="$FULL_ICON"
|
||||||
|
full="true"
|
||||||
|
elif [ "$status" = "Discharging" ] && [ "$capacity" -le "$CRITICAL_PERCENTAGE" ]; then
|
||||||
|
extra_icon="$CRITICAL_ICON"
|
||||||
|
elif [ "$status" = "Discharging" ]; then
|
||||||
|
extra_icon="$DISCHARGING_ICON"
|
||||||
|
elif [ "$status" = "Charging" ]; then
|
||||||
|
extra_icon="$CHARGING_ICON"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$capacity" -le "$CRITICAL_PERCENTAGE" ] && critical="true" || critical="false"
|
||||||
|
|
||||||
|
jq -n -c --monochrome-output \
|
||||||
|
--arg percent "$capacity" \
|
||||||
|
--arg plugged "$adp_connected" \
|
||||||
|
--arg status "$status" \
|
||||||
|
--arg capacity_icon "$capacity_icon" \
|
||||||
|
--arg extra_icon "$extra_icon" \
|
||||||
|
--arg manufacturer "$manufacturer" \
|
||||||
|
--arg model_name "$model_name" \
|
||||||
|
--arg technology "$technology" \
|
||||||
|
--arg energy_now "$energy_now" \
|
||||||
|
--arg energy_full "$energy_full" \
|
||||||
|
--arg energy_full_design "$energy_full_design" \
|
||||||
|
--arg cycle_count "$cycle_count" \
|
||||||
|
--arg critical "$critical" \
|
||||||
|
--arg full "$full" \
|
||||||
|
'$ARGS.named'
|
85
home/.config/eww/scripts/bluetooth
Executable file
85
home/.config/eww/scripts/bluetooth
Executable file
|
@ -0,0 +1,85 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
ICON_IDLE=""
|
||||||
|
ICON_CONNECTED=""
|
||||||
|
ICON_OFF=""
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
status=$(rfkill -J | jq -r '.rfkilldevices[] | select(.type == "bluetooth") | .soft' | head -1)
|
||||||
|
|
||||||
|
if [ "$status" = "unblocked" ]; then
|
||||||
|
rfkill block bluetooth
|
||||||
|
else
|
||||||
|
rfkill unblock bluetooth
|
||||||
|
if ! systemctl -q is-active bluetooth.service; then
|
||||||
|
# This will use polkit for privillege elevation
|
||||||
|
systemctl start bluetooth
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_report() {
|
||||||
|
status=$(rfkill -J | jq -r '.rfkilldevices[] | select(.type == "bluetooth") | .soft' | head -1)
|
||||||
|
if [ "$status" = "blocked" ] || ! systemctl -q is-active bluetooth.service || ! command -v bluetoothctl >/dev/null 2>&1; then
|
||||||
|
jq -n -c --monochrome-output \
|
||||||
|
--arg icon "$ICON_OFF" \
|
||||||
|
--arg status "unknown" \
|
||||||
|
--arg name "" \
|
||||||
|
--arg mac "" \
|
||||||
|
--arg battery "" \
|
||||||
|
'$ARGS.named'
|
||||||
|
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
status="$(bluetoothctl show)"
|
||||||
|
|
||||||
|
powered="$(echo "$status" | grep Powered | cut -d' ' -f 2-)"
|
||||||
|
if [ "$powered" != "yes" ]; then
|
||||||
|
jq -n -c --monochrome-output \
|
||||||
|
--arg icon "$ICON_OFF" \
|
||||||
|
--arg status "unpowered" \
|
||||||
|
--arg name "" \
|
||||||
|
--arg mac "" \
|
||||||
|
--arg battery "" \
|
||||||
|
'$ARGS.named'
|
||||||
|
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
status="$(bluetoothctl info)"
|
||||||
|
if [ "$status" == "Missing device address argument" ]; then
|
||||||
|
jq -n -c --monochrome-output \
|
||||||
|
--arg icon "$ICON_IDLE" \
|
||||||
|
--arg status "idle" \
|
||||||
|
--arg name "" \
|
||||||
|
--arg mac "" \
|
||||||
|
--arg battery "" \
|
||||||
|
'$ARGS.named'
|
||||||
|
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
name="$(echo "$status" | grep Name | cut -d' ' -f 2-)"
|
||||||
|
mac="$(echo "$status" | head -1 | awk '{print $2}' | tr ':' '_')"
|
||||||
|
|
||||||
|
if [ "$(echo "$status" | grep Percentage)" != "" ] && command -v upower >/dev/null 2>&1; then
|
||||||
|
battery="$(upower -i /org/freedesktop/UPower/devices/headset_dev_"$mac" | grep percentage | awk '{print $2}' | cut -f 1 -d '%')%"
|
||||||
|
else
|
||||||
|
battery=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq -n -c --monochrome-output \
|
||||||
|
--arg icon "$ICON_CONNECTED" \
|
||||||
|
--arg status "connected" \
|
||||||
|
--arg name "$name" \
|
||||||
|
--arg mac "$mac" \
|
||||||
|
--arg battery "$battery" \
|
||||||
|
'$ARGS.named'
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
"status") get_report ;;
|
||||||
|
"toggle") toggle ;;
|
||||||
|
*) >&2 echo "Invalid usage, argument '$1' not recognized."; exit 1 ;;
|
||||||
|
esac
|
82
home/.config/eww/scripts/gammarelay
Executable file
82
home/.config/eww/scripts/gammarelay
Executable file
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ "$1" = "temperature" ]; then
|
||||||
|
watch_cmd="{t}"
|
||||||
|
update_cmd="UpdateTemperature"
|
||||||
|
update_signature="n"
|
||||||
|
set_cmd="Temperature"
|
||||||
|
set_signature="q"
|
||||||
|
default_val=6500
|
||||||
|
click_val=4500
|
||||||
|
scroll_change=100
|
||||||
|
cmp_op="<"
|
||||||
|
|
||||||
|
elif [ "$1" = "brightness" ]; then
|
||||||
|
watch_cmd="{bp}"
|
||||||
|
update_cmd="UpdateBrightness"
|
||||||
|
update_signature="d"
|
||||||
|
set_cmd="Brightness"
|
||||||
|
set_signature="d"
|
||||||
|
default_val=1
|
||||||
|
click_val=0.8
|
||||||
|
scroll_change=0.02
|
||||||
|
cmp_op="<"
|
||||||
|
|
||||||
|
elif [ "$1" = "gamma" ]; then
|
||||||
|
watch_cmd="{g}"
|
||||||
|
update_cmd="UpdateGamma"
|
||||||
|
update_signature="d"
|
||||||
|
set_cmd="Gamma"
|
||||||
|
set_signature="d"
|
||||||
|
default_val=1
|
||||||
|
click_val=1.1
|
||||||
|
scroll_change=0.02
|
||||||
|
cmp_op=">"
|
||||||
|
|
||||||
|
else
|
||||||
|
>&2 echo "Invalid option, first argument must be one of: temperature, brightness, gamma"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$2" = "watch" ]; then
|
||||||
|
exec wl-gammarelay-rs watch "$watch_cmd"
|
||||||
|
|
||||||
|
elif [ "$2" = "get" ]; then
|
||||||
|
exec busctl --user get-property rs.wl-gammarelay / rs.wl.gammarelay "$set_cmd" | cut -d' ' -f2
|
||||||
|
|
||||||
|
elif [ "$2" = "scroll" ]; then
|
||||||
|
if [ "$3" = "up" ]; then
|
||||||
|
sign="+"
|
||||||
|
elif [ "$3" = "down" ]; then
|
||||||
|
sign="-"
|
||||||
|
else
|
||||||
|
>&2 echo "Invalid sign, second argument must be one of: up, down"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec busctl --user -- call rs.wl-gammarelay / rs.wl.gammarelay "$update_cmd" "$update_signature" ${sign}${scroll_change}
|
||||||
|
|
||||||
|
elif [ "$2" = "set" ]; then
|
||||||
|
mode="$3"
|
||||||
|
if [ "$mode" = "toggle" ]; then
|
||||||
|
cur_val="$(busctl --user get-property rs.wl-gammarelay / rs.wl.gammarelay "$set_cmd" | cut -d' ' -f2)"
|
||||||
|
if [ "$(echo "$cur_val $cmp_op $default_val" | bc -l)" = "1" ]; then
|
||||||
|
mode="off"
|
||||||
|
else
|
||||||
|
mode="on"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$mode" = "on" ]; then
|
||||||
|
exec busctl --user -- set-property rs.wl-gammarelay / rs.wl.gammarelay "$set_cmd" "$set_signature" "$click_val"
|
||||||
|
elif [ "$mode" = "off" ]; then
|
||||||
|
exec busctl --user -- set-property rs.wl-gammarelay / rs.wl.gammarelay "$set_cmd" "$set_signature" "$default_val"
|
||||||
|
else
|
||||||
|
>&2 echo "Invalid mode, third argument, must be one of: toggle, on, off"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
>&2 echo "Invalid operation, second argument must be one of: watch, scroll, set"
|
||||||
|
exit 1
|
||||||
|
fi
|
50
home/.config/eww/scripts/include
Executable file
50
home/.config/eww/scripts/include
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# $1: Current number
|
||||||
|
# $2: Range minimum
|
||||||
|
# $3: Range maximum
|
||||||
|
# $4-: Icons as individual arguments
|
||||||
|
pick_icon() {
|
||||||
|
cur="$1"
|
||||||
|
min="$2"
|
||||||
|
max="$3"
|
||||||
|
shift 3
|
||||||
|
icons=("$@")
|
||||||
|
|
||||||
|
index="$(echo "($cur-$min)/(($max-$min)/${#icons[@]})" | bc)"
|
||||||
|
|
||||||
|
# Print the picked icon, handling overflows/underflows, i.e. if our index is <0 or >len(icons)
|
||||||
|
if [ "$index" -ge "${#icons[@]}" ]; then
|
||||||
|
index=-1
|
||||||
|
elif [ "$index" -lt 0 ]; then
|
||||||
|
index=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${icons[index]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Will block and listen to the hyprland socket messages and output them
|
||||||
|
# Generally used like: hyprland_ipc | while read line; do handle $line; done
|
||||||
|
# Read <https://wiki.hyprland.org/IPC/> for output format and available events
|
||||||
|
# Note: requires openbsd version of netcat.
|
||||||
|
# $1 - Optional event to listen for (no event filtering will be done if not provided)
|
||||||
|
hyprland_ipc() {
|
||||||
|
if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
|
||||||
|
>&2 echo "Hyprland is not running, IPC not available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOCKET_PATH="${XDG_RUNTIME_DIR:-/run/user/$UID}/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
|
||||||
|
#SOCKET_PATH="/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
nc -U "$SOCKET_PATH" | while read -r test; do
|
||||||
|
echo "$test"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
nc -U "$SOCKET_PATH" | while read -r test; do
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
echo "$test" | grep --line-buffered -E "^$1>>" | stdbuf -oL awk -F '>>' '{print $2}'
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
52
home/.config/eww/scripts/net
Executable file
52
home/.config/eww/scripts/net
Executable file
|
@ -0,0 +1,52 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# shellcheck source=include
|
||||||
|
source "./scripts/include"
|
||||||
|
|
||||||
|
STRENGTH_ICONS=("" "" "" "" "" "")
|
||||||
|
DISCONNECTED_ICON=""
|
||||||
|
WIFI_OFF=""
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
status=$(rfkill -J | jq -r '.rfkilldevices[] | select(.type == "wlan") | .soft' | head -1)
|
||||||
|
|
||||||
|
if [ "$status" = "unblocked" ]; then
|
||||||
|
rfkill block wlan
|
||||||
|
else
|
||||||
|
rfkill unblock wlan
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_report() {
|
||||||
|
connection_details="$(nmcli -t -f NAME,TYPE,DEVICE connection show --active | grep wireless | head -n1)"
|
||||||
|
essid="$(echo $connection_details | cut -d':' -f1)"
|
||||||
|
device="$(echo $connection_details | cut -d':' -f3)"
|
||||||
|
if [ -n "$device" ]; then
|
||||||
|
state="$(nmcli -t -f DEVICE,STATE device status | grep "$device" | head -n1 | cut -d':' -f2)"
|
||||||
|
signal="$(nmcli -t -f in-use,signal dev wifi | grep "\*" | cut -d':' -f2)"
|
||||||
|
else
|
||||||
|
state="unknown"
|
||||||
|
signal="0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$state" = "disconnected" ] ; then
|
||||||
|
icon="$DISCONNECTED_ICON"
|
||||||
|
elif [ "$state" = "unknown" ]; then
|
||||||
|
icon="$WIFI_OFF"
|
||||||
|
else
|
||||||
|
icon="$(pick_icon "$signal" 0 100 "${STRENGTH_ICONS[@]}")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq -n -c --monochrome-output \
|
||||||
|
--arg essid "$essid" \
|
||||||
|
--arg icon "$icon" \
|
||||||
|
--arg state "$state" \
|
||||||
|
--arg signal "$signal" \
|
||||||
|
'$ARGS.named'
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
"toggle") toggle ;;
|
||||||
|
"status") get_report ;;
|
||||||
|
*) >&2 echo "Invalid usage, argument '$1' not recognized."; exit 1 ;;
|
||||||
|
esac
|
12
home/.config/eww/scripts/nightlight
Normal file
12
home/.config/eww/scripts/nightlight
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# shellcheck source=include
|
||||||
|
source "./scripts/include"
|
||||||
|
|
||||||
|
# Consider usning a file as a flag for whether nightlight is on or off
|
||||||
|
# as we might be in transition state and just killing the program might
|
||||||
|
# not be enough.
|
||||||
|
|
||||||
|
if [ "$1" = "toggle" ]; then
|
||||||
|
gammastep -x
|
||||||
|
fi
|
12
home/.config/eww/scripts/pyproject.toml
Normal file
12
home/.config/eww/scripts/pyproject.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[tool.black]
|
||||||
|
line-length = 119
|
||||||
|
extend-exclude = "^/.cache"
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
line_length = 119
|
||||||
|
atomic = true
|
||||||
|
order_by_type = false
|
||||||
|
case_sensitive = true
|
||||||
|
combine_as_imports = true
|
||||||
|
skip = [".venv", ".git", ".cache"]
|
35
home/.config/eww/scripts/storage
Executable file
35
home/.config/eww/scripts/storage
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
MOUNTPOINTS=("/" "/mnt/ext")
|
||||||
|
|
||||||
|
data="$(df -H)"
|
||||||
|
|
||||||
|
as_json() {
|
||||||
|
mountpoint="$1"
|
||||||
|
res="$2"
|
||||||
|
arr_res=($res)
|
||||||
|
|
||||||
|
jq -n -c --monochrome-output \
|
||||||
|
--arg mountpoint "$mountpoint" \
|
||||||
|
--arg size "${arr_res[0]}" \
|
||||||
|
--arg used "${arr_res[1]}" \
|
||||||
|
--arg avail "${arr_res[2]}" \
|
||||||
|
--arg percent "${arr_res[3]}" \
|
||||||
|
'$ARGS.named'
|
||||||
|
}
|
||||||
|
|
||||||
|
output_json="[]"
|
||||||
|
for mountpoint in "${MOUNTPOINTS[@]}"; do
|
||||||
|
res="$(echo "$data" | awk -v m="$mountpoint" '$6 == m {print $2 " " $3 " " $4 " " $5}')"
|
||||||
|
out="$(as_json "$mountpoint" "$res")"
|
||||||
|
|
||||||
|
# echo "$output_json $out" | jq -c -s
|
||||||
|
|
||||||
|
jq --argjson arr1 "$output_json" --argjson arr2 "[$out]" -n \
|
||||||
|
'$arr1 + $arr2'
|
||||||
|
|
||||||
|
# mount_data+=("$mountpoint" $res)
|
||||||
|
# echo "${mount_data[@]}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# echo "${mount_data[@]}"
|
7
home/.config/eww/scripts/temp
Executable file
7
home/.config/eww/scripts/temp
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# shellcheck source=include
|
||||||
|
source "./scripts/include"
|
||||||
|
|
||||||
|
#hyprland_ipc "workspace|createworkspace|destroyworkspace|activewindow"
|
||||||
|
hyprland_ipc
|
112
home/.config/eww/scripts/volume
Executable file
112
home/.config/eww/scripts/volume
Executable file
|
@ -0,0 +1,112 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Define some icons
|
||||||
|
SPEAKER_ICONS=("" "" "")
|
||||||
|
SPEAKER_MUTED_ICON=""
|
||||||
|
MIC_ICON=""
|
||||||
|
MIC_MUTED_ICON=" "
|
||||||
|
|
||||||
|
# Define some helper functions for getting/setting audio data using wireplumber (wpctl)
|
||||||
|
|
||||||
|
# $1 can either be "SINK" (speaker) or "SOURCE" (microphone)
|
||||||
|
get_vol() {
|
||||||
|
wpctl get-volume "@DEFAULT_AUDIO_${1}@" | awk '{print int($2*100)}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# $1 can either be "SINK" (speaker) or "SOURCE" (microphone)
|
||||||
|
# #2 is the voulme (as percentage) to set the volume to
|
||||||
|
# $3 is optional, if set, it can be '+' or '-', which then adds/decreases volume, instead of setting
|
||||||
|
set_vol() {
|
||||||
|
wpctl set-volume "@DEFAULT_AUDIO_${1}@" "$(awk -v n="$2" 'BEGIN{print (n / 100)}')$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
# $1 can either be "SINK" (speaker) or "SOURCE" (microphone)
|
||||||
|
check_mute() {
|
||||||
|
wpctl get-volume "@DEFAULT_AUDIO_${1}@" | grep -i muted >/dev/null
|
||||||
|
echo $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# $1 can either be "SINK" (speaker) or "SOURCE" (microphone)
|
||||||
|
toggle_mute() {
|
||||||
|
wpctl set-mute "@DEFAULT_AUDIO_${1}@" toggle
|
||||||
|
}
|
||||||
|
|
||||||
|
get_report() {
|
||||||
|
spkr_vol="$(get_vol "SINK")"
|
||||||
|
mic_vol="$(get_vol "SOURCE")"
|
||||||
|
|
||||||
|
if [ "$(check_mute "SINK")" == "0" ]; then
|
||||||
|
spkr_mute="true"
|
||||||
|
spkr_icon="$SPEAKER_MUTED_ICON"
|
||||||
|
else
|
||||||
|
spkr_mute="false"
|
||||||
|
index="$(awk -v n="$spkr_vol" -v m="${#SPEAKER_ICONS[@]}" 'BEGIN{print int(n/(100/m))}')"
|
||||||
|
|
||||||
|
# We might end up with an higher than the length of icons, if the volume is over 100%
|
||||||
|
# in this case, set the index to last icon
|
||||||
|
if [ "$index" -ge "${#SPEAKER_ICONS[@]}" ]; then
|
||||||
|
spkr_icon="${SPEAKER_ICONS[-1]}"
|
||||||
|
else
|
||||||
|
spkr_icon="${SPEAKER_ICONS[$index]}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(check_mute "SOURCE")" = "0" ]; then
|
||||||
|
mic_mute="true"
|
||||||
|
mic_icon="$MIC_MUTED_ICON"
|
||||||
|
else
|
||||||
|
mic_mute="false"
|
||||||
|
mic_icon="$MIC_ICON"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "{ \"speaker_vol\": \"$spkr_vol\", \"speaker_mute\": $spkr_mute, \"speaker_icon\": \"$spkr_icon\", \"microphone_mute\": $mic_mute, \"microphone_vol\": \"$mic_vol\", \"microphone_icon\": \"$mic_icon\" }"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Continually run and report every volume change (into stdout)
|
||||||
|
loop() {
|
||||||
|
get_report
|
||||||
|
pactl subscribe | grep --line-buffered "change" | while read -r _; do
|
||||||
|
get_report
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
"loop") loop ;;
|
||||||
|
|
||||||
|
"once") get_report ;;
|
||||||
|
|
||||||
|
"togglemute")
|
||||||
|
if [ "$2" != "SOURCE" ] && [ "$2" != "SINK" ]; then
|
||||||
|
>&2 echo "Invalid usage, expected second argument to be 'SINK' or 'SOURCE', got '$2'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
toggle_mute "$2"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"setvol")
|
||||||
|
if [ "$2" != "SOURCE" ] && [ "$2" != "SINK" ]; then
|
||||||
|
>&2 echo "Invalid usage, expected second argument to be 'SINK' or 'SOURCE', got '$2'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$3" =~ ^[+-]?[0-9]*\.?[0-9]+$ ]]; then
|
||||||
|
case "$4" in
|
||||||
|
"") set_vol "$2" "$3" ;;
|
||||||
|
up | +) set_vol "$2" "$3" "+" ;;
|
||||||
|
down | -) set_vol "$2" "$3" "-" ;;
|
||||||
|
*)
|
||||||
|
>&2 echo "Invalid usage, expected fourth argument to be up/down or +/-, got '$4'"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
>&2 echo "Invalid usage, exepcted third argument to be a number, got '$3'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
>&2 echo "Invalid usage, argument '$1' not recognized."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
6
home/.config/eww/scripts/window_name
Executable file
6
home/.config/eww/scripts/window_name
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# shellcheck source=include
|
||||||
|
source "./scripts/include"
|
||||||
|
|
||||||
|
hyprland_ipc "activewindow" | ./scripts/window_name.py
|
116
home/.config/eww/scripts/window_name.py
Executable file
116
home/.config/eww/scripts/window_name.py
Executable file
|
@ -0,0 +1,116 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""This is a utility script for regex remaps on window names.
|
||||||
|
|
||||||
|
This is done in python, because of the complex regex logic, which would be pretty hard to
|
||||||
|
recreate in bash. This python script is expected to be called from the bash script controlling
|
||||||
|
the window names. Window name and class are obtained from piped stdin, to prevent having to
|
||||||
|
needlessly keep restarting this program, which takes a while due to the interpreter starting
|
||||||
|
overhead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from typing import Iterator, Optional
|
||||||
|
|
||||||
|
|
||||||
|
class RemapRule:
|
||||||
|
__slots__ = ("name_pattern", "output_pattern", "class_pattern")
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name_pattern: str,
|
||||||
|
output_pattern: str,
|
||||||
|
class_pattern: Optional[str] = None,
|
||||||
|
):
|
||||||
|
self.name_pattern = re.compile(name_pattern)
|
||||||
|
self.output_pattern = output_pattern
|
||||||
|
self.class_pattern = re.compile(class_pattern) if class_pattern else None
|
||||||
|
|
||||||
|
def apply(self, window_name: str, window_class: str) -> str:
|
||||||
|
"""Returns new name after this remap rule was applied."""
|
||||||
|
if self.class_pattern is not None:
|
||||||
|
if not self.class_pattern.fullmatch(window_class):
|
||||||
|
# Rule doesn't apply, class mismatch, return original name
|
||||||
|
return window_name
|
||||||
|
|
||||||
|
res = self.name_pattern.fullmatch(window_name)
|
||||||
|
if not res:
|
||||||
|
# Rule doesn't apply, name mismatch, return original name
|
||||||
|
return window_name
|
||||||
|
|
||||||
|
# NOTE: This is potentially unsafe, since output_pattern might be say {0.__class__}, etc.
|
||||||
|
# meaning this allows arbitrary attribute access, however it doesn't allow running functions
|
||||||
|
# here. That said, code could still end up being run if there's some descriptor defined,
|
||||||
|
# and generally I wouldn't trust this in production. However, this code is for my personal
|
||||||
|
# use here, and all of the output patterns are hard-coded in this file, so in this case, it's
|
||||||
|
# fine. But if you see this code and you'd like to use it in your production code, maybe don't
|
||||||
|
return self.output_pattern.format(*res.groups())
|
||||||
|
|
||||||
|
|
||||||
|
# Rules will be applied in specified order
|
||||||
|
REMAP_RULES: list[RemapRule] = [
|
||||||
|
RemapRule(r"", "", ""),
|
||||||
|
RemapRule(r"(.*) — Mozilla Firefox", " {}", "firefox"),
|
||||||
|
RemapRule(r"Mozilla Firefox", " Mozilla Firefox", "firefox"),
|
||||||
|
RemapRule(r"Alacritty", " Alacritty", "Alacritty"),
|
||||||
|
RemapRule(
|
||||||
|
r"zsh;#toggleterm#1 - \(term:\/\/(.+)\/\/(\d+):(.+)\) - N?VIM",
|
||||||
|
" Terminal: {0}",
|
||||||
|
),
|
||||||
|
RemapRule(r"(.+) \+ \((.+)\) - N?VIM", " {0} ({1}) [MODIFIED]"),
|
||||||
|
RemapRule(r"(.+) \((.+)\) - N?VIM", " {0} ({1})"),
|
||||||
|
RemapRule(r"(?:\[\d+\] )?\*?WebCord - (.+)", " {}", "WebCord"),
|
||||||
|
RemapRule(r"(.+) - Discord", " {}", "discord"),
|
||||||
|
RemapRule(r"(?:\(\d+\) )?Discord \| (.+)", " {}", "vesktop"),
|
||||||
|
RemapRule(r"(.+) - mpv", " {}", "mpv"),
|
||||||
|
RemapRule(r"Stremio - (.+)", " Stremio - {}", r"(Stremio)|(com.stremio.stremio)"),
|
||||||
|
RemapRule(r"Spotify((?: Premium)?)", " Spotify{}", "[Ss]potify"),
|
||||||
|
RemapRule(r"pulsemixer", " Pulsemixer"),
|
||||||
|
RemapRule(r"(.*)", " {}", "Pcmanfm"),
|
||||||
|
RemapRule(r"(.*)", " {}", "pcmanfm-qt"),
|
||||||
|
# Needs to be last
|
||||||
|
RemapRule(r"(.*)", " {}", "kitty"),
|
||||||
|
]
|
||||||
|
|
||||||
|
MAX_LENGTH = 65
|
||||||
|
|
||||||
|
|
||||||
|
def iter_window() -> Iterator[tuple[str, str]]:
|
||||||
|
"""Listen for the window parameters from stdin/pipe, yields (window_name, window_class)."""
|
||||||
|
for line in sys.stdin:
|
||||||
|
line = line.removesuffix("\n")
|
||||||
|
els = line.split(",", maxsplit=1)
|
||||||
|
if len(els) != 2:
|
||||||
|
raise ValueError(
|
||||||
|
f"Expected 2 arguments from stdin line (name, class), but got {len(els)}"
|
||||||
|
)
|
||||||
|
yield els[1], els[0]
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
for window_name, window_class in iter_window():
|
||||||
|
formatted_name = window_name
|
||||||
|
for remap_rule in REMAP_RULES:
|
||||||
|
new_name = remap_rule.apply(formatted_name, window_class)
|
||||||
|
if new_name != formatted_name:
|
||||||
|
formatted_name = new_name
|
||||||
|
break
|
||||||
|
|
||||||
|
formatted_name = formatted_name.split("\n")[0]
|
||||||
|
if len(formatted_name) > MAX_LENGTH:
|
||||||
|
formatted_name = formatted_name[: MAX_LENGTH - 3] + "..."
|
||||||
|
|
||||||
|
ret = json.dumps(
|
||||||
|
{
|
||||||
|
"name": window_name,
|
||||||
|
"class": window_class,
|
||||||
|
"formatted_name": formatted_name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
print(ret)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
12
home/.config/eww/scripts/workspaces
Executable file
12
home/.config/eww/scripts/workspaces
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# shellcheck source=include
|
||||||
|
source "./scripts/include"
|
||||||
|
|
||||||
|
if [ "$1" = "--switch" ]; then
|
||||||
|
hyprctl dispatch focusworkspaceoncurrentmonitor "$2" >/dev/null
|
||||||
|
elif [ "$1" = "--loop" ]; then
|
||||||
|
hyprland_ipc "workspace|createworkspace|destroyworkspace" | ./scripts/workspaces.py "$@"
|
||||||
|
else
|
||||||
|
./scripts/workspaces.py "$@"
|
||||||
|
fi
|
188
home/.config/eww/scripts/workspaces.py
Executable file
188
home/.config/eww/scripts/workspaces.py
Executable file
|
@ -0,0 +1,188 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from typing import TypedDict, TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from _typeshed import SupportsRichComparison
|
||||||
|
|
||||||
|
|
||||||
|
class WorkspaceInfo(TypedDict):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
monitor: str
|
||||||
|
windows: int
|
||||||
|
hasfullscreen: bool
|
||||||
|
lastwindow: str
|
||||||
|
lastwindowtitle: str
|
||||||
|
|
||||||
|
|
||||||
|
class ActiveWorkspaceInfo(TypedDict):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
class MonitorInfo(TypedDict):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
make: str
|
||||||
|
model: str
|
||||||
|
width: int
|
||||||
|
height: int
|
||||||
|
refreshRate: float
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
activeWorkspace: ActiveWorkspaceInfo
|
||||||
|
reserved: list[int]
|
||||||
|
scale: float
|
||||||
|
transform: int
|
||||||
|
focused: bool
|
||||||
|
dpmsStatus: bool
|
||||||
|
vrr: bool
|
||||||
|
|
||||||
|
|
||||||
|
class OutputWorkspaceInfo(WorkspaceInfo):
|
||||||
|
format_name: str
|
||||||
|
active: bool
|
||||||
|
monitor_id: int
|
||||||
|
|
||||||
|
|
||||||
|
# workspace id -> remapped name
|
||||||
|
REMAPS = {
|
||||||
|
1: "",
|
||||||
|
2: "",
|
||||||
|
3: "",
|
||||||
|
4: "",
|
||||||
|
5: "",
|
||||||
|
6: "",
|
||||||
|
7: "7",
|
||||||
|
8: "8",
|
||||||
|
9: "9",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Skip the special (scratchpad) workspace
|
||||||
|
SKIP = {-99}
|
||||||
|
|
||||||
|
|
||||||
|
def workspace_sort(obj: OutputWorkspaceInfo) -> "SupportsRichComparison":
|
||||||
|
"""Returns a key to sort by, given the current element."""
|
||||||
|
return obj["id"]
|
||||||
|
|
||||||
|
|
||||||
|
def fill_blank_workspaces(open: list[OutputWorkspaceInfo]) -> list[OutputWorkspaceInfo]:
|
||||||
|
"""Add in the rest of the workspaces which don't have any open windows on them.
|
||||||
|
|
||||||
|
This is needed because hyprland deletes workspaces with nothing in them.
|
||||||
|
Note that this assumes all available workspaces were listed in REMAPS, and will
|
||||||
|
only fill those. These blank workspaces will have most string values set to "N/A",
|
||||||
|
and most int values set to 0.
|
||||||
|
"""
|
||||||
|
# Work on a copy, we don't want to alter the original list
|
||||||
|
lst = open.copy()
|
||||||
|
|
||||||
|
for remap_id, format_name in REMAPS.items():
|
||||||
|
# Skip for already present workspaces
|
||||||
|
if any(ws_info["id"] == remap_id for ws_info in lst):
|
||||||
|
continue
|
||||||
|
|
||||||
|
blank_ws: OutputWorkspaceInfo = {
|
||||||
|
"id": remap_id,
|
||||||
|
"name": str(remap_id),
|
||||||
|
"monitor": "N/A",
|
||||||
|
"windows": 0,
|
||||||
|
"hasfullscreen": False,
|
||||||
|
"lastwindow": "N/A",
|
||||||
|
"lastwindowtitle": "N/A",
|
||||||
|
"active": False,
|
||||||
|
"format_name": format_name,
|
||||||
|
"monitor_id": 0,
|
||||||
|
}
|
||||||
|
lst.append(blank_ws)
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
|
||||||
|
def get_workspaces() -> list[OutputWorkspaceInfo]:
|
||||||
|
"""Obtain workspaces from hyprctl, sort them and add format_name arg."""
|
||||||
|
proc = subprocess.run(["hyprctl", "workspaces", "-j"], stdout=subprocess.PIPE)
|
||||||
|
proc.check_returncode()
|
||||||
|
try:
|
||||||
|
workspaces: list[WorkspaceInfo] = json.loads(proc.stdout)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
sys.stderr.writelines([
|
||||||
|
"Error decoding json response from hyprctl, returning empty workspaces",
|
||||||
|
f"Actual captured output from hyprctl: {proc.stdout!r}"
|
||||||
|
])
|
||||||
|
sys.stderr.flush()
|
||||||
|
workspaces = []
|
||||||
|
|
||||||
|
proc = subprocess.run(["hyprctl", "monitors", "-j"], stdout=subprocess.PIPE)
|
||||||
|
proc.check_returncode()
|
||||||
|
monitors: list[MonitorInfo] = json.loads(proc.stdout)
|
||||||
|
|
||||||
|
active_workspaces = {monitor["activeWorkspace"]["id"] for monitor in monitors}
|
||||||
|
|
||||||
|
out: list[OutputWorkspaceInfo] = []
|
||||||
|
for workspace in workspaces:
|
||||||
|
if workspace["id"] in SKIP:
|
||||||
|
continue
|
||||||
|
format_name = REMAPS.get(workspace["id"], workspace["name"])
|
||||||
|
active = workspace["id"] in active_workspaces
|
||||||
|
try:
|
||||||
|
mon_id = [monitor["id"] for monitor in monitors if monitor["name"] == workspace["monitor"]][0]
|
||||||
|
except IndexError: # Sometimes workspace["monitor"] is "?", which doesn't match any monitor
|
||||||
|
mon_id = -1
|
||||||
|
out.append({**workspace, "format_name": format_name, "active": active, "monitor_id": mon_id})
|
||||||
|
|
||||||
|
out = fill_blank_workspaces(out)
|
||||||
|
out.sort(key=workspace_sort)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def print_workspaces() -> None:
|
||||||
|
wks = get_workspaces()
|
||||||
|
ret = json.dumps(wks)
|
||||||
|
print(ret)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"--oneshot",
|
||||||
|
action="store_true",
|
||||||
|
help="Don't listen to stdout for updates, only run once and quit",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--loop",
|
||||||
|
action="store_true",
|
||||||
|
help="Listen to stdout input, once something is received, re-print workspaces"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.loop and args.oneshot:
|
||||||
|
print("Can't use both --oneshot and --loop", file=sys.stdout)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.loop is None and args.oneshot is None:
|
||||||
|
print("No option specified!", file=sys.stdout)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Print workspaces here immediately, we don't want to have to wait for the first
|
||||||
|
# update from stdin as we only receive those on actual workspace change.
|
||||||
|
print_workspaces()
|
||||||
|
|
||||||
|
if args.oneshot:
|
||||||
|
# We've already printed the workspaces once, we can exit now
|
||||||
|
return
|
||||||
|
|
||||||
|
# Reprint workspaces on each stdin update (flush)
|
||||||
|
for _ in sys.stdin:
|
||||||
|
print_workspaces()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
14
home/.config/eww/windows/calendar.yuck
Normal file
14
home/.config/eww/windows/calendar.yuck
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
(defwidget calendar-win []
|
||||||
|
(box
|
||||||
|
:class "calendar-win"
|
||||||
|
(calendar)))
|
||||||
|
|
||||||
|
(defwindow calendar
|
||||||
|
:monitor 0
|
||||||
|
:geometry (geometry
|
||||||
|
:x "0%"
|
||||||
|
:y "0%"
|
||||||
|
:anchor "top right"
|
||||||
|
:width "0px"
|
||||||
|
:height "0px")
|
||||||
|
(calendar-win))
|
78
home/.config/eww/windows/radio-menu.yuck
Normal file
78
home/.config/eww/windows/radio-menu.yuck
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
(defwidget radio-menu-win []
|
||||||
|
(box
|
||||||
|
:class "radio-menu-box"
|
||||||
|
:space-evenly false
|
||||||
|
:orientation "v"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:class "text-row"
|
||||||
|
:space-evenly false
|
||||||
|
(label
|
||||||
|
:class "title"
|
||||||
|
:text "Radio/Connections Panel"))
|
||||||
|
|
||||||
|
(box
|
||||||
|
:class "element-row"
|
||||||
|
|
||||||
|
(box
|
||||||
|
:class "wifi-box"
|
||||||
|
:space-evenly false
|
||||||
|
:orientation "v"
|
||||||
|
(box
|
||||||
|
:class "element icon"
|
||||||
|
:space-evenly false
|
||||||
|
:halign "center"
|
||||||
|
(button
|
||||||
|
:class "wifi-button"
|
||||||
|
:tooltip "${net.state} (strength: ${net.signal}%)"
|
||||||
|
:onclick "scripts/net toggle"
|
||||||
|
{net.icon})
|
||||||
|
(label
|
||||||
|
:class "separator"
|
||||||
|
:text "│")
|
||||||
|
(button
|
||||||
|
:class "wifi-arrow-btn"
|
||||||
|
:onclick "eww close radio-menu && nm-connection-editor &"
|
||||||
|
""))
|
||||||
|
(label
|
||||||
|
:text {net.essid}
|
||||||
|
:xalign 0.5
|
||||||
|
:limit-width 15))
|
||||||
|
|
||||||
|
(box
|
||||||
|
:class "bluetooth-box"
|
||||||
|
:space-evenly false
|
||||||
|
:orientation "v"
|
||||||
|
(box
|
||||||
|
:class "element icon"
|
||||||
|
:space-evenly false
|
||||||
|
:halign "center"
|
||||||
|
(button
|
||||||
|
:class "bluetooth-button"
|
||||||
|
:onclick "scripts/bluetooth toggle"
|
||||||
|
:tooltip "${bluetooth.name} (${bluetooth.mac}) ${bluetooth.battery}"
|
||||||
|
{bluetooth.icon})
|
||||||
|
(label
|
||||||
|
:class "separator"
|
||||||
|
:text "│")
|
||||||
|
(button
|
||||||
|
:class "bluetooth-arrow-btn"
|
||||||
|
:onclick "eww close radio-menu && blueberry"
|
||||||
|
""))
|
||||||
|
(label
|
||||||
|
:text {bluetooth.name}
|
||||||
|
:xalign 0.5
|
||||||
|
:tooltip "${bluetooth.name} (${bluetooth.mac}) ${bluetooth.battery}"
|
||||||
|
:limit-width 15)))
|
||||||
|
))
|
||||||
|
|
||||||
|
(defwindow radio-menu
|
||||||
|
:stacking "fg"
|
||||||
|
:monitor 0
|
||||||
|
:geometry (geometry
|
||||||
|
:x "0"
|
||||||
|
:y "0"
|
||||||
|
:width "0%"
|
||||||
|
:height "0%"
|
||||||
|
:anchor "right top")
|
||||||
|
(radio-menu-win))
|
18
home/.config/systemd/user/eww-window@.service
Normal file
18
home/.config/systemd/user/eww-window@.service
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Open %I eww window
|
||||||
|
After=graphical-session.target
|
||||||
|
After=eww.service
|
||||||
|
PartOf=eww.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStartPre=/usr/bin/eww ping
|
||||||
|
ExecStart=/usr/bin/eww open %i
|
||||||
|
ExecStop=/usr/bin/eww close %i
|
||||||
|
RemainAfterExit=true
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3s
|
||||||
|
Slice=session-graphical.slice
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
14
home/.config/systemd/user/eww.service
Normal file
14
home/.config/systemd/user/eww.service
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Eww daemon
|
||||||
|
After=graphical-session.target
|
||||||
|
After=pipewire.service
|
||||||
|
Requires=graphical-session.target
|
||||||
|
Requires=pipewire.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/eww daemon --no-daemonize
|
||||||
|
Restart=always
|
||||||
|
Slice=session-graphical.slice
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
|
@ -130,8 +130,9 @@ paru -S --noconfirm --needed hyprlock hypridle systemd-lock-handler
|
||||||
|
|
||||||
# Temporary
|
# Temporary
|
||||||
# TODO: Swaync should be replaced by quickshell (also remove swaync.service)
|
# TODO: Swaync should be replaced by quickshell (also remove swaync.service)
|
||||||
|
# TODO: Eww should be replaced by quickshell (also remove associated services)
|
||||||
# TODO: Quickshell should be moved outside of temporary once config is ready
|
# TODO: Quickshell should be moved outside of temporary once config is ready
|
||||||
paru -S --noconfirm --needed quickshell swaync
|
paru -S --noconfirm --needed quickshell swaync eww
|
||||||
|
|
||||||
# Dconf/Gsettings
|
# Dconf/Gsettings
|
||||||
paru -S --needed --noconfirm dconf
|
paru -S --needed --noconfirm dconf
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue