mirror of
				https://github.com/ItsDrike/dotfiles.git
				synced 2025-10-30 07:36:36 +00:00 
			
		
		
		
	Temporarily re-add eww
This commit is contained in:
		
							parent
							
								
									aedbfed456
								
							
						
					
					
						commit
						4dcf5244cf
					
				
					 49 changed files with 1731 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; } | ||||
| } | ||||
							
								
								
									
										9
									
								
								home/.config/eww/css/modules/_volume.scss
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								home/.config/eww/css/modules/_volume.scss
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| .volume { | ||||
|   .icon { color: $peach; } | ||||
|   .speaker { | ||||
|     .icon { | ||||
|       margin-left: 8px; | ||||
|       margin-right: 5px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										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 | ||||
| # 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 | ||||
| paru -S --noconfirm --needed quickshell swaync | ||||
| paru -S --noconfirm --needed quickshell swaync eww | ||||
| 
 | ||||
| # Dconf/Gsettings | ||||
| paru -S --needed --noconfirm dconf | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue