Move waybar into its own role that sway depends on.

This commit is contained in:
Tom Alexander
2022-11-25 15:35:36 -05:00
parent 2222c9d033
commit 7c6c81711b
22 changed files with 104 additions and 49 deletions

View File

@@ -0,0 +1,201 @@
/* Work-around for regressions introduced in 0.9.15 */
* {
all: unset;
}
/* -----------------------------------------------------------------------------
* Keyframes
* -------------------------------------------------------------------------- */
@keyframes blink-warning {
70% {
color: white;
}
to {
color: white;
background-color: orange;
}
}
@keyframes blink-critical {
70% {
color: white;
}
to {
color: white;
background-color: red;
}
}
/* -----------------------------------------------------------------------------
* Base styles
* -------------------------------------------------------------------------- */
/* Reset all styles */
* {
border: none;
border-radius: 0;
min-height: 0;
margin: 0;
padding: 0;
}
/* The whole bar */
#waybar {
background: #323232;
color: white;
font-family: Cascadia Mono, monospace;
font-size: 10px;
}
/* Each module */
#battery,
#clock,
#cpu,
#custom-available_memory,
#custom-battery,
#custom-clock,
#custom-sound,
#custom-temperature,
#idle_inhibitor,
#memory,
#mode,
#network,
#pulseaudio,
#temperature,
#tray {
padding-left: 10px;
padding-right: 10px;
border: 1px solid white;
}
/* -----------------------------------------------------------------------------
* Module styles
* -------------------------------------------------------------------------- */
#battery {
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
}
#custom-battery.warning {
color: orange;
}
#custom-battery.critical {
color: red;
}
#battery.warning.discharging {
animation-name: blink-warning;
animation-duration: 3s;
}
#battery.critical.discharging {
animation-name: blink-critical;
animation-duration: 2s;
}
#clock {
font-weight: bold;
}
#custom-clock {
font-weight: bold;
}
#cpu {
/* No styles */
}
#cpu.warning {
color: orange;
}
#cpu.critical {
color: red;
}
#memory {
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
}
#memory.warning {
color: orange;
}
#memory.critical {
color: red;
animation-name: blink-critical;
animation-duration: 2s;
}
#mode {
background: #64727D;
border-top: 2px solid white;
/* To compensate for the top border and still have vertical centering */
padding-bottom: 2px;
}
#network {
/* No styles */
}
#network.disconnected {
color: orange;
}
#pulseaudio {
/* No styles */
}
#pulseaudio.muted {
/* No styles */
}
#custom-spotify {
color: rgb(102, 220, 105);
}
#temperature {
/* No styles */
}
#temperature.critical {
color: red;
}
#tray {
/* No styles */
}
#window {
font-weight: bold;
}
#workspaces button {
border-top: 2px solid transparent;
/* To compensate for the top border and still have vertical centering */
padding-bottom: 2px;
padding-left: 10px;
padding-right: 10px;
color: #888888;
}
#workspaces button.focused {
border-color: #4c7899;
color: white;
background-color: #285577;
}
#workspaces button.urgent {
border-color: #c9545d;
color: #c9545d;
}

View File

@@ -0,0 +1,47 @@
{
// "height": 10, // Waybar height (to be removed for auto height)
"modules-left": ["sway/workspaces", "sway/mode"],
"modules-right": ["custom/temperature", "custom/sound", "custom/available_memory", "custom/battery", "idle_inhibitor", "custom/clock", "tray"],
"sway/workspaces": {
"disable-scroll": true
},
"sway/mode": {
"format": "<span style=\"italic\">{}</span>"
},
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "",
"deactivated": ""
}
},
"tray": {
// "icon-size": 21,
"spacing": 10
},
"custom/clock": {
"exec": "waybar_custom_clock",
"return-type": "json",
"restart-interval": 30
},
"custom/battery": {
"exec": "waybar_custom_battery",
"return-type": "json",
"restart-interval": 30
},
"custom/available_memory": {
"exec": "waybar_custom_available_memory",
"return-type": "json",
"restart-interval": 30
},
"custom/sound": {
"exec": "waybar_custom_sound",
"return-type": "json",
"restart-interval": 30
},
"custom/temperature": {
"exec": "waybar_custom_temperature",
"return-type": "json",
"restart-interval": 30
}
}

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
#
# Read memory usage in FreeBSD
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SLEEP_INTERVAL=${SLEEP_INTERVAL:-30}
while true; do
# TODO: Why not vm.stats.vm.v_page_size ? Are these the same?
page_size=$(sysctl -n hw.pagesize)
free_pages=$(sysctl -n vm.stats.vm.v_free_count)
free_bytes=$((page_size * free_pages))
total_pages=$(sysctl -n vm.stats.vm.v_page_count)
free_percent=$((100 * free_pages / total_pages))
text=""
if [ $free_bytes -ge $((1024 * 1024 * 1024)) ]; then
text="$((free_bytes / 1024 / 1024 / 1024)) GiB"
fi
tooltip="${free_percent}%"
jq --unbuffered --compact-output <<EOF
{
"text":"${text}",
"tooltip":"${tooltip}",
"percentage":${free_percent}
}
EOF
sleep $SLEEP_INTERVAL
done

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
#
# Read memory usage in Linux
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SLEEP_INTERVAL=${SLEEP_INTERVAL:-30}
while true; do
memory_usage=$(free --bytes --wide)
total_bytes=$(grep 'Mem:' <<<"$memory_usage" | awk '{print $2}')
free_bytes=$(grep 'Mem:' <<<"$memory_usage" | awk '{print $4}')
free_percent=$((100 * free_bytes / total_bytes))
text=""
if [ $free_bytes -ge $((1024 * 1024 * 1024)) ]; then
text="$((free_bytes / 1024 / 1024 / 1024)) GiB"
fi
tooltip="${free_percent}%"
jq --unbuffered --compact-output <<EOF
{
"text":"${text}",
"tooltip":"${tooltip}",
"percentage":${free_percent}
}
EOF
sleep $SLEEP_INTERVAL
done

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
#
# Read battery status in FreeBSD
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# TODO: Which is better, apm or reading sysctls from hw.acpi.battery ?
SLEEP_INTERVAL=${SLEEP_INTERVAL:-30}
while true; do
battery_percentage=$(apm -l)
battery_status=$(apm -b)
seconds_remaining=$(apm -t)
class=""
if [ $battery_status -eq 3 ]; then
if [ $battery_percentage -eq 100 ]; then
battery_icon=""
else
battery_icon=""
fi
elif [ $battery_percentage -le 20 ]; then
battery_icon=""
elif [ $battery_percentage -le 40 ]; then
battery_icon=""
elif [ $battery_percentage -le 60 ]; then
battery_icon=""
elif [ $battery_percentage -le 80 ]; then
battery_icon=""
elif [ $battery_percentage -lt 100 ]; then
battery_icon=""
else
battery_icon=""
fi
if [ $battery_percentage -le 15 ]; then
class="critical"
elif [ $battery_percentage -le 30 ]; then
class="warning"
fi
if [ $seconds_remaining -eq -1 ]; then
time_remaining="unknown time remaining."
else
time_remaining=$(printf '%dh:%dm:%ds\n' $((seconds_remaining/3600)) $((seconds_remaining%3600/60)) $((seconds_remaining%60)) )
fi
jq --unbuffered --compact-output <<EOF
{
"text":"${battery_percentage}% ${battery_icon}",
"tooltip":"${time_remaining}",
"percentage":${battery_percentage},
"class":"${class}"
}
EOF
sleep $SLEEP_INTERVAL
done

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
#
# Read battery status in Linux
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
batteries=$(upower --enumerate | grep BAT)
function generate_battery_update {
local battery_path=$1
local battery_status=$(upower --show-info "$battery_path")
local battery_state=$(grep 'state:' <<<"$battery_status" | awk '{print $2}')
local battery_percentage=$(grep 'percentage:' <<<"$battery_status" | awk '{print $2}')
battery_percentage=${battery_percentage%\%}
local time_remaining=$(grep 'time to empty:' <<<"$battery_status" | sed 's/\W*time to empty:\W*//g')
local tooltip="$time_remaining until empty"
if [ -z "$time_remaining" ]; then
time_remaining=$(grep 'time to full:' <<<"$battery_status" | sed 's/\W*time to full:\W*//g')
tooltip="$time_remaining until full"
fi
local battery_icon=""
local class=""
if [ $battery_state = "charging" ]; then
if [ $battery_percentage -eq 100 ]; then
battery_icon=""
else
battery_icon=""
fi
elif [ $battery_percentage -le 20 ]; then
battery_icon=""
elif [ $battery_percentage -le 40 ]; then
battery_icon=""
elif [ $battery_percentage -le 60 ]; then
battery_icon=""
elif [ $battery_percentage -le 80 ]; then
battery_icon=""
elif [ $battery_percentage -lt 100 ]; then
battery_icon=""
else
battery_icon=""
fi
if [ $battery_percentage -le 15 ]; then
class="critical"
elif [ $battery_percentage -le 30 ]; then
class="warning"
fi
jq --unbuffered --compact-output <<EOF
{
"text":"${battery_percentage}% ${battery_icon}",
"tooltip":"$tooltip",
"percentage":${battery_percentage},
"class":"${class}"
}
EOF
}
while read bat; do
generate_battery_update "$bat"
done<<<"$batteries"
upower --monitor | grep --line-buffered 'device changed:' | while read l; do
while read bat; do
generate_battery_update "$bat"
done<<<"$batteries"
done

View File

@@ -0,0 +1,108 @@
#!/usr/bin/env python
#
# Custom waybar module for clocks. Implemented because the official clock module was downloading timezone definitions on every boot.
import datetime
import json
import sys
import time
from dataclasses import dataclass
from functools import lru_cache
from typing import Final, List, Optional
from zoneinfo import ZoneInfo
INTERVAL: Final[int] = 10
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
@dataclass
class Update:
text: Optional[str]
alt: Optional[str]
tooltip: Optional[str]
css_class: Optional[List[str]]
percentage: Optional[str]
def dump(self) -> str:
# Dump a dict because we can't name our member variable "class"
return json.dumps(
{
k: v
for k, v in {
"text": self.text,
"alt": self.alt,
"tooltip": self.tooltip,
"class": self.css_class,
"percentage": self.percentage,
}.items()
if v is not None
}
)
@lru_cache(maxsize=1)
def make_calendar(today: datetime.date, tz: datetime.tzinfo):
width: Final[int] = 20
start_of_month = today.replace(day=1)
month_header = today.strftime("%B %Y")
padding = width - len(month_header)
right_padding = " " * (padding // 2)
left_padding = right_padding + (" " if padding % 2 == 1 else "")
header = f"{left_padding}{month_header}{right_padding}"
days_of_week = "Su Mo Tu We Th Fr Sa"
timezone_str = str(tz)
# Make the grid
first_day_padding = " " * (
0 if start_of_month.weekday() == 6 else (3 * (1 + start_of_month.weekday())) - 1
)
output = f"{header}\n{days_of_week}\n{first_day_padding}"
print_day = start_of_month
while print_day.month == today.month:
if print_day.weekday() == 6:
output += "\n"
else:
output += " "
if print_day == today:
output += '<span foreground="#323232" background="#CCCCCC">'
output += f"{print_day.day: >2}"
if print_day == today:
output += "</span>"
print_day += datetime.timedelta(days=1)
output += f'\n<span size="small">{timezone_str}</span>'
return output
def main():
tz: Optional[datetime.tzinfo] = (
ZoneInfo(sys.argv[1]) if len(sys.argv) >= 2 else LOCAL_TIMEZONE
)
if tz is None:
raise Exception("Failed to detect timezone.")
next_update = time.time()
while True:
time_before_next_update = next_update - time.time()
if time_before_next_update > 0:
time.sleep(time_before_next_update)
next_update = time.time() + INTERVAL
now = datetime.datetime.now(tz=tz)
text = now.strftime("%Y-%m-%d %H:%M")
tooltip = make_calendar(now.date(), tz)
out = Update(
text=text,
alt="foo",
tooltip=f"<tt>{tooltip}</tt>",
css_class=["foo"],
percentage="100",
)
print(out.dump(), flush=True)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
#
# Read volume status in FreeBSD
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SLEEP_INTERVAL=${SLEEP_INTERVAL:-30}
while true; do
current_vol_mixer=$(mixer -S vol)
vol_left=$(cut -d ':' -f 2 <<<"$current_vol_mixer")
vol_right=$(cut -d ':' -f 3 <<<"$current_vol_mixer")
avg_vol=$(((vol_left + vol_right) / 2))
tooltip="<tt>$(mixer)</tt>"
class=""
icon=""
if [ $avg_vol -eq 0 ]; then
icon="🔇"
elif [ $avg_vol -le 50 ]; then
icon="🔉"
else
icon="🔊"
fi
jq --unbuffered --compact-output <<EOF
{
"text":"${avg_vol}% ${icon}",
"tooltip":"${tooltip//$'\n'/\\n}",
"percentage":${avg_vol},
"class":"${class}"
}
EOF
sleep $SLEEP_INTERVAL
done

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
#
# Read volume status in Linux
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SLEEP_INTERVAL=${SLEEP_INTERVAL:-30}
while true; do
current_vol_decimal=$(wpctl get-volume @DEFAULT_AUDIO_SINK@ | sed 's/Volume: //g')
if [[ "$current_vol_decimal" = *MUTED* ]]; then
current_vol_percent=0
else
current_vol_percent=$(bc -s <<<"$current_vol_decimal * 100")
current_vol_percent=${current_vol_percent%.*} # Remove decimal
fi
tooltip="<tt>$(wpctl status)</tt>"
tooltip=${tooltip//$'\n'/\\n}
tooltip=${tooltip//$'\t'/\\t}
class=""
icon=""
if [ $current_vol_percent -eq 0 ]; then
icon="🔇"
elif [ $current_vol_percent -le 50 ]; then
icon="🔉"
else
icon="🔊"
fi
jq --unbuffered --compact-output <<EOF
{
"text":"${current_vol_percent}% ${icon}",
"tooltip":"${tooltip}",
"percentage":${current_vol_percent},
"class":"${class}"
}
EOF
sleep $SLEEP_INTERVAL
done

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env bash
#
# Read temperature status in FreeBSD
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SLEEP_INTERVAL=${SLEEP_INTERVAL:-30}
while true; do
current_cpu_temps=$(sysctl 'dev.cpu' | grep -E 'dev\.cpu\.[0-9]+\.temperature')
sum_temperature=0
num_temperature=0
max_temperature=0
while read temp; do
numeric_temp=$(echo "$temp" | cut -d ':' -f 2 | grep -oE '[0-9]+(\.[0-9]+)?')
sum_temperature=$(bc -s <<<"$sum_temperature + $numeric_temp")
num_temperature=$((num_temperature + 1))
max_temperature=$(bc <<EOF
define max(a,b){
if(a>b)
{
return(a)
}else{
return(b)
}
}
max($max_temperature,$numeric_temp)
EOF
)
done<<<"$current_cpu_temps"
avg_temperature=$(bc -s <<<"$sum_temperature / $num_temperature")
tooltip="<tt>$current_cpu_temps</tt>"
class=""
icon="🌡"
jq --unbuffered --compact-output <<EOF
{
"text":"${max_temperature}℃ ${icon}",
"tooltip":"${tooltip//$'\n'/\\n}",
"percentage":50,
"class":"${class}"
}
EOF
sleep $SLEEP_INTERVAL
done

View File

@@ -0,0 +1,2 @@
dependencies:
- users

View File

@@ -0,0 +1,25 @@
- name: Install scripts
copy:
src: "files/waybar_scripts/{{ item.src }}"
dest: "{{ item.dest }}"
mode: 0755
owner: root
group: wheel
loop:
- src: waybar_custom_clock.py
dest: /usr/local/bin/waybar_custom_clock
- import_tasks: tasks/freebsd.yaml
when: 'os_flavor == "freebsd"'
- import_tasks: tasks/linux.yaml
when: 'os_flavor == "linux"'
- include_tasks:
file: tasks/peruser.yaml
apply:
become: yes
become_user: "{{ initialize_user }}"
loop: "{{ users | dict2items | community.general.json_query('[?value.initialize==`true`].key') }}"
loop_control:
loop_var: initialize_user

View File

@@ -0,0 +1,22 @@
- name: Install packages
package:
name:
- waybar
state: present
- name: Install scripts
copy:
src: "files/waybar_scripts/{{ item.src }}"
dest: "{{ item.dest }}"
mode: 0755
owner: root
group: wheel
loop:
- src: waybar_battery_freebsd.bash
dest: /usr/local/bin/waybar_custom_battery
- src: waybar_available_memory_freebsd.bash
dest: /usr/local/bin/waybar_custom_available_memory
- src: waybar_sound_freebsd.bash
dest: /usr/local/bin/waybar_custom_sound
- src: waybar_temperature_freebsd.bash
dest: /usr/local/bin/waybar_custom_temperature

View File

@@ -0,0 +1,21 @@
- name: Install packages
package:
name:
- bc # For waybar sound script
- upower # Needed for waybar battery script
state: present
- name: Install scripts
copy:
src: "files/waybar_scripts/{{ item.src }}"
dest: "{{ item.dest }}"
mode: 0755
owner: root
group: wheel
loop:
- src: waybar_battery_linux.bash
dest: /usr/local/bin/waybar_custom_battery
- src: waybar_available_memory_linux.bash
dest: /usr/local/bin/waybar_custom_available_memory
- src: waybar_sound_linux.bash
dest: /usr/local/bin/waybar_custom_sound

View File

@@ -0,0 +1,2 @@
- import_tasks: tasks/common.yaml
when: install_graphics is defined and install_graphics

View File

@@ -0,0 +1,31 @@
- include_role:
name: per_user
- name: Create directories
file:
name: "{{ account_homedir.stdout }}/{{ item }}"
state: directory
mode: 0700
owner: "{{ account_name.stdout }}"
group: "{{ group_name.stdout }}"
loop:
- ".config/waybar"
- name: Copy files
copy:
src: "files/{{ item.src }}"
dest: "{{ account_homedir.stdout }}/{{ item.dest }}"
mode: 0600
owner: "{{ account_name.stdout }}"
group: "{{ group_name.stdout }}"
loop:
- src: waybar_config.json
dest: .config/waybar/config
- src: style.css
dest: .config/waybar/style.css
- import_tasks: tasks/peruser_freebsd.yaml
when: 'os_flavor == "freebsd"'
- import_tasks: tasks/peruser_linux.yaml
when: 'os_flavor == "linux"'