Unified EWW config

This commit is contained in:
Ezri Brimhall 2024-03-07 13:49:47 -07:00
parent e5cc36a647
commit 1dd4f8d8e4
Signed by: ezri
GPG Key ID: D4EE46AFBD899DB5
87 changed files with 802 additions and 4113 deletions

View File

@ -1,115 +0,0 @@
@import 'colors';
* {
all: unset;
}
.root {
color: $foreground;
font-family: "Source Code Pro";
font-size: 7.5pt;
background-color: rgba(0,0,0,0);
// Probably needs to change
&.bar {
margin: 10px;
margin-bottom: 0px;
}
&.side {
margin: 10px;
margin-right: 0px;
}
}
.gauge {
color: $foreground;
}
.gauge-hole {
color: $wallpaper;
}
.gauge-gutter {
color: $bg0;
}
.icon {
font-family: "Font Awesome 5 Free Solid";
}
.invisible {
color: $wallpaper;
}
.highlight {
color: $red;
}
.offline {
color: $bg1;
}
.special {
color: $blue;
}
.green {
color: $green;
}
.message-overlay {
background-color: $wallpaper;
}
.nebula {
font-family: "Nebula";
font-size: 1.2em;
&.big, .big {
font-size: 2.4em;
}
&.bigger, .bigger {
font-size: 2.9em;
}
&.medium, .medium {
font-size: 1.6em;
}
&.medium-big, .medium-big {
font-size: 2em;
}
}
.big .normal, .bigger .normal {
font-size: 1rem;
}
// sway module
.sway--ws {
.fill {
background-color: $foreground;
}
color: $bg1;
&.sway--active {
color: $foreground;
}
&.sway--visible {
color: $blue;
}
&.sway--focused {
}
}
// clock module
.clock--time {
font-size: 20pt;
}
.clock--date {
font-size: 9pt;
}

View File

@ -1,130 +0,0 @@
;; Include modules
(include "./modules/workspaces/workspaces.yuck")
(include "./modules/clock/clock.yuck")
(include "./modules/system/system.yuck")
(include "./modules/network/network.yuck")
(include "./modules/volume/volume.yuck")
(include "./modules/timer/timer.yuck")
;; Windows
(defwidget leftbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(system-name)))
(defwidget leftbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(met)
))
(defwidget leftbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(sway-workspace :group "left")
(sway-workspaces :group "left")))
(defwidget rightbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "right")
(sway-workspace :group "right")))
(defwidget rightbar--hypr-left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(hypr-workspaces :group "main")
(hypr-workspace :group "main")))
(defwidget rightbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(met)
))
(defwidget rightbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "leftbox"
(system-name)))
(defwidget sidebar []
(box :orientation "v"
:valign "start"
:space-evenly false
:spacing 20
:class "bar root"
(sideclock)
(network-details)
(system-gauges)
))
(defwindow leftbar
:monitor 1
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root"
(leftbar--left)
(leftbar--center)
(leftbar--right)))
(defwindow rightbar
:monitor 0
:geometry (geometry :width "100%"
:height "26px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root"
(rightbar--left)
(rightbar--center)
(rightbar--right)))
(defwindow hypr-mainbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "overlay"
(centerbox :orientation "h" :class "bar root"
(rightbar--hypr-left)
(rightbar--center)
(rightbar--right)))
(defwindow sidebar
:monitor 1
:geometry (geometry :width "210px"
:height "1044px"
:anchor "left bottom")
:exclusive true
:focusable false
:stacking "fg"
(sidebar))

View File

@ -1,11 +0,0 @@
(defwidget left-angle []
(image :path "/home/ezri/.config/eww.new/modules/angles/left.png"
:width 150
:height 36))
(defwidget right-angle []
(image :path "/home/ezri/.config/eww.new/modules/angles/right.png"
:width 150
:height 36))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,34 +0,0 @@
#!/usr/bin/env python3
import asyncio
import signal
from contextlib import suppress
import pulsectl_asyncio
import json
async def get_values(pulse):
sink = await pulse.get_sink_by_name("@DEFAULT_SINK@")
result = {
"mute": sink.mute == 1,
"volume": f"{int(sink.volume.value_flat * 100):2}"
}
print(json.dumps(result), flush=True)
return result
async def listen():
async with pulsectl_asyncio.PulseAsync("volume-monitor") as pulse:
await get_values(pulse)
async for _ in pulse.subscribe_events('sink'):
await get_values(pulse)
async def main():
listen_task = asyncio.create_task(listen())
for sig in (signal.SIGTERM, signal.SIGHUP, signal.SIGINT):
loop.add_signal_handler(sig, listen_task.cancel)
with suppress(asyncio.CancelledError):
await listen_task
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

View File

@ -1,17 +0,0 @@
(deflisten audio-data
`~/.config/eww/modules/audio.py`)
(defwidget volume [align]
(box :orientation "h"
:halign align
:class "module volume ${audio-data['mute'] ? 'muted' : ''}"
:space-evenly false
:spacing 0
(revealer :transition "none"
:reveal {!audio-data["mute"]}
"")
(revealer :transition "none"
:reveal {audio-data["mute"]}
"")
' ${audio-data["volume"]}%'))

View File

@ -1,67 +0,0 @@
(defpoll clock--data :interval "500ms"
`date +'{"hour": "%H", "minute": "%M", "second": "%S", "year": "%Y", "day": "%d", "month": "%m", "dow": "%A", "month_name": "%B", "unix": "%s"}'`)
(defvar clock--show "clock")
(defwidget clock []
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text "${clock--data['hour']}:${clock--data['minute']}")
(label :text "${clock--data['year']}-${clock--data['month']}-${clock--data['day']}")))
(defwidget sideclock []
(button :onclick "echo -n $(date +%Y-%d-%m) | wl-copy"
:onrightclick "echo -n $(date +%s) | wl-copy && eww update clock--show=unixtime && sleep 2 && eww update clock--show=clock"
(overlay
(box :class "module text nebula"
:spacing 0
:space-evenly false
:orientation "v"
(centerbox :class "bigger nebula"
:space-evenly false
:width 150
:halign "center"
:orientation "h"
(box :halign "start" "${clock--data.hour}")
(box :halign "center" ":")
(box :halign "end" "${clock--data.minute}"))
(label :text "${clock--data.dow}"
:class "special")
(label :text "${clock--data.month_name} ${clock--data.day}"))
(box
:height 100
(revealer :transition "crossfade"
:reveal {clock--show == "unixtime"}
:duration {clock--show == "unixtime" ? "2s" : "500ms"}
(box :width 200
:height 50
:class "message-overlay nebula special"
(box
:space-evenly false
:spacing 0
:halign "center"
:valign "center"
:orientation "v"
"Copied UNIX"
"timestamp"
))))
(box
:height 100
(revealer :transition "crossfade"
:reveal {clock--show == "date"}
:duration {clock--show == "date" ? "2s" : "500ms"}
(box :width 200
:height 50
:class "message-overlay nebula special"
(box
:space-evenly false
:spacing 0
:halign "center"
:valign "center"
:orientation "v"
"Copied"
"current date"
)))))))

View File

@ -1,102 +0,0 @@
{
"1": {
"name": "1",
"use": "terminal",
"groups": ["left"]
},
"2": {
"name": "2",
"use": "code",
"groups": ["left"]
},
"3": {
"name": "3",
"use": "web",
"groups": ["left"]
},
"4": {
"groups": ["left"],
"name": "4",
"use": "project"
},
"5": {
"groups": ["left"],
"name": "5",
"use": "vms"
},
"6": {
"groups": ["left"],
"name": "6",
"use": "documents"
},
"7": {
"groups": ["left"],
"name": "7",
"use": "media"
},
"8": {
"groups": ["left"],
"name": "8",
"use": "discord"
},
"9": {
"groups": ["left"],
"name": "9",
"use": "zoom"
},
"10": {
"groups": ["left"],
"name": "10",
"use": "config"
},
"11": {
"groups": ["right"],
"name": "1",
"use": "terminal"
},
"12": {
"groups": ["right"],
"name": "2",
"use": "code"
},
"13": {
"groups": ["right"],
"name": "3",
"use": "web"
},
"14": {
"groups": ["right"],
"name": "4",
"use": "project"
},
"15": {
"groups": ["right"],
"name": "5",
"use": "misc"
},
"16": {
"groups": ["right"],
"name": "6",
"use": "documents"
},
"17": {
"groups": ["right"],
"name": "7",
"use": "media"
},
"18": {
"groups": ["right"],
"name": "8",
"use": "slack"
},
"19": {
"groups": ["right"],
"name": "9",
"use": "email"
},
"20": {
"groups": ["right"],
"name": "10",
"use": "config"
}
}

View File

@ -1,114 +0,0 @@
#!/usr/bin/env python3
import asyncio
import json
import os
from i3ipc.aio import Connection
from i3ipc import Event
from typing import List
class WorkspaceConfig:
i3_index: str
sorting_index: int
display_index: str
display_name: str
display_groups: List[str]
def __init__(self, i3_index: str, dictionary: dict):
self.i3_index = i3_index
self.sorting_index = dictionary.get("sort", int(i3_index))
self.display_index = dictionary["name"]
self.display_name = dictionary.get("use", "???")
self.display_groups = dictionary.get("groups", ['default'])
@classmethod
def parse_file(cls: type, filename: str):
result = []
dictionary: dict = None
with open(filename, 'r') as file:
dictionary = json.load(file)
for index, data in dictionary.items():
result.append(cls(index, data))
result.sort(key=lambda config: config.sorting_index)
return result
class WorkspaceStatus:
config: WorkspaceConfig
expanded: bool
state: str
active: bool
def __init__(self, config, state = None):
self.config = config
self.state = state or ""
self.active = state != None
self.expanded = state == "focused" or state == "visible"
def dict_dump(self):
return {
"i3_index": self.config.i3_index,
"name": self.config.display_index,
"purpose": self.config.display_name,
"expand": self.expanded,
"state": self.state,
"active": self.active
}
config = WorkspaceConfig.parse_file(f"{os.environ['HOME']}/.config/eww/modules/i3.json")
groups = []
for ws in config:
for group in ws.display_groups:
if not group in groups:
groups.append(group)
data = {
"ws": {},
"mode": "default"
}
def write_data():
global data
print(json.dumps(data), flush=True)
async def workspace_event(self: Connection, _):
global config, data
ws_i3_dict = { ws.name: ws for ws in await self.get_workspaces()}
status = []
for ws_def in config:
ws_i3 = ws_i3_dict.get(ws_def.i3_index, None)
if ws_i3:
state = ws_i3.focused and "focused" or ws_i3.visible and "visible" or ws_i3.urgent and "urgent" or "unfocused"
status.append(WorkspaceStatus(ws_def, state))
else:
status.append(WorkspaceStatus(ws_def))
for group in groups:
data['ws'][group] = [ ws.dict_dump() for ws in filter(lambda ws: group in ws.config.display_groups, status) ]
# data['ws']['left'] = [ ws.dict_dump() for ws in filter(lambda ws: ws.config.sorting_index in range(1, 11), status) ]
# data['ws']['right'] = [ ws.dict_dump() for ws in filter(lambda ws: ws.config.sorting_index in range(11, 21), status) ]
write_data()
async def mode_event(self: Connection, event):
global data
data['mode'] = event.change;
write_data()
async def main():
i3 = await Connection(auto_reconnect = True).connect()
i3.on(Event.WORKSPACE_FOCUS, workspace_event)
i3.on(Event.WORKSPACE_URGENT, workspace_event)
i3.on(Event.MODE, mode_event)
await workspace_event(i3, None)
await i3.main()
asyncio.run(main())

View File

@ -1,47 +0,0 @@
(defwidget workspace [description]
(revealer :transition "slideright"
:reveal {description["active"]}
:duration "500ms"
(button :onclick "i3-msg workspace ${description['i3_index']}"
(box :orientation "h"
:halign "start"
:class '${description["state"]} workspace'
:space-evenly false
:spacing 1
(revealer :transition "slideleft" :reveal {description["state"] == "urgent"} :duration "500ms"
" ")
{description["name"]}
(revealer :transition "slideright" :reveal {description["expand"]} :duration "500ms"
': ${description["purpose"]}')))))
(deflisten i3-data :initial "[]"
`~/.config/eww/modules/i3.py`)
(defwidget i3-mode [align]
(box :orientation "h"
:halign align
:space-evenly false
:spacing 0
:class "module i3-mode"
:visible {i3-data["mode"] != "default"}
"mode: ${i3-data['mode']}"))
(defwidget i3 [align group]
(box :orientation "h"
:halign align
:space-evenly false
:spacing 0
:class "module i3"
(workspace :description {i3-data["ws"][group][0]})
(workspace :description {i3-data["ws"][group][1]})
(workspace :description {i3-data["ws"][group][2]})
(workspace :description {i3-data["ws"][group][3]})
(workspace :description {i3-data["ws"][group][4]})
(workspace :description {i3-data["ws"][group][5]})
(workspace :description {i3-data["ws"][group][6]})
(workspace :description {i3-data["ws"][group][7]})
(workspace :description {i3-data["ws"][group][8]})
(workspace :description {i3-data["ws"][group][9]})
))

View File

@ -1,111 +0,0 @@
#!/usr/bin/env python3
import gi
import os
import sys
import json
import time
try:
gi.require_version('Playerctl', '2.0')
except:
sys.exit(1)
from gi.repository import Playerctl, GLib
title_maxlen = 30;
artist_maxlen = 30;
class Status:
def __init__(self):
self.running = False
self.playing = False
self.title = None
self.artist = None
self.album = None
self.album_artist = None
def _dict_dump(self):
return {
"running": self.running,
"playing": self.playing,
"title": self.title,
"artist": self.artist,
"album": self.album,
"album_artist": self.album_artist
}
def __str__(self):
return json.dumps(self._dict_dump())
class StatusDisplay:
def __init__(self):
self._player = None
def show(self):
self._init_player()
main = GLib.MainLoop()
main.run()
def _get_status(self, playing = None):
if self._player:
status = Status()
status.running = self._player.props.playback_status != 2
if playing == None:
status.playing = self._player.props.playback_status == 0
else:
status.playing = playing
status.title = self._player.get_title() or ""
status.artist = self._player.get_artist() or ""
status.album = self._player.get_album() or ""
if len(status.title) > title_maxlen:
status.title = status.title[:title_maxlen-1] + ''
if len(status.artist) > artist_maxlen:
status.artist = status.artist[:artist_maxlen-1] + ''
return status
else:
return Status()
def _print_status(self, status):
print(status, flush=True)
def _init_player(self):
success = False
while not success:
try:
self._player = Playerctl.Player()
self._player.connect('metadata', self._on_update)
self._player.connect('play', self._on_play)
self._player.connect('pause', self._on_pause)
self._player.connect('exit', self._on_exit)
self._print_status(self._get_status())
success = True
except:
self._print_status(Status())
time.sleep(2)
def _on_update(self, *args):
self._print_status(self._get_status())
def _on_play(self, *args):
self._print_status(self._get_status(playing=True))
def _on_pause(self, *args):
self._print_status(self._get_status(playing=False))
def _on_exit(self, player):
del self._player
self._player = None
self._init_player()
StatusDisplay().show()

View File

@ -1,17 +0,0 @@
(deflisten mpris-data
`~/.config/eww/modules/mpris.py`)
(defwidget mpris [align]
(box :orientation "h"
:halign align
:class "module mpris ${mpris-data['running'] ? '' : 'offline'} ${mpris-data['playing'] ? 'playing' : 'paused'}"
:space-evenly false
:spacing 0
(label :class "fontawesome"
:text "")
(revealer :transition "none"
:reveal {!mpris-data['running']}
" players offline")
(revealer :transition "none"
:reveal {mpris-data['running']}
" ${mpris-data['title']} by ${mpris-data['artist']}")))

View File

@ -1,64 +0,0 @@
#!/usr/bin/env python3
import subprocess
import json
import sys
from time import sleep
TRUSTED_NETWORKS = ['honnouji', 'honnouji_2.4']
def wifi():
ssid_cmd = subprocess.run(['iwgetid', '-r'], capture_output = True)
if ssid_cmd.returncode != 0:
return {"connected": False, "ssid": None}
return {"connected": True, "ssid": ssid_cmd.stdout.decode('utf-8').strip()}
def netdev(device: str):
ip_cmd = subprocess.run(['ip', '-j', 'addr', 'show', device], capture_output = True)
if ip_cmd.returncode != 0:
sys.stderr.write(ip_cmd.stdout.decode('utf-8'))
return {"exists": False, "online": False}
ip_data = json.loads(ip_cmd.stdout.decode('utf-8'))[0]
ip4_addr = ""
ip4_prefix_length = 24
addr4_info = list(filter(lambda addr: addr.get("family") == "inet", ip_data["addr_info"]))
if len(addr4_info) >= 1:
ip4_addr = addr4_info[0]["local"]
ip4_prefix_length = addr4_info[0]["prefixlen"]
online = ip_data["operstate"] == "UP" or ip4_addr != ""
connecting = ip_data["operstate"] != "DOWN" and (ip4_addr == "" or not online)
return {
"exists": True,
"online": online,
"connecting": connecting,
"offline": not online and not connecting,
"ip4_addr": ip4_addr,
"ip4_prefix": ip4_prefix_length
}
def trusted(ssid: str | None):
# Don't throw up an "INSECURE" alert when offline
if not ssid:
return True
return ssid in TRUSTED_NETWORKS
while True:
insight = netdev('insight')
wlan0 = netdev('wlan0')
wifi_data = wifi()
connected = insight['exists'] and insight['online'] or wifi_data['connected']
networks = {
"insight": insight,
"wlan0": netdev("wlan0"),
"ezrinet": netdev("ezrinet"),
"wg-mullvad": netdev("wg-mullvad"),
}
result = {
'connected': connected,
"network": networks,
'wifi': wifi_data,
"trusted": True,
"ip4_addrs": [ network.get('ip4_addr') for network in networks.values() if network.get('ip4_addr', "") != "" ]
}
print(json.dumps(result), flush=True)
sleep(1)

View File

@ -1,194 +0,0 @@
(deflisten network--data
`~/.config/eww/modules/network/network.py`)
(defwidget network--wlan [device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {network--data["network"][device]["offline"]}
:text "offline")
(label :visible {network--data["network"][device]["connecting"]}
:class "highlight"
:text "connecting...")
(label :visible {network--data["network"][device]["online"]}
:class "special"
:text "${network--data['wifi']['ssid']}")))
(defwidget network--lan [device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {network--data["network"][device]["offline"]}
:text "offline")
(label :visible {network--data["network"][device]["connecting"]}
:class "highlight"
:text "connecting...")
(label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting}
:class "special"
:text "${network--data['network'][device]['ip4_addr']}/${network--data['network'][device]['ip4_prefix']}")))
(defwidget network--proxy-vpn [device ?required]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data["network"][device]["exists"] || required}
(label :class "highlight"
:text "- insecure"
:visible {! network--data["network"][device]["exists"]})
(label :class "green"
:text "- secured"
:visible {network--data["network"][device]["exists"]})))
(defwidget proxy-network [device]
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
(label :class "green"
:text "connected"
:visible {network--data.network[device].exists})
(label :class "offline"
:text "offline"
:visible {!network--data.network[device].exists})
"proxy vpn"))
(defwidget vpn-network []
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
(label :class "highlight"
:text "offline"
:visible {! network--data["network"]["ezrinet"]["exists"] || ! network--data["connected"]})
(label :class "green"
:text "connected"
:visible {network--data["network"]["ezrinet"]["exists"] && network--data["connected"]})
"personal network"))
(defwidget network []
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 10
(network--lan :device "insight")
(network--proxy-vpn :device "wg-mullvad" :required {!network--data.trusted}))
"communications"))
(defwidget network-details []
(box :orientation "v"
:halign "start"
:class "module"
:space-evenly false
:spacing 5
:width 200
(box :orientation "h"
:halign "center"
:class "nebula"
:spacing 10
:space-evenly false
(label :text "Comms"
:class "medium special"))
(centerbox :orientation "h"
:halign "start"
:class "nebula"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
"Status:")
""
(box :halign "end"
(label :text "Online"
:class "green"
:visible {network--data.connected})
(label :text "Offline"
:class "highlight"
:visible {!network--data.connected})))
(centerbox :orientation "h"
:halign "start"
:class "nebula"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
"VPN:")
""
(box :halign "end"
(label :text "Connected"
:class "green"
:visible {network--data.network.ezrinet.online && network--data.connected})
(label :text "Offline"
:class "highlight"
:visible {!network--data.network.ezrinet.exists})))
(centerbox :orientation "h"
:halign "start"
:class "nebula"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
"Proxy:")
""
(box :halign "end"
(label :text "Connected"
:class "green"
:visible {network--data.network.wg-mullvad.online})
(label :text "Offline"
:class "highlight"
:visible {!network--data.network.wg-mullvad.exists})))
(centerbox :orientation "h"
:halign "start"
:class "nebula"
:spacing 10
:width 200
:space-evenly false
(box :halign "start"
"Wi-Fi:")
""
(box :halign "end"
(label :text {network--data.wifi.ssid}
:limit-width 12
:class "green"
:visible {network--data.wifi.connected})
(label :text "Offline"
:class "offline"
:visible {!network--data.wifi.connected})))
(centerbox :orientation "h"
:halign "start"
:spacing 10
:width 200
:class "nebula"
:space-evenly false
(box :valign "start"
:halign "start"
"Addrs:")
""
(box :valign "start"
:halign "end"
:visible {network--data.connected}
:orientation "v"
(for addr in {network--data.ip4_addrs}
(box :class "special"
:halign "end"
{addr}))
(box :visible {!network--data.connected}
:class "offline"
"none")))
;; (box :orientation "h"
;; :halign "start"
;; :class "nebula"
;; :spacing 10
;; :space-evenly false
;; (label :text "Addr:")
;; (label :text {network--data.network[device].ip4_addr}
;; :class "medium special"))))
))

View File

@ -1,10 +0,0 @@
#!/usr/bin/env zsh
installed="$(file /boot/vmlinuz-linux | cut -d',' -f2 | cut -d' ' -f3)"
running="$(uname -r)"
if [[ $installed == $running ]]; then
echo "false"
else
echo "true"
fi

View File

@ -1,66 +0,0 @@
#!/usr/bin/env python3
from time import sleep
import subprocess
import json
def static(**kwargs):
def decorate(func):
for k in kwargs:
setattr(func, k, kwargs[k])
return func
return decorate
@static(idle = 0, total = 0)
def cpu_util():
with open('/proc/stat') as file:
fields = [float(column) for column in file.readline().strip().split()[1:]]
idle = fields[3]
total = sum(fields)
idle_delta = idle - cpu_util.idle
total_delta = total - cpu_util.total
utilization = 100 * (1 - idle_delta / total_delta)
cpu_util.idle = idle
cpu_util.total = total
return f"{int(utilization):2}"
def wifi():
ssid_cmd = subprocess.run(['iwgetid', '-r'], capture_output = True)
if ssid_cmd.returncode != 0:
return {"connected": False, "ssid": ""}
return {"connected": True, "ssid": ssid_cmd.stdout.decode('utf-8').strip()}
def netdev(device: str):
ip_cmd = subprocess.run(['ip', '-j', 'addr', 'show', device], capture_output = True)
if ip_cmd.returncode != 0:
return {"exists": False}
ip_data = json.loads(ip_cmd.stdout.decode('utf-8'))[0]
online = ip_data["operstate"] == "UP"
ip4_addr = ""
ip4_prefix_length = 24
addr4_info = list(filter(lambda addr: addr.get("family") == "inet", ip_data["addr_info"]))
if len(addr4_info) >= 1:
ip4_addr = addr4_info[0]["local"]
ip4_prefix_length = addr4_info[0]["prefixlen"]
connecting = ip_data["operstate"] != "DOWN" and (ip4_addr == "" or not online)
return {
"exists": True,
"online": online,
"connecting": connecting,
"ip4_addr": ip4_addr,
"ip4_prefix": ip4_prefix_length
}
# Prime cpu_util() with starting values
cpu_util()
sleep(0.1)
while True:
result = {
"cpu": cpu_util(),
"network": {
"br0": netdev("br0")
}
}
print(json.dumps(result), flush=True)
sleep(1)

View File

@ -1,79 +0,0 @@
(deflisten system-data
`~/.config/eww/modules/system.py`)
(defpoll reboot-needed :interval "10s"
:initial false
`~/.config/eww/modules/reboot.sh`)
(defwidget reboot [align]
(box :orientation "h"
:halign align
:class "module reboot"
:space-evenly false
:spacing 0
:visible {reboot-needed}
(button :onclick "~/.local/bin/i3-reboot"
:timeout "60s"
" reboot required")))
(defwidget memory [align]
(box :orientation "h"
:halign align
:class "module memory"
:space-evenly false
:spacing 0
' ${round(EWW_RAM["used_mem"]/1024/1024, 2)} GiB'))
(defwidget cpu [align]
(box :orientation "h"
:halign align
:class "module cpu"
:space-evenly false
:spacing 0
' ${system-data["cpu"]}%'))
(defwidget wlan-dev [align device]
(box :orientation "h"
:halign align
:class "module wlan-dev network ${system-data['network'][device]['online'] ? 'online' : 'offline'} ${system-data['network'][device]['connecting'] ? 'connecting' : ''}"
:space-evenly false
:spacing 0
""
(revealer :transition "slideright"
:reveal {!system-data["network"][device]["online"] && !system-data["network"][device]["connecting"]}
:duration "500ms"
" offline")
(revealer :transition "slideright"
:reveal {system-data["network"][device]["connecting"]}
:duration "500ms"
" connecting...")
(revealer :transition "slideright"
:reveal {system-data["network"][device]["online"] && system-data["network"][device]["ip4_addr"] != ""}
:duration "500ms"
' ${system-data["wifi"]["ssid"]}')
))
(defwidget lan-dev [align device]
(box :orientation "h"
:halign align
:class "module lan-dev network ${system-data['network'][device]['online'] ? 'online' : 'offline'} ${system-data['network'][device]['connecting'] ? 'connecting' : ''}"
:space-evenly false
:spacing 0
(revealer :transition "none"
:reveal {!system-data["network"][device]["online"] && !system-data["network"][device]["connecting"]}
"")
(revealer :transition "none"
:reveal {system-data["network"][device]["online"] || system-data["network"][device]["connecting"]}
"")
(revealer :transition "slideright"
:reveal {!system-data["network"][device]["online"] && !system-data["network"][device]["connecting"]}
:duration "500ms"
" offline")
(revealer :transition "slideright"
:reveal {system-data["network"][device]["connecting"]}
:duration "500ms"
" connecting...")
(revealer :transition "slideright"
:reveal {system-data["network"][device]["online"] && system-data["network"][device]["ip4_addr"] != ""}
:duration "500ms"
' ${system-data["network"][device]["ip4_addr"]}')
))

View File

@ -1,111 +0,0 @@
#!/usr/bin/env python3
from time import sleep
import json
import psutil
import subprocess
import os
import sys
amdgpuinfo_installed = False
# Try to import GPU info
try:
import pyamdgpuinfo as gpuinfo
amdgpuinfo_installed = True
except:
pass
def cpu():
util = psutil.cpu_percent(percpu=False)
per_core = psutil.cpu_percent(percpu=True)
return {
"avg_display": f"{int(util):2}",
"avg": util,
"cores": [ { "value": core, "display": f"{int(core):2}" } for core in per_core ],
"cores_display": "".join([ f"{int(core):3}" for core in per_core ]),
"core_count": len(per_core)
}
def gpu():
if not amdgpuinfo_installed or gpuinfo.detect_gpus() <= 0:
return {
"available": False,
"load": 0,
"power_state": 0,
"memory": 0
}
gpu = gpuinfo.get_gpu(0)
return {
"available": True,
"load": gpu.query_load(),
"power_state": gpu.query_power(),
"memory": gpu.query_vram_usage() / gpu.memory_info['vram_size']
}
def sensor(chip: str):
return { temp.label: temp.current for temp in psutil.sensors_temperatures().get(chip) }
def memory():
mem = psutil.virtual_memory()
return {
"total": mem.total,
"available": mem.available,
"percent": mem.percent,
"used": mem.used,
"free": mem.free,
"active": mem.active,
"inactive": mem.inactive,
"buffers": mem.buffers,
"cached": mem.cached,
"shared": mem.shared,
"slab": mem.slab
}
def swap():
swap = psutil.swap_memory()
return {
"total": swap.total,
"used": swap.used,
"free": swap.free,
"percent": swap.percent
}
def reboot():
running = os.uname().release
version_proc = subprocess.run(["pacman", "-Q", "linux"], capture_output=True)
installed = version_proc.stdout.strip().decode('utf-8').split(' ')[1]
return running != installed
def get_processes():
return [ process for process in psutil.process_iter() ]
def cpu_top(processes):
# Get the top 5 CPU usage processes
try:
result = [ { 'name': ps.name(), 'cpu': ps.cpu_percent() } for ps in processes ]
result.sort(key=lambda ps : -ps.get('cpu'))
return result[0:5]
except:
print("[ ERR ] missing process", file=sys.stderr)
def mem_top(processes):
try:
result = [ { 'name': ps.name(), 'memory': ps.memory_info().rss } for ps in processes ]
result.sort(key=lambda ps : -ps.get('memory'))
return result[0:5]
except:
print("[ ERR ] missing process", file=sys.stderr)
sensor_list = ['nvme', 'k10temp', 'amdgpu']
while True:
result = {
"cpu": cpu(),
"gpu": gpu(),
"sensors": { chip: sensor(chip) for chip in sensor_list },
"memory": memory(),
"swap": swap(),
"reboot": reboot(),
}
print(json.dumps(result), flush=True)
sleep(1)

View File

@ -1,276 +0,0 @@
(defpoll system--hostname :interval "30s"
`hostnamectl hostname --pretty`)
(deflisten system--data :initial "{}"
`~/.config/eww/modules/system/system.py`)
(defwidget system-battery [battery]
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'green' : EWW_BATTERY[battery].capacity <= 25 ? 'highlight' : 'special'}
:text "${EWW_BATTERY[battery].capacity}%")
(label :text "${EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'external' : 'internal'} power")))
(defwidget system-name []
(label :halign "center"
:valign "center"
:class "module text big nebula"
:text {system--hostname}))
(defwidget system-cpu-avg []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {system--data.cpu.avg > 90 ? 'highlight' : 'special'}
:text "${system--data.cpu.avg_display}%")
(label :text "cpu utilization")))
(defwidget system--cpu-core [core]
(label :class {core.value > 90 ? "highlight" : "special"}
:text "${core.display}%"))
(defwidget system-cpu-percore []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
;; (box :orientation "h"
;; :halign "center"
;; :space-evenly false
;; (for core in {system--data.cpu.cores}
;; (system--cpu-core :core core)))
(label :class "special"
:text {system--data.cpu.cores_display})
(label :text "per-core cpu utilization")
))
(defwidget system-memory []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
(label :class {system--data.memory.percent > 85 ? "highlight" : "special"}
:text "${round(system--data.memory.used / 1024 / 1024 / 1024, 2)} / ${round(system--data.memory.total / 1024 / 1024 / 1024, 2)} GiB")
(label :text "system memory")))
(defwidget system--gauge [value ?threshold]
(overlay :width 80
:height 80
(circular-progress :value 75
:class "gauge-gutter"
:start-at 37.5
:thickness 2)
(circular-progress :value {value * 0.75}
:class 'gauge ${value > (threshold ?: 80) ? "highlight" : ""}'
:start-at 37.5
:thickness 2)))
(defwidget system-gauges []
(box :orientation "h"
:space-evenly false
:width 200
:halign "start"
:spacing 10
(box :orientation "v"
:space-evenly false
:spacing 20
:width 95
:halign "start"
(system--cpu-gauge)
(system--gpu-gauge)
)
(box :orientation "v"
:space-evenly false
:spacing 20
:width 95
:halign "end"
(system--memory-gauge)
(system--vram-gauge))))
(defwidget system--memory-gauge []
(box :orientation "v"
:halign "end"
:width 95
:space-evenly false
:spacing 10
:class "nebula"
(label :text "RAM"
:class "medium special")
(box :halign "center"
(overlay
(system--gauge :value {system--data.memory.percent})
(transform
:translate-y "-2px"
(box :halign "center"
:valign "center"
:orientation "h"
:space-evenly false
(label :text "%"
:class "invisible")
(label :text {round(system--data.memory.percent, 0)}
:class "medium special")
(transform
:translate-y "3px"
(label :text "%"
:class "offline"))))))))
(defwidget system--cpu-gauge []
(box :orientation "v"
:halign "start"
:width 95
:space-evenly false
:spacing 10
:class "nebula"
(label :text "CPU"
:class "medium special")
(box :halign "center"
(overlay
(system--gauge :value {system--data.cpu.avg})
(transform
:translate-y "-2px"
(box :halign "center"
:valign "center"
:orientation "h"
:space-evenly false
(label :text "%"
:class "invisible")
(label :text {system--data.cpu.avg_display}
:class "medium special")
(transform
:translate-y "3px"
(label :text "%"
:class "offline"))))))
;; (box :orientation "v"
;; :halign "end"
;; :valign "start"
;; :width 100
;; :space-evenly false
;; (for ps in {system--data.cpu_top}
;; (centerbox :width 100
;; :orientation "h"
;; (box :halign "start"
;; (label :text {ps.name}
;; :limit-width 7))
;; ""
;; (box :halign "end"
;; (label :text '${round(ps.cpu, 0)}%')))
;; )
))
(defwidget system--gpu-gauge []
(box :orientation "v"
:halign "start"
:width 95
:space-evenly false
:spacing 10
:class "nebula"
(label :text "GPU"
:class "medium special")
(box :halign "center"
(overlay
(system--gauge :value {system--data.gpu.load * 100})
(transform
:translate-y "-2px"
(box :halign "center"
:valign "center"
:orientation "h"
:space-evenly false
(label :text "%"
:class "invisible")
(label :text {round(system--data.gpu.load * 100, 0)}
:class "medium special")
(transform
:translate-y "3px"
(label :text "%"
:class "offline"))))))))
(defwidget system--vram-gauge []
(box :orientation "v"
:halign "start"
:width 95
:space-evenly false
:spacing 10
:class "nebula"
(label :text "VRAM"
:class "medium special")
(box :halign "center"
(overlay
(system--gauge :value {system--data.gpu.memory * 100})
(transform
:translate-y "-2px"
(box :halign "center"
:valign "center"
:orientation "h"
:space-evenly false
(label :text "%"
:class "invisible")
(label :text {round(system--data.gpu.memory * 100, 0)}
:class "medium special")
(transform
:translate-y "3px"
(label :text "%"
:class "offline"))))))))
(defwidget system--gauge-generic [value value-fmt big-text little-text ?subscript ?threshold]
(box :orientation "h"
:halign "start"
:class "module gauge-widget"
:space-evenly true
:spacing 0
(overlay :width 100
(circular-progress :value 100
:class "gauge-hole"
:start-at 0
:thickness 50
)
(circular-progress :value 80
:class "gauge-gutter"
:start-at 35
:thickness 2)
(circular-progress :value {value * 0.8}
:class 'gauge ${value > (threshold ?: 80) ? "highlight" : ""}'
:start-at 35
:thickness 2)
(transform :translate-y "-5px"
:translate-x "3px"
(box :halign "center"
:valign "center"
:class "big nebula"
:space-evenly false
"${value-fmt}"
(box :class "normal offline"
:halign "start"
:valign "end"
(transform :translate-y "-2px"
:translate-x "1px"
{subscript})))))
(transform :translate-y "-5px"
(box :orientation "v"
:halign "center"
:valign "center"
:space-evenly false
(label :text {big-text}
:class "big nebula")
(label :text {little-text}
:class "nebula special")))))
;; (defwidget system-cpu-gauge []
;; (system--gauge-generic :value {system--data.cpu.avg}
;; :value-fmt {system--data.cpu.avg_display}
;; :big-text "CPU"
;; :little-text "usage"
;; :subscript "%"))
;; (defwidget system-memory-gauge []
;; (system--gauge-generic :value {system--data.memory.percent}
;; :value-fmt {round(system--data.memory.percent, 0)}
;; :big-text "RAM"
;; :little-text "${round(system--data.memory.used / 1024 / 1024 / 1024, 1)} GiB"
;; :subscript "%"))

View File

@ -1,44 +0,0 @@
#!/usr/bin/env python3
import datetime
import os
import json
from time import sleep
import sys
def get_time():
try:
with open(f'{os.environ["HOME"]}/.timer', 'rb') as timestamp_file:
return datetime.datetime.fromtimestamp(int.from_bytes(timestamp_file.read(8), 'little'))
except Exception as exc:
return None
while True:
now = datetime.datetime.now()
end = get_time()
if end is None:
print(json.dumps({
'hours': '00',
'minutes': '00',
'seconds': '00',
'future': False,
'timer': False
}), flush=True)
sleep(0.5)
continue
delta = int((now - get_time()).total_seconds())
future = False
if delta < 0:
future = True
delta = -delta
hours = int(delta / 3600)
minutes = int((delta % 3600) / 60)
seconds = delta % 60
print(json.dumps({
'hours': hours,
'minutes': f'{minutes:02}',
'seconds': f'{seconds:02}',
'future': future,
'timer': True
}), flush=True)
sleep(0.5)

View File

@ -1,29 +0,0 @@
(deflisten timer--data :initial '{"timer": false}'
`~/.config/eww/modules/timer/timer.py`)
(defwidget timer--gauge [value green]
(overlay :width 180
:height 180
(circular-progress :value 75
:class "gauge-gutter"
:start-at 37.5
:thickness 2)
(circular-progress :value {value * 0.75}
:class 'gauge ${green ? "green" : ""}'
:start-at 37.5
:thickness 2)))
(defwidget met []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 5
:class "nebula medium"
:visible {timer--data.timer}
"Baldur's Gate 3: "
(label :text 'T${timer--data.future ? "-" : "+"}'
:class {timer--data.future ? "highlight" : "green"})
(label :text '${timer--data.hours}:${timer--data.minutes}:${timer--data.seconds}'
:class "special")))

View File

@ -1,28 +0,0 @@
(deflisten volume--data
`~/.config/eww/modules/volume/volume.py`)
(defwidget volume-h []
(box :orientation "h"
:halign "start"
:class "module ${volume--data['mute'] ? 'offline' : ''}"
:space-evenly false
:spacing 0
(label :visible {!volume--data["mute"]} :text "")
(label :visible { volume--data["mute"]} :text "")
(label :text " ${volume--data['volume']}")))
(defwidget audio []
(box :orientation "v"
:halign "center"
:class "module text"
:space-evenly false
:spacing 0
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 15
(label :class {volume--data.output.mute ? "offline" : "special"}
:text "${volume--data.output.volume}%")
(label :class {volume--data.input.mute ? "offline" : "special"}
:text "${volume--data.input.volume}%"))
"audio system"))

View File

@ -1,184 +0,0 @@
#!/usr/bin/env python3
import asyncio
import json
import os
import sys
from i3ipc.aio import Connection
from i3ipc import Event
from typing import List, Dict, Any, Union, Tuple
WorkspaceTree = Dict[str, Dict[str, List['Workspace']]]
WorkspaceList = Dict[str, 'Workspace']
class Workspace:
index: str = None
name: str = None
exec_cmd: str = None
group: str = None
active: bool = False
visible: bool = False
focused: bool = False
alerted: bool = False
def __init__(self, dictionary: Dict[str, Union[str, int]], group: str):
self.index = str(dictionary.get('index'))
self.name = dictionary.get('name')
self.exec_cmd = dictionary.get('exec')
self.group = group
self.active = dictionary.get('active', False)
self.visible = dictionary.get('visible', False)
self.focused = dictionary.get('focused', False)
self.alerted = dictionary.get('alerted', False)
def update_state(self, state_update: Any):
self.active = True
self.visible = state_update.visible
self.focused = state_update.focused
self.alerted = state_update.urgent
def deactivate(self):
self.active = False
self.visible = False
self.focused = False
self.alerted = False
@classmethod
def parse_file(cls: type, filename: str) -> Tuple[WorkspaceTree, WorkspaceList]:
result = {}
initial: dict = None
with open(filename, 'r') as file:
initial = json.load(file)
workspaces: WorkspaceList = {}
def find_workspace(workspace: Dict[str, Union[str, int]], group: str) -> 'Workspace':
index = str(workspace.get('index'))
if index in workspaces:
return workspaces[index]
else:
workspaces[index] = cls(workspace, group)
return workspaces[index]
result = {
context: {
group: [
find_workspace(workspace, group) for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in initial.items()
}
return result, workspaces
@staticmethod
def full_dictify(tree: WorkspaceTree):
return {
context: {
group: [
workspace.dictify() for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in tree.items()
}
def dictify(self):
return {
'index': self.index,
'name': self.name,
'exec': self.exec_cmd,
'active': self.active,
'visible': self.visible,
'focused': self.focused,
'alerted': self.alerted
}
workspace_tree, workspace_list = Workspace.parse_file(f"{os.environ['HOME']}/.config/sway/workspaces.json")
data = {
"ws": {},
"mode": "default",
"current": {},
"context": "personal",
"visible": {},
}
def write_data():
global data
print(json.dumps(data), flush=True)
async def workspace_event(self: Connection, _):
global workspace_tree, workspace_list, data
ws_sway_dict = { ws.name: ws for ws in await self.get_workspaces()}
touched = []
for index, ws_data in ws_sway_dict.items():
# Update data for all active workspaces
ws_state = workspace_list.get(index)
if ws_state is None:
# If the workspace isn't configured, note it and handle gracefully
print(f"Warning: found unconfigured workspace {index}", file=sys.stderr, flush=True)
if ws_data.focused:
data['current'] = {
'index': index,
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': True,
'alerted': False
}
else:
# Otherwise, 'touch' it and update the status data
touched.append(index)
ws_state.update_state(ws_data)
if ws_state.focused:
data['current'] = ws_state.dictify()
if ws_state.visible:
data['visible'][ws_state.group] = ws_state.dictify()
# 'Deactivate' any untouched workspaces
inactives = [
v for k, v in workspace_list.items() if v.active and k not in touched
]
for workspace in inactives:
workspace.deactivate()
# Create an 'unknown' workspace object for each group that doesn't yet have a listed visible workspace
for group in workspace_tree[data['context'] or 'personal'].keys():
if group not in data['visible']:
data['visible'][group] = {
'index': 'U',
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': False,
'alerted': False
}
data['ws'] = Workspace.full_dictify(workspace_tree)
write_data()
async def mode_event(self: Connection, event):
global data
data['mode'] = event.change
write_data()
async def main():
sway = await Connection(auto_reconnect = True).connect()
sway.on(Event.WORKSPACE, workspace_event)
sway.on(Event.MODE, mode_event)
await workspace_event(sway, None)
await sway.main()
asyncio.run(main())

View File

@ -1,75 +0,0 @@
(deflisten sway--data :initial '{mode: "default"}'
`~/.config/eww/modules/workspaces/sway.py`)
(defvar hypr--data '{}')
(defwidget sway--workspace [ws]
(button :onclick "swaymsg workspace ${ws['index']}"
(circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused" : ""} ${ws.alerted ? "sway--alerted" : ""}'
:value 100
:start-at 0
:clockwise true
:width 16
:thickness 1
(box :class 'fill' :visible {ws.visible}))))
(defwidget hypr--workspace [ws]
(button :onclick "hyprmsg dispatch workspace ${ws['index']}"
(circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused": ""}'
:value 100
:start-at 0
:clockwise true
:width 15
:thickness 1
(box :class 'fill' :visible {ws.focused}))))
(defwidget sway-mode []
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class "module text"
:visible {hypr--data.mode != "default"}
(label :class "special"
:text "${hypr--data.mode}")
"sway mode"))
(defwidget sway-workspace [group]
(box :orientation "v"
:halign "center"
:valign "center"
:space-evenly false
:spacing 0
:class 'module text nebula medium'
(label :class '${sway--data.visible[group].focused ? "special" : "offline"}'
:text '${sway--data.visible[group].name}')))
(defwidget hypr-workspace [group]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class 'module text'
(label :class '${hypr--data.visible[group].focused ? "special" : "offline"}'
:text '${hypr--data.visible[group].name}')
(label :text "current workspace")))
(defwidget sway-workspaces [group]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]}
(sway--workspace :ws workspace))))
(defwidget hypr-workspaces [group]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {hypr--data.ws[hypr--data.context ?: "personal"][group]}
(hypr--workspace :ws workspace))))

View File

@ -1 +0,0 @@
eww-modules

View File

@ -1,13 +0,0 @@
$wallpaper: #1e1e1e;
$foreground: #9a7c9d;
$bg0: #2d272f;
$bg1: #3f3242;
$red: #cf6a4c;
$green: #8f9d6a;
$yellow: #f9ee98;
$blue: #7587a6;
$magenta: #9b859d;
$cyan: #afc4db;
$white: #a7a7a7;

View File

@ -1,90 +0,0 @@
@import 'colors';
* {
all: unset;
}
.reservepower.reservepower {
color: $red;
}
.root {
color: $foreground;
font-family: "Source Code Pro";
font-size: 9pt;
background-color: rgba(0,0,0,0);
// Probably needs to change
&.bar {
margin: 10px;
margin-bottom: 0px;
}
&.side {
margin: 10px;
margin-right: 0px;
}
}
.icon {
font-family: "Font Awesome 5 Free Solid";
}
.highlight {
color: $red;
}
.offline {
color: $bg1;
}
.special {
color: $blue;
}
.green {
color: $green;
}
.big {
font-size: 1.8rem;
font-family: "Nebula";
}
// sway module
.sway--ws {
.fill {
background-color: $foreground;
}
color: $bg1;
&.sway--active {
color: $foreground;
}
&.sway--visible {
color: $blue;
}
&.sway--focused {
}
}
.reservepower .sway--ws.sway--active {
color: $red;
}
.reservepower .sway--ws .fill {
background-color: $red;
}
// clock module
.clock--time {
font-size: 20pt;
}
.clock--date {
font-size: 9pt;
}

View File

@ -1,183 +0,0 @@
;; Include modules
(include "./modules/workspaces/workspaces.yuck")
(include "./modules/clock/clock.yuck")
(include "./modules/system/system.yuck")
(include "./modules/network/network.yuck")
(include "./modules/volume/volume.yuck")
(defvar power-state "normal")
;; Windows
(defwidget leftbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 10
:class "leftbox"
(vpn-network)
(network)))
(defwidget leftbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(system-name)))
(defwidget leftbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 10
:class "rightbox"
(sway-workspace :group "left")
(sway-workspaces :group "left")))
(defwidget rightbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "right")
(sway-workspace :group "right")))
(defwidget rightbar--hypr-left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(hypr-workspaces :group "main")
(hypr-workspace :group "main")))
(defwidget rightbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(system-name)))
(defwidget rightbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "leftbox"
(system-battery :battery "BAT1")
(audio)
(clock)))
(defwidget builtinbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "builtin")
(sway-workspace :group "builtin")))
(defwidget builtinbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(system-name)))
(defwidget builtinbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(vpn-network)
(network)
(system-battery :battery "BAT1")
(audio)
(clock)))
(defwindow builtinbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root ${power-state == "critical" ? 'reservepower' : ''}"
(builtinbar--left)
(builtinbar--center)
(builtinbar--right)))
(defwindow side
:monitor 0
:geometry (geometry :width "36px"
:height "100%"
:anchor "center left")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "v" :class "bar root" :width 36
(sway-workspaces-v :group "main")
""
""))
(defwidget sidebar []
(box :orientation "v"
:valign "start"
:space-evenly false
:spacing 0
:class "bar root"
(clock)))
(defwindow leftbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root"
(leftbar--left)
(leftbar--center)
(leftbar--right)))
(defwindow rightbar
:monitor 1
:geometry (geometry :width "100%"
:height "55px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root"
(rightbar--left)
(rightbar--center)
(rightbar--right)))
(defwindow hypr-mainbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "overlay"
(centerbox :orientation "h" :class "bar root"
(rightbar--hypr-left)
(rightbar--center)
(rightbar--right)))
(defwindow sidebar
:monitor 1
:geometry (geometry :width "210px"
:height "1044px"
:anchor "left bottom")
:exclusive true
:focusable false
:stacking "fg"
(sidebar))

View File

@ -1,11 +0,0 @@
(defwidget left-angle []
(image :path "/home/ezri/.config/eww.new/modules/angles/left.png"
:width 150
:height 36))
(defwidget right-angle []
(image :path "/home/ezri/.config/eww.new/modules/angles/right.png"
:width 150
:height 36))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,10 +0,0 @@
(defpoll clock--data :interval "500ms"
`date +'{"hour": "%H", "minute": "%M", "second": "%S", "year": "%Y", "day": "%d", "month": "%m", "dow": "%A", "month_name": "%B"}'`)
(defwidget clock []
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text "${clock--data['hour']}:${clock--data['minute']}")
(label :text "${clock--data['year']}-${clock--data['month']}-${clock--data['day']}")))

View File

@ -1,56 +0,0 @@
#!/usr/bin/env python3
from time import sleep
import json
import psutil
import subprocess
import os
def cpu():
util = psutil.cpu_percent(percpu=False)
per_core = psutil.cpu_percent(percpu=True)
return {
"avg_display": f"{int(util):2}",
"avg": util,
"cores": per_core,
"core_count": len(per_core)
}
def sensor(chip: str):
return { temp.label: temp.current for temp in psutil.sensors_temperatures()[chip] }
def memory():
mem = psutil.virtual_memory()
return {
'used': mem.used,
'available': mem.available,
'total': mem.total,
'percent': mem.percent
}
def swap():
mem = psutil.swap_memory()
return {
'used': mem.used,
'total': mem.total,
'percent': mem.percent
}
def reboot():
running = os.uname().release
file_proc = subprocess.run("file /boot/vmlinuz-linux | cut -d',' -f2 | cut -d' ' -f3", shell=True, capture_output=True)
installed = file_proc.stdout.strip().decode('utf-8')
return running != installed
sensor_list = ['coretemp']
while True:
result = {
"cpu": cpu(),
"sensors": { chip: sensor(chip) for chip in sensor_list },
"memory": memory(),
"swap": swap(),
"reboot": reboot()
}
print(json.dumps(result), flush=True)
sleep(1)

View File

@ -1,20 +0,0 @@
(defpoll system--hostname :interval "30s"
`bash -c 'eval $(cat /etc/machine-info); echo $PRETTY_HOSTNAME'`)
(defvar system--battery-text "")
(defwidget system-battery [battery]
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'green' : EWW_BATTERY[battery].capacity <= 30 ? 'highlight' : 'special'}
:text "${EWW_BATTERY[battery].capacity}%")
(label :text "${EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].capacity == 100 ? 'external' : EWW_BATTERY[battery].capacity <= 15 ? 'emergency' : EWW_BATTERY[battery].capacity <= 30 ? 'reserve' : 'internal'} power")))
(defwidget system-name []
(label :halign "center"
:valign "center"
:class "module text big"
:text {system--hostname}))

View File

@ -1,50 +0,0 @@
#!/usr/bin/env python3
import asyncio
import signal
from contextlib import suppress
import pulsectl_asyncio
import json
import sys
import os
async def get_values(pulse):
sink = None
try:
sink = await pulse.get_sink_by_name("@DEFAULT_SINK@")
source = await pulse.get_source_by_name("@DEFAULT_SOURCE@")
except:
# reload the script in the event of an exception
os.execv(sys.argv[0], sys.argv)
sink_result = {
"mute": sink.mute == 1,
"volume": f"{int(sink.volume.value_flat * 100):2}"
}
source_result = {
"mute": source.mute == 1,
"volume": f"{int(source.volume.value_flat * 100):2}"
}
result = {
"output": sink_result,
"input": source_result
}
print(json.dumps(result), flush=True)
return result
async def listen():
async with pulsectl_asyncio.PulseAsync("volume-monitor") as pulse:
await get_values(pulse)
async for _ in pulse.subscribe_events('all'):
await get_values(pulse)
async def main():
listen_task = asyncio.create_task(listen())
for sig in (signal.SIGTERM, signal.SIGHUP, signal.SIGINT):
loop.add_signal_handler(sig, listen_task.cancel)
with suppress(asyncio.CancelledError):
await listen_task
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

View File

@ -1,28 +0,0 @@
(deflisten volume--data
`~/.config/eww/modules/volume/volume.py`)
(defwidget volume-h []
(box :orientation "h"
:halign "start"
:class "module ${volume--data['mute'] ? 'offline' : ''}"
:space-evenly false
:spacing 0
(label :visible {!volume--data["mute"]} :text "")
(label :visible { volume--data["mute"]} :text "")
(label :text " ${volume--data['volume']}")))
(defwidget audio []
(box :orientation "v"
:halign "center"
:class "module text"
:space-evenly false
:spacing 0
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 15
(label :class {volume--data.output.mute ? "offline" : "special"}
:text "${volume--data.output.volume}%")
(label :class {volume--data.input.mute ? "offline" : "special"}
:text "${volume--data.input.volume}%"))
"audio system"))

View File

@ -1,213 +0,0 @@
#!/usr/bin/env python3
import asyncio
import json
import os
import sys
WorkspaceTree = dict[str, dict[str, list['Workspace']]]
WorkspaceList = dict[str, 'Workspace']
socketdir = f"/tmp/hypr/{os.environ['HYPRLAND_INSTANCE_SIGNATURE']}"
socket1 = f"{socketdir}/.socket.sock"
socket2 = f"{socketdir}/.socket2.sock"
listened_events = ['workspace', 'movewindow', 'createworkspace', 'destroyworkspace']
class Workspace:
index: str = None
name: str = None
exec_cmd: str = None
group: str = None
active: bool = False
visible: bool = False
focused: bool = False
alerted: bool = False
def __init__(self, dictionary: dict[str, str | int], group: str):
self.index = str(dictionary.get('index'))
self.name = dictionary.get('name')
self.exec_cmd = dictionary.get('exec')
self.group = group
self.active = dictionary.get('active', False)
self.visible = dictionary.get('visible', False)
self.focused = dictionary.get('focused', False)
self.alerted = dictionary.get('alerted', False)
def update_state(self, state_update, monitor_dict):
self.active = True
self.visible = monitor_dict[state_update['monitor']]['activeWorkspace']['name'] == state_update['name']
self.focused = self.visible and monitor_dict[state_update['monitor']]['focused']
self.alerted = False
def deactivate(self):
self.active = False
self.visible = False
self.focused = False
self.alerted = False
@classmethod
def parse_file(cls: type, filename: str) -> tuple[WorkspaceTree, WorkspaceList]:
result = {}
initial: dict = None
with open(filename, 'r') as file:
initial = json.load(file)
workspaces: WorkspaceList = {}
def find_workspace(workspace: dict[str, str|int], group: str) -> 'Workspace':
index = str(workspace.get('index'))
if index in workspaces:
return workspaces[index]
else:
workspaces[index] = cls(workspace, group)
return workspaces[index]
result = {
context: {
group: [
find_workspace(workspace, group) for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in initial.items()
}
return result, workspaces
@staticmethod
def full_dictify(tree: WorkspaceTree):
return {
context: {
group: [
workspace.dictify() for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in tree.items()
}
def dictify(self):
return {
'index': self.index,
'name': self.name,
'exec': self.exec_cmd,
'active': self.active,
'visible': self.visible,
'focused': self.focused,
'alerted': self.alerted
}
workspace_tree, workspace_list = Workspace.parse_file(f"{os.environ['HOME']}/.config/hypr/workspaces.json")
data = {
"ws": {},
"current": {},
"context": "personal",
"visible": {},
}
def write_data():
global data
print(json.dumps(data), flush=True)
async def get_workspace_data():
request = b"[[BATCH]] j/workspaces; j/monitors"
reader = None
writer = None
data = None
try:
reader, writer = await asyncio.open_unix_connection(socket1)
writer.write(request)
await writer.drain()
data = await reader.read()
finally:
if writer is not None:
writer.close()
if data is None:
return;
workspace_data = None
monitor_data = None
try:
workspace_data, monitor_data = data.decode().split("}][{")
workspace_data += "}]"
monitor_data = "[{" + monitor_data
except ValueError:
print("Error unpacking response", file=sys.stderr)
return
return [json.loads(workspace_data), json.loads(monitor_data)]
async def update_workspaces():
global workspace_tree, workspace_list, data
workspaces, monitors = await get_workspace_data()
ws_hypr_dict = { ws["name"]: ws for ws in workspaces }
monitor_dict = { monitor["name"]: monitor for monitor in monitors }
touched = []
for index, ws_data in ws_hypr_dict.items():
# Update data for all active workspaces
ws_state = workspace_list.get(index)
if ws_state is None:
# If the workspace isn't configured, note it and handle gracefully
print(f"Warning: found unconfigured workspace {index}", file=sys.stderr, flush=True)
if monitor_dict[ws_data['monitor']]['activeWorkspace']['name'] == ws_data['name']:
data['current'] = {
'index': index,
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': True,
'alerted': False
}
else:
# Otherwise, 'touch' it and update status data
touched.append(index)
ws_state.update_state(ws_data, monitor_dict)
if ws_state.focused:
data['current'] = ws_state.dictify()
if ws_state.visible:
data['visible'][ws_state.group] = ws_state.dictify()
inactives = [
v for k, v in workspace_list.items() if v.active and k not in touched
]
for workspace in inactives:
workspace.deactivate()
# Create an 'unknown' workspace object for each group that doesn't yet have a listed visible workspace
for group in workspace_tree[data['context'] or 'personal'].keys():
if group not in data['visible']:
data['visible'][group] = {
'index': 'U',
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': False,
'alerted': False
}
data['ws'] = Workspace.full_dictify(workspace_tree)
write_data()
async def main():
reader, writer = await asyncio.open_unix_connection(socket2)
await update_workspaces()
while True:
event = (await reader.readline()).decode()
eventType, eventData = event.split(">>")
if eventType in listened_events:
await update_workspaces()
asyncio.run(main())

View File

@ -1,184 +0,0 @@
#!/usr/bin/env python3
import asyncio
import json
import os
import sys
from i3ipc.aio import Connection
from i3ipc import Event
from typing import List, Dict, Any, Union, Tuple
WorkspaceTree = Dict[str, Dict[str, List['Workspace']]]
WorkspaceList = Dict[str, 'Workspace']
class Workspace:
index: str = None
name: str = None
exec_cmd: str = None
group: str = None
active: bool = False
visible: bool = False
focused: bool = False
alerted: bool = False
def __init__(self, dictionary: Dict[str, Union[str, int]], group: str):
self.index = str(dictionary.get('index'))
self.name = dictionary.get('name')
self.exec_cmd = dictionary.get('exec')
self.group = group
self.active = dictionary.get('active', False)
self.visible = dictionary.get('visible', False)
self.focused = dictionary.get('focused', False)
self.alerted = dictionary.get('alerted', False)
def update_state(self, state_update: Any):
self.active = True
self.visible = state_update.visible
self.focused = state_update.focused
self.alerted = state_update.urgent
def deactivate(self):
self.active = False
self.visible = False
self.focused = False
self.alerted = False
@classmethod
def parse_file(cls: type, filename: str) -> Tuple[WorkspaceTree, WorkspaceList]:
result = {}
initial: dict = None
with open(filename, 'r') as file:
initial = json.load(file)
workspaces: WorkspaceList = {}
def find_workspace(workspace: Dict[str, Union[str, int]], group: str) -> 'Workspace':
index = str(workspace.get('index'))
if index in workspaces:
return workspaces[index]
else:
workspaces[index] = cls(workspace, group)
return workspaces[index]
result = {
context: {
group: [
find_workspace(workspace, group) for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in initial.items()
}
return result, workspaces
@staticmethod
def full_dictify(tree: WorkspaceTree):
return {
context: {
group: [
workspace.dictify() for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in tree.items()
}
def dictify(self):
return {
'index': self.index,
'name': self.name,
'exec': self.exec_cmd,
'active': self.active,
'visible': self.visible,
'focused': self.focused,
'alerted': self.alerted
}
workspace_tree, workspace_list = Workspace.parse_file(f"{os.environ['HOME']}/.config/sway/workspaces.json")
data = {
"ws": {},
"mode": "default",
"current": {},
"context": "personal",
"visible": {},
}
def write_data():
global data
print(json.dumps(data), flush=True)
async def workspace_event(self: Connection, _):
global workspace_tree, workspace_list, data
ws_sway_dict = { ws.name: ws for ws in await self.get_workspaces()}
touched = []
for index, ws_data in ws_sway_dict.items():
# Update data for all active workspaces
ws_state = workspace_list.get(index)
if ws_state is None:
# If the workspace isn't configured, note it and handle gracefully
print(f"Warning: found unconfigured workspace {index}", file=sys.stderr, flush=True)
if ws_data.focused:
data['current'] = {
'index': index,
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': True,
'alerted': False
}
else:
# Otherwise, 'touch' it and update the status data
touched.append(index)
ws_state.update_state(ws_data)
if ws_state.focused:
data['current'] = ws_state.dictify()
if ws_state.visible:
data['visible'][ws_state.group] = ws_state.dictify()
# 'Deactivate' any untouched workspaces
inactives = [
v for k, v in workspace_list.items() if v.active and k not in touched
]
for workspace in inactives:
workspace.deactivate()
# Create an 'unknown' workspace object for each group that doesn't yet have a listed visible workspace
for group in workspace_tree[data['context'] or 'personal'].keys():
if group not in data['visible']:
data['visible'][group] = {
'index': 'U',
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': False,
'alerted': False
}
data['ws'] = Workspace.full_dictify(workspace_tree)
write_data()
async def mode_event(self: Connection, event):
global data
data['mode'] = event.change
write_data()
async def main():
sway = await Connection(auto_reconnect = True).connect()
sway.on(Event.WORKSPACE, workspace_event)
sway.on(Event.MODE, mode_event)
await workspace_event(sway, None)
await sway.main()
asyncio.run(main())

View File

@ -1,89 +0,0 @@
(deflisten sway--data :initial '{mode: "default"}'
`~/.config/eww/modules/workspaces/sway.py`)
(deflisten hypr--data :initial '{}'
`~/.config/eww/modules/workspaces/hyprland.py`)
(defwidget sway--workspace [ws]
(button :onclick "swaymsg workspace ${ws['index']}"
(overlay :width 20
:height 20
(circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused" : ""} ${ws.alerted ? "sway--alerted" : ""}'
:value 100
:start-at 0
:clockwise true
:width 20
:thickness 1
(box :class 'fill' :visible {ws.focused}))
)))
(defwidget hypr--workspace [ws]
(button :onclick "hyprmsg dispatch workspace ${ws['index']}"
(circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused": ""}'
:value 100
:start-at 0
:clockwise true
:width 20
:thickness 1
(box :class 'fill' :visible {ws.focused}))))
(defwidget sway-mode []
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class "module text"
:visible {sway--data.mode != "default"}
(label :class "special"
:text "${hypr--data.mode}")
"sway mode"))
(defwidget sway-workspace [group]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class 'module text'
(label :class '${sway--data.visible[group].focused ? "special" : "offline"}'
:text '${sway--data.visible[group].name}')
(label :text "current workspace")))
(defwidget hypr-workspace [group]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class 'module text'
(label :class '${hypr--data.visible[group].focused ? "special" : "offline"}'
:text '${hypr--data.visible[group].name}')
(label :text "current workspace")))
(defwidget sway-workspaces [group]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]}
(sway--workspace :ws workspace))))
(defwidget sway-workspaces-v [group]
(box :orientation "v"
:halign "center"
:valign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]}
(sway--workspace :ws workspace))))
(defwidget hypr-workspaces [group]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {hypr--data.ws[hypr--data.context ?: "personal"][group]}
(hypr--workspace :ws workspace))))

View File

@ -1,89 +0,0 @@
(deflisten sway--data :initial '{mode: "default"}'
`~/.config/eww/modules/sway.py`)
(deflisten hypr--data :initial '{}'
`~/.config/eww/modules/workspaces/hyprland.py`)
(defwidget sway--workspace [ws]
(button :onclick "swaymsg workspace ${ws['index']}"
(overlay :width 20
:height 20
(circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused" : ""} ${ws.alerted ? "sway--alerted" : ""}'
:value 100
:start-at 0
:clockwise true
:width 20
:thickness 1
(box :class 'fill' :visible {ws.focused}))
)))
(defwidget hypr--workspace [ws]
(button :onclick "hyprmsg dispatch workspace ${ws['index']}"
(circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused": ""}'
:value 100
:start-at 0
:clockwise true
:width 20
:thickness 1
(box :class 'fill' :visible {ws.focused}))))
(defwidget sway-mode []
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class "module text"
:visible {sway--data.mode != "default"}
(label :class "special"
:text "${hypr--data.mode}")
"sway mode"))
(defwidget sway-workspace [group]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class 'module text'
(label :class '${sway--data.visible[group].focused ? "special" : "offline"}'
:text '${sway--data.visible[group].name}')
(label :text "current workspace")))
(defwidget hypr-workspace [group]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
:class 'module text'
(label :class '${hypr--data.visible[group].focused ? "special" : "offline"}'
:text '${hypr--data.visible[group].name}')
(label :text "current workspace")))
(defwidget sway-workspaces [group]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]}
(sway--workspace :ws workspace))))
(defwidget sway-workspaces-v [group]
(box :orientation "v"
:halign "center"
:valign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]}
(sway--workspace :ws workspace))))
(defwidget hypr-workspaces [group]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 5
:class "sway--root"
(for workspace in {hypr--data.ws[hypr--data.context ?: "personal"][group]}
(hypr--workspace :ws workspace))))

View File

@ -1 +0,0 @@
eww-modules

View File

@ -1,13 +0,0 @@
$wallpaper: #1e1e1e;
$foreground: #9a7c9d;
$bg0: #2d272f;
$bg1: #3f3242;
$red: #cf6a4c;
$green: #8f9d6a;
$yellow: #f9ee98;
$blue: #7587a6;
$magenta: #9b859d;
$cyan: #afc4db;
$white: #a7a7a7;

View File

@ -1,170 +0,0 @@
;; Include modules
(include "./modules/workspaces/workspaces.yuck")
(include "./modules/clock/clock.yuck")
(include "./modules/system/system.yuck")
(include "./modules/network/network.yuck")
(include "./modules/volume/volume.yuck")
(include "./modules/aggietime/aggietime.yuck")
(include "./modules/weather/weather.yuck")
(include "./modules/timer/timer.yuck")
(include "./modules/mpris/mpris.yuck")
;; Windows
(defwidget leftbar--left
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(clock)
(network)
(vpn-network)
(aggietime-shift)))
(defwidget leftbar--center
[]
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(system-name)))
(defwidget leftbar--right
[]
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(sway-workspace :group "left")
(sway-workspaces :group "left")))
(defwidget rightbar--left
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "right")
(sway-workspace :group "right")))
(defwidget rightbar--hypr-left
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(hypr-workspaces :group "main")
(hypr-workspace :group "main")))
(defwidget rightbar--center
[]
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
(system-name)))
(defwidget rightbar--right
[]
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "leftbox"
(mpris)
(system-memory)
(system-cpu-avg)
(clock)))
(defwidget sidebar
[]
(box :orientation "v"
:valign "start"
:space-evenly false
:spacing 0
:class "bar root"
(clock)))
(defwindow leftbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center"):exclusive
true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(leftbar--left)
(leftbar--center)
(leftbar--right)))
(defwindow rightbar
:monitor 1
:geometry (geometry :width "100%"
:height "26px"
:anchor "top center"):exclusive
true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(rightbar--left)
(rightbar--center)
(rightbar--right)))
(defwindow network-status
:monitor 0
:geometry (geometry :width "200px"
:height "0px"
:x "80px"
:y "0px"
:anchor "top left")
:exclusive false
:focusable false
:stacking "overlay"
(box :orientation "v"
:class "bar root bg"
:visible {network--show-details}
(network-detail)))
(defwindow lock-overlay-1
:monitor 1
:geometry (geometry :width "50%"
:height "50%"
:anchor "center"):exclusive
false
:focusable false
:stacking "overlay"
"testing")
(defwindow hypr-mainbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center"):exclusive
true
:focusable false
:stacking "overlay"
(centerbox :orientation "h"
:class "bar root"
(rightbar--hypr-left)
(rightbar--center)
(rightbar--right)))
(defwindow sidebar
:monitor 0
:geometry (geometry :width "210px"
:height "1044px"
:anchor "left bottom"):exclusive
true
:focusable false
:stacking "fg"
(sidebar))

View File

@ -1,128 +0,0 @@
;; Include modules
(include "./modules/workspaces/workspaces.yuck")
(include "./modules/clock/clock.yuck")
(include "./modules/system/system.yuck")
(include "./modules/network/network.yuck")
(include "./modules/volume/volume.yuck")
;; Windows
(defwidget leftbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(clock)
(network)
(vpn-network)))
(defwidget leftbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
))
(defwidget leftbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(sway-workspace :group "left")
(sway-workspaces :group "left")))
(defwidget rightbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "right")
(sway-workspace :group "right")))
(defwidget rightbar--hypr-left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(hypr-workspaces :group "main")
(hypr-workspace :group "main")))
(defwidget rightbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 0
:class "centerbox"
))
(defwidget rightbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "leftbox"
(system-memory)
(system-cpu-avg)
(clock)))
(defwidget sidebar []
(box :orientation "v"
:valign "start"
:space-evenly false
:spacing 0
:class "bar root"
(clock)))
(defwindow leftbar
:monitor 1
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root"
(leftbar--left)
(leftbar--center)
(leftbar--right)))
(defwindow rightbar
:monitor 0
:geometry (geometry :width "100%"
:height "26px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root"
(rightbar--left)
(rightbar--center)
(rightbar--right)))
(defwindow hypr-mainbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "overlay"
(centerbox :orientation "h" :class "bar root"
(rightbar--hypr-left)
(rightbar--center)
(rightbar--right)))
(defwindow sidebar
:monitor 1
:geometry (geometry :width "210px"
:height "1044px"
:anchor "left bottom")
:exclusive true
:focusable false
:stacking "fg"
(sidebar))

View File

@ -1,18 +0,0 @@
(defpoll aggietime--data :interval "10s"
`~/.config/eww/modules/aggietime/aggietime.sh`)
(defwidget aggietime-shift []
(box :class "module text"
:spacing 0
:orientation "v"
:visible {aggietime--data != ''}
(label :class "highlight"
:text "AggieTimeD Not Running"
:visible {aggietime--data.err})
(label :class "special"
:visible {aggietime--data.active && !aggietime--data.err}
:text "${aggietime--data.hours}:${aggietime--data.minutes}")
(label :class "highlight"
:text "not clocked in"
:visible {!aggietime--data.active && !aggietime--data.err})
"current shift"))

View File

@ -1,11 +0,0 @@
(defwidget left-angle []
(image :path "/home/ezri/.config/eww.new/modules/angles/left.png"
:width 150
:height 36))
(defwidget right-angle []
(image :path "/home/ezri/.config/eww.new/modules/angles/right.png"
:width 150
:height 36))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,28 +0,0 @@
(deflisten mpris--data :initial "{}"
`~/.config/eww/modules/mpris/mpris.py`)
(defwidget mpris
[]
(box :class "module text"
:spacing 0
:orientation "v"
(label :class {mpris--data.playing ? "special" : "offline"}
:visible {mpris--data.running}
:text "${mpris--data.title} by ${mpris--data.artist}")
(label :class "offline"
:visible {!mpris--data.running}
:text "player offline")
(label :visible {mpris--data.running}
:text "now playing from ${mpris--data.album}")
(label :visible {!mpris--data.running}
:text "player offline")))
(defwidget mpris-miniplayer []
(box :class "miniplayer"
:orientation "v"
:spacing 10
(image :path {mpris--data.album_art}
:image-width 100
:image-height 100)
(label)))

View File

@ -1,86 +0,0 @@
#!/usr/bin/env python3
import subprocess
import json
import sys
from time import sleep
TRUSTED_NETWORKS = ["honnouji", "honnouji_2.4"]
def wifi():
try:
ssid_cmd = subprocess.run(["iwgetid", "-r"], capture_output=True)
if ssid_cmd.returncode != 0:
return {"connected": False, "ssid": None}
return {"connected": True, "ssid": ssid_cmd.stdout.decode("utf-8").strip()}
except:
return {"connected": False, "ssid": None}
def netdev(device: str):
ip_cmd = subprocess.run(["ip", "-j", "addr", "show", device], capture_output=True)
if ip_cmd.returncode != 0:
sys.stderr.write(ip_cmd.stdout.decode("utf-8"))
return {
"exists": False,
"online": False,
"connecting": False,
"offline": True,
"ip4_addr": None,
"ip4_prefix": None,
}
ip_data = json.loads(ip_cmd.stdout.decode("utf-8"))[0]
online = ip_data["operstate"] == "UP"
ip4_addr = ""
ip4_prefix_length = 24
addr4_info = list(
filter(lambda addr: addr.get("family") == "inet", ip_data["addr_info"])
)
if len(addr4_info) >= 1:
ip4_addr = addr4_info[0]["local"]
ip4_prefix_length = addr4_info[0]["prefixlen"]
connecting = ip_data["operstate"] != "DOWN" and (ip4_addr == "" or not online)
return {
"exists": True,
"online": online,
"connecting": connecting,
"offline": not online and not connecting,
"ip4_addr": ip4_addr,
"ip4_prefix": ip4_prefix_length,
}
def trusted(ssid: str | None):
# Don't throw up an "INSECURE" alert when offline
if not ssid:
return True
return ssid in TRUSTED_NETWORKS
while True:
lan = netdev("lan")
wlan = netdev("wlan0")
vpn = netdev("ezrinet")
mullvad = netdev("wg-mullvad")
wifi_data = wifi()
# VPNs are routed over physical interfaces, so don't check them for online status
online = lan["online"] or wlan["online"]
configuring = (lan["connecting"] and not wlan["online"]) or (
wlan["connecting"] and not lan["online"]
)
result = {
"online": online,
"configuring": configuring,
"offline": not online and not configuring,
"network": {
"lan": lan,
"wlan": wlan,
"vpn": vpn,
"mullvad": mullvad,
},
"wifi": wifi_data,
"trusted": True,
}
print(json.dumps(result), flush=True)
sleep(1)

View File

@ -1,249 +0,0 @@
(deflisten network--data
`~/.config/eww/modules/network/new_network.py`)
(defvar network--show-details false)
(defwidget network-big
[]
(box :orientation "h"
:halign "start"
:valign "center"
:space-evenly false
:spacing 10
(label :class "big nebula"
:text "comms:")
(network--interface :device "lan")
(network--interface :device "ezrinet")
(network--secure)
(network--vpn)))
(defwidget network--interface
[device]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {!device.online}
:text "offline")
(label :visible {device.online}
:class "special"
:text "${device.addresses[0].address}/${device.addresses[0].prefixlen}")))
(defwidget network-big--online
[]
(box :orientation "h"
:halign "start"
:valign "center"
:space-evenly false
:spacing 10
(label :class "medium green nebula"
:visible {network--data.online}
:text "online")
(label :class "medium offline nebula"
:visible {network--data.offline}
:text "offline")
(label :class "medium highlight nebula"
:visible {network--data.configuring}
:text "configuring")))
(defwidget network-big--lan
[device]
(label :visible {network--data
[device]
.online}
:class ""
:text "${network--data.interfaces[device].addresses[0].address}/${network--data.interfaces[device].addresses[0].prefixlen}"))
(defwidget network--wlan
[device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {network--data
["network"]
[device]
["offline"]
}
:text "offline")
(label :visible {network--data
["network"]
[device]
["connecting"]
}
:class "highlight"
:text "connecting...")
(label :visible {network--data
["network"]
[device]
["online"]
}
:class "special"
:text "${network--data['wifi']['ssid']}")))
(defwidget network--lan
[device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {!device.online}
:text "offline")
(label :visible {device.online}
:class {network--data.last_update.unix < clock--data.unix - 30 ? "highlight" : "special"}
:text "${device.addresses[0].address}/${device.addresses[0].prefixlen}")))
(defwidget network--secure
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "highlight"
:text "- insecure"
:visible {!
network--data.secure })
(label :class "green"
:text "- secured via ${network--data.secure_msg}"
:visible {network--data.secure})))
(defwidget vpn-network
[]
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data
!=
''}
(label :class "highlight"
:text "offline"
:visible {!
network--data.interfaces.ezrinet.online })
(label :class "green"
:text "connected"
:visible {network--data.interfaces.ezrinet.online})
"personal network"))
(defwidget network
[]
(button :onclick "eww update network--show-details=${!network--show-details}"
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data != ''}
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 10
(network--lan :device {network--data.default_interface}))
"communications")))
(defwidget network--public-ip
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"public ip:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "highlight"
:text "no response"
:visible {network--data.online && !network--data.have_public_ip})
(label :class "special"
:text {network--data.public_ip.ip}
:visible {network--data.online && network--data.have_public_ip}))))
(defwidget network--default-route
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"route on:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "highlight"
:text "no route"
:visible {network--data.online && !network--data.have_default_route})
(label :class "special"
:text {network--data.default_route}
:visible {network--data.online && network--data.have_default_route}))))
(defwidget network--gateway
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"gateway:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "no response"
:visible {!network--data.have_gateway})
(label :class "special"
:text {network--data.gateway}
:visible {network--data.have_gateway}))))
(defwidget network--status-summary
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"status:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "special"
:text "online"
:visible {network--data.online && !network--data.secure})
(label :class "green"
:text {network--data.secure_msg == "usu" ? "vpn online" : "secure"}
:visible {network--data.online && network--data.secure}))))
(defwidget network-detail
[]
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
(network--status-summary)
(network--public-ip)
(network--default-route)
(network--gateway)
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"last update:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class {network--data.last_update.unix < clock--data.unix - 30 ? "highlight" : "special"}
:text "${network--data.last_update.month}-${network--data.last_update.day} ${network--data.last_update.hour}:${network--data.last_update.minute}:${network--data.last_update.second}")))
))

View File

@ -1,59 +0,0 @@
(deflisten system--data :initial "{}"
`~/.config/eww/modules/system/system.py`)
(defwidget system-battery [battery]
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'green' : EWW_BATTERY[battery].capacity <= 25 ? 'highlight' : 'special'}
:text "${EWW_BATTERY[battery].capacity}%")
(label :text "${EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'external' : 'internal'} power")))
(defwidget system-name []
(label :halign "center"
:valign "center"
:class "module text big nebula"
:text {system--data.hostname}))
(defwidget system-cpu-avg []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {system--data.cpu.avg > 90 ? 'highlight' : 'special'}
:text "${system--data.cpu.avg_display}%")
(label :text "cpu utilization")))
(defwidget system--cpu-core [core]
(label :class {core.value > 90 ? "highlight" : "special"}
:text "${core.display}%"))
(defwidget system-cpu-percore []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
;; (box :orientation "h"
;; :halign "center"
;; :space-evenly false
;; (for core in {system--data.cpu.cores}
;; (system--cpu-core :core core)))
(label :class "special"
:text {system--data.cpu.cores_display})
(label :text "per-core cpu utilization")
))
(defwidget system-memory []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
(label :class {system--data.memory.percent > 85 ? "highlight" : "special"}
:text "${round(system--data.memory.used / 1024 / 1024 / 1024, 2)} / ${round(system--data.memory.total / 1024 / 1024 / 1024, 2)} GiB")
(label :text "system memory")))

View File

@ -1,11 +0,0 @@
(deflisten timer--text :initial 'loading...'
`~/.config/eww/modules/timer/timer.py`)
(defwidget timer []
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text {timer--text})
(label :text "baldur's gate 3")))

View File

@ -1,50 +0,0 @@
#!/usr/bin/env python3
import asyncio
import signal
from contextlib import suppress
import pulsectl_asyncio
import json
import sys
import os
async def get_values(pulse):
sink = None
try:
sink = await pulse.get_sink_by_name("@DEFAULT_SINK@")
source = await pulse.get_source_by_name("@DEFAULT_SOURCE@")
except:
# reload the script in the event of an exception
os.execv(sys.argv[0], sys.argv)
sink_result = {
"mute": sink.mute == 1,
"volume": f"{int(sink.volume.value_flat * 100):2}"
}
source_result = {
"mute": source.mute == 1,
"volume": f"{int(source.volume.value_flat * 100):2}"
}
result = {
"output": sink_result,
"input": source_result
}
print(json.dumps(result), flush=True)
return result
async def listen():
async with pulsectl_asyncio.PulseAsync("volume-monitor") as pulse:
await get_values(pulse)
async for _ in pulse.subscribe_events('all'):
await get_values(pulse)
async def main():
listen_task = asyncio.create_task(listen())
for sig in (signal.SIGTERM, signal.SIGHUP, signal.SIGINT):
loop.add_signal_handler(sig, listen_task.cancel)
with suppress(asyncio.CancelledError):
await listen_task
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

View File

@ -1,28 +0,0 @@
(deflisten volume--data
`~/.config/eww/modules/volume/volume.py`)
(defwidget volume-h []
(box :orientation "h"
:halign "start"
:class "module ${volume--data['mute'] ? 'offline' : ''}"
:space-evenly false
:spacing 0
(label :visible {!volume--data["mute"]} :text "")
(label :visible { volume--data["mute"]} :text "")
(label :text " ${volume--data['volume']}")))
(defwidget audio []
(box :orientation "v"
:halign "center"
:class "module text"
:space-evenly false
:spacing 0
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 15
(label :class {volume--data.output.mute ? "offline" : "special"}
:text "${volume--data.output.volume}%")
(label :class {volume--data.input.mute ? "offline" : "special"}
:text "${volume--data.input.volume}%"))
"audio system"))

View File

@ -1,17 +0,0 @@
;; -*- lisp -*-
;; This is NOT lisp. It is "yuck", a lisp-like language that is used
;; to configure eww. It is a subset of lisp, with some extra features
;; that make it more suitable for configuration.
(defpoll weather--data :interval "30m"
`curl wttr.in/84321?format=j1 | jq -c `)
(defwidget weather
[]
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text "${weather--data.current_condition[0].weatherDesc[0].value} ${weather--data.current_condition[0].temp_F}°F")
(label :text "current weather")))

View File

@ -1,213 +0,0 @@
#!/usr/bin/env python3
import asyncio
import json
import os
import sys
WorkspaceTree = dict[str, dict[str, list['Workspace']]]
WorkspaceList = dict[str, 'Workspace']
socketdir = f"/tmp/hypr/{os.environ['HYPRLAND_INSTANCE_SIGNATURE']}"
socket1 = f"{socketdir}/.socket.sock"
socket2 = f"{socketdir}/.socket2.sock"
listened_events = ['workspace', 'movewindow', 'createworkspace', 'destroyworkspace']
class Workspace:
index: str = None
name: str = None
exec_cmd: str = None
group: str = None
active: bool = False
visible: bool = False
focused: bool = False
alerted: bool = False
def __init__(self, dictionary: dict[str, str | int], group: str):
self.index = str(dictionary.get('index'))
self.name = dictionary.get('name')
self.exec_cmd = dictionary.get('exec')
self.group = group
self.active = dictionary.get('active', False)
self.visible = dictionary.get('visible', False)
self.focused = dictionary.get('focused', False)
self.alerted = dictionary.get('alerted', False)
def update_state(self, state_update, monitor_dict):
self.active = True
self.visible = monitor_dict[state_update['monitor']]['activeWorkspace']['name'] == state_update['name']
self.focused = self.visible and monitor_dict[state_update['monitor']]['focused']
self.alerted = False
def deactivate(self):
self.active = False
self.visible = False
self.focused = False
self.alerted = False
@classmethod
def parse_file(cls: type, filename: str) -> tuple[WorkspaceTree, WorkspaceList]:
result = {}
initial: dict = None
with open(filename, 'r') as file:
initial = json.load(file)
workspaces: WorkspaceList = {}
def find_workspace(workspace: dict[str, str|int], group: str) -> 'Workspace':
index = str(workspace.get('index'))
if index in workspaces:
return workspaces[index]
else:
workspaces[index] = cls(workspace, group)
return workspaces[index]
result = {
context: {
group: [
find_workspace(workspace, group) for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in initial.items()
}
return result, workspaces
@staticmethod
def full_dictify(tree: WorkspaceTree):
return {
context: {
group: [
workspace.dictify() for workspace in workspaces
] for group, workspaces in groups.items()
} for context, groups in tree.items()
}
def dictify(self):
return {
'index': self.index,
'name': self.name,
'exec': self.exec_cmd,
'active': self.active,
'visible': self.visible,
'focused': self.focused,
'alerted': self.alerted
}
workspace_tree, workspace_list = Workspace.parse_file(f"{os.environ['HOME']}/.config/hypr/workspaces.json")
data = {
"ws": {},
"current": {},
"context": "personal",
"visible": {},
}
def write_data():
global data
print(json.dumps(data), flush=True)
async def get_workspace_data():
request = b"[[BATCH]] j/workspaces; j/monitors"
reader = None
writer = None
data = None
try:
reader, writer = await asyncio.open_unix_connection(socket1)
writer.write(request)
await writer.drain()
data = await reader.read()
finally:
if writer is not None:
writer.close()
if data is None:
return;
workspace_data = None
monitor_data = None
try:
workspace_data, monitor_data = data.decode().split("}][{")
workspace_data += "}]"
monitor_data = "[{" + monitor_data
except ValueError:
print("Error unpacking response", file=sys.stderr)
return
return [json.loads(workspace_data), json.loads(monitor_data)]
async def update_workspaces():
global workspace_tree, workspace_list, data
workspaces, monitors = await get_workspace_data()
ws_hypr_dict = { ws["name"]: ws for ws in workspaces }
monitor_dict = { monitor["name"]: monitor for monitor in monitors }
touched = []
for index, ws_data in ws_hypr_dict.items():
# Update data for all active workspaces
ws_state = workspace_list.get(index)
if ws_state is None:
# If the workspace isn't configured, note it and handle gracefully
print(f"Warning: found unconfigured workspace {index}", file=sys.stderr, flush=True)
if monitor_dict[ws_data['monitor']]['activeWorkspace']['name'] == ws_data['name']:
data['current'] = {
'index': index,
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': True,
'alerted': False
}
else:
# Otherwise, 'touch' it and update status data
touched.append(index)
ws_state.update_state(ws_data, monitor_dict)
if ws_state.focused:
data['current'] = ws_state.dictify()
if ws_state.visible:
data['visible'][ws_state.group] = ws_state.dictify()
inactives = [
v for k, v in workspace_list.items() if v.active and k not in touched
]
for workspace in inactives:
workspace.deactivate()
# Create an 'unknown' workspace object for each group that doesn't yet have a listed visible workspace
for group in workspace_tree[data['context'] or 'personal'].keys():
if group not in data['visible']:
data['visible'][group] = {
'index': 'U',
'name': 'undefined',
'exec': 'alacritty',
'active': True,
'visible': True,
'focused': False,
'alerted': False
}
data['ws'] = Workspace.full_dictify(workspace_tree)
write_data()
async def main():
reader, writer = await asyncio.open_unix_connection(socket2)
await update_workspaces()
while True:
event = (await reader.readline()).decode()
eventType, eventData = event.split(">>")
if eventType in listened_events:
await update_workspaces()
asyncio.run(main())

108
.config/eww/eww.scss Normal file
View File

@ -0,0 +1,108 @@
@import "colors";
* {
all: unset;
}
.reservepower.reservepower {
color: $red;
}
.root {
color: $foreground;
font-family: "Source Code Pro";
font-size: 9pt;
background-color: rgba(0, 0, 0, 0);
// Probably needs to change
&.bar {
margin: 10px;
margin-bottom: 0px;
}
&.side {
margin: 10px;
margin-right: 0px;
}
&.bg {
background-color: $bg0;
padding: 10px;
}
.nebula {
font-family: "Nebula";
font-size: 1.2em;
&.big,
.big {
font-size: 2em;
}
&.medium,
.medium {
font-size: 1.6em;
}
&.small,
.small {
font-size: 1.4em;
}
}
}
.icon {
font-family: "Font Awesome 5 Free Solid";
}
.highlight {
color: $red;
}
.offline {
color: $bg1;
}
.special {
color: $blue;
}
.green {
color: $green;
}
.big {
font-size: 12pt;
}
// sway module
.sway--ws {
color: $bg1;
&.sway--active {
color: $foreground;
}
&.sway--visible .fill {
background-color: $foreground;
}
&.sway--focused .fill {
background-color: $foreground;
}
}
.reservepower .sway--ws.sway--active {
color: $red;
}
.reservepower .sway--ws .fill {
background-color: $red;
}
// clock module
.clock--time {
font-size: 20pt;
}
.clock--date {
font-size: 9pt;
}

1
.config/eww/eww.yuck Symbolic link
View File

@ -0,0 +1 @@
eww.yuck##hostname.tycho

View File

@ -0,0 +1,24 @@
;; -*-lisp-*- Include modules
(include "./modules/workspaces.yuck")
(include "./modules/clock.yuck")
(include "./modules/system.yuck")
(include "./modules/network.yuck")
(include "./modules/volume.yuck")
(include "./modules/aggietime.yuck")
(include "./modules/timer.yuck")
(include "./modules/mpris.yuck")
(include "./windows.yuck")
(defwindow builtinbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center")
:exclusive true
:focusable false
:stacking "fg"
(centerbox :orientation "h" :class "bar root ${power--state == 'critical' ? 'reservepower' : ''}"
(rocinante-builtinbar--left)
(rocinante-builtinbar--center)
(rocinante-builtinbar--right)))

View File

@ -0,0 +1,55 @@
;; -*-lisp-*- Include modules
(include "./modules/workspaces.yuck")
(include "./modules/clock.yuck")
(include "./modules/system.yuck")
(include "./modules/network.yuck")
(include "./modules/volume.yuck")
(include "./modules/aggietime.yuck")
(include "./modules/timer.yuck")
(include "./modules/mpris.yuck")
(include "./windows.yuck")
(defwindow leftbar
:monitor 0
:geometry (geometry :width "100%"
:height "36px"
:anchor "top center"):exclusive
true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(tycho-leftbar--left)
(tycho-leftbar--center)
(tycho-leftbar--right)))
(defwindow rightbar
:monitor 1
:geometry (geometry :width "100%"
:height "26px"
:anchor "top center"):exclusive
true
:focusable false
:stacking "fg"
(centerbox :orientation "h"
:class "bar root"
(tycho-rightbar--left)
(tycho-rightbar--center)
(tycho-rightbar--right)))
(defwindow network-status
:monitor 0
:geometry (geometry :width "200px"
:height "0px"
:x "80px"
:y "0px"
:anchor "top left")
:exclusive false
:focusable false
:stacking "overlay"
(box :orientation "v"
:class "bar root bg"
:visible {network--show-details}
(network-detail)))

View File

@ -0,0 +1,19 @@
;; -*-lisp-*-
(defpoll aggietime--data :interval "10s"
`~/.config/eww/scripts/aggietime.sh`)
(defwidget aggietime-shift []
(box :class "module text"
:spacing 0
:orientation "v"
:visible {aggietime--data != ''}
(label :class "highlight"
:text "AggieTimeD Not Running"
:visible {aggietime--data.err})
(label :class "special"
:visible {aggietime--data.active && !aggietime--data.err}
:text "${aggietime--data.hours}:${aggietime--data.minutes}")
(label :class "highlight"
:text "not clocked in"
:visible {!aggietime--data.active && !aggietime--data.err})
"current shift"))

View File

@ -1,10 +1,11 @@
;; -*-lisp-*-
(defpoll clock--data :interval "500ms" (defpoll clock--data :interval "500ms"
`date +'{"hour": "%H", "minute": "%M", "second": "%S", "year": "%Y", "day": "%d", "month": "%m", "dow": "%A", "month_name": "%B", "unix": %s}'`) `date +'{"hour": "%H", "minute": "%M", "second": "%S", "year": "%Y", "day": "%d", "month": "%m", "dow": "%A", "month_name": "%B", "unix": %s}'`)
(defwidget clock [] (defwidget clock []
(box :class "module text" (box :class "module text"
:spacing 0 :spacing 0
:orientation "v" :orientation "v"
(label :class "special" (label :class "special"
:text "${clock--data.hour}:${clock--data.minute}:${clock--data.second}") :text "${clock--data.hour}:${clock--data.minute}:${clock--data.second}")
(label :text "${clock--data.year}-${clock--data.month}-${clock--data.day}"))) (label :text "${clock--data.year}-${clock--data.month}-${clock--data.day}")))

View File

@ -0,0 +1,29 @@
;; -*-lisp-*-
(deflisten mpris--data :initial "{}"
`~/.config/eww/scripts/mpris.py`)
(defwidget mpris2
[]
(box :class "module text"
:spacing 0
:orientation "v"
(label :class {mpris--data.playing ? "special" : "offline"}
:visible {mpris--data.running}
:text "${mpris--data.title} by ${mpris--data.artist}")
(label :class "offline"
:visible {!mpris--data.running}
:text "player offline")
(label :visible {mpris--data.running}
:text "now playing from ${mpris--data.album}")
(label :visible {!mpris--data.running}
:text "player offline")))
(defwidget mpris-miniplayer []
(box :class "miniplayer"
:orientation "v"
:spacing 10
(image :path {mpris--data.album_art}
:image-width 100
:image-height 100)
(label)))

View File

@ -0,0 +1 @@
network.yuck##hostname.tycho

View File

@ -1,5 +1,6 @@
;; -*-lisp-*-
(deflisten network--data (deflisten network--data
`~/.config/eww/modules/network/network.py`) `~/.config/eww/scripts/network.py`)
(defwidget network--wlan [device] (defwidget network--wlan [device]
(box :orientation "h" (box :orientation "h"
@ -7,18 +8,18 @@
:space-evenly false :space-evenly false
:spacing 10 :spacing 10
(label :class "offline" (label :class "offline"
:visible {network--data["network"][device]["offline"]} :visible {network--data["network"][device]["offline"]}
:text "offline") :text "offline")
(label :visible {network--data["network"][device]["connecting"]} (label :visible {network--data["network"][device]["connecting"]}
:class "highlight" :class "highlight"
:text "connecting...") :text "connecting...")
(label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting} (label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting}
:class "special" :class "special"
:text "${network--data['wifi']['ssid']}") :text "${network--data['wifi']['ssid']}")
(label :visible {!network--data.connection.internet && network--data.network[device].online} (label :visible {!network--data.connection.internet && network--data.network[device].online}
:class "highlight" :class "highlight"
:text "- no internet" :text "- no internet"
))) )))
(defwidget network--lan [device] (defwidget network--lan [device]
(box :orientation "h" (box :orientation "h"
@ -26,14 +27,14 @@
:space-evenly false :space-evenly false
:spacing 0 :spacing 0
(label :class "offline" (label :class "offline"
:visible {network--data["network"][device]["offline"]} :visible {network--data["network"][device]["offline"]}
:text "offline") :text "offline")
(label :visible {network--data["network"][device]["connecting"]} (label :visible {network--data["network"][device]["connecting"]}
:class "highlight" :class "highlight"
:text "connecting...") :text "connecting...")
(label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting} (label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting}
:class "special" :class "special"
:text "${network--data['network'][device]['ip4_addr']}/${network--data['network'][device]['ip4_prefix']}"))) :text "${network--data['network'][device]['ip4_addr']}/${network--data['network'][device]['ip4_prefix']}")))
(defwidget network--proxy-vpn [device ?required] (defwidget network--proxy-vpn [device ?required]
(box :orientation "h" (box :orientation "h"
@ -42,11 +43,11 @@
:spacing 0 :spacing 0
:visible {network--data.connection.internet && (network--data["network"][device]["exists"] || required)} :visible {network--data.connection.internet && (network--data["network"][device]["exists"] || required)}
(label :class "highlight" (label :class "highlight"
:text "- insecure" :text "- insecure"
:visible {! network--data["network"][device]["exists"]}) :visible {! network--data["network"][device]["exists"]})
(label :class "green" (label :class "green"
:text "- secured" :text "- secured"
:visible {network--data["network"][device]["exists"]}))) :visible {network--data["network"][device]["exists"]})))
(defwidget vpn-network [] (defwidget vpn-network []
(box :orientation "v" (box :orientation "v"
@ -54,11 +55,11 @@
:space-evenly false :space-evenly false
:spacing 0 :spacing 0
(label :class "highlight" (label :class "highlight"
:text "offline" :text "offline"
:visible {!network--data.connection.ezrinet}) :visible {!network--data.connection.ezrinet})
(label :class "green" (label :class "green"
:text "connected" :text "connected"
:visible {network--data.connection.ezrinet}) :visible {network--data.connection.ezrinet})
"personal network")) "personal network"))
(defwidget network [] (defwidget network []
@ -67,10 +68,10 @@
:space-evenly false :space-evenly false
:spacing 0 :spacing 0
(box :orientation "h" (box :orientation "h"
:halign "center" :halign "center"
:space-evenly false :space-evenly false
:spacing 10 :spacing 10
(network--wlan :device "wlan0") (network--wlan :device "wlan0")
(network--proxy-vpn :device "wg-mullvad" :required {!network--data.trusted})) (network--proxy-vpn :device "wg-mullvad" :required {!network--data.trusted}))
"communications")) "communications"))

View File

@ -0,0 +1,236 @@
;; -*-lisp-*-
(deflisten network--data
`~/.config/eww/scripts/network.py`)
(defvar network--show-details false)
(defwidget network--interface
[device]
(box :orientation "v"
:halign "center"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {!device.online}
:text "offline")
(label :visible {device.online}
:class "special"
:text "${device.addresses[0].address}/${device.addresses[0].prefixlen}")))
(defwidget network-big--online
[]
(box :orientation "h"
:halign "start"
:valign "center"
:space-evenly false
:spacing 10
(label :class "medium green nebula"
:visible {network--data.online}
:text "online")
(label :class "medium offline nebula"
:visible {network--data.offline}
:text "offline")
(label :class "medium highlight nebula"
:visible {network--data.configuring}
:text "configuring")))
(defwidget network-big--lan
[device]
(label :visible {network--data
[device]
.online}
:class ""
:text "${network--data.interfaces[device].addresses[0].address}/${network--data.interfaces[device].addresses[0].prefixlen}"))
(defwidget network--wlan
[device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {network--data
["network"]
[device]
["offline"]
}
:text "offline")
(label :visible {network--data
["network"]
[device]
["connecting"]
}
:class "highlight"
:text "connecting...")
(label :visible {network--data
["network"]
[device]
["online"]
}
:class "special"
:text "${network--data['wifi']['ssid']}")))
(defwidget network--lan
[device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "offline"
:visible {!device.online}
:text "offline")
(label :visible {device.online}
:class {network--data.last_update.unix < clock--data.unix - 30 ? "highlight" : "special"}
:text "${device.addresses[0].address}/${device.addresses[0].prefixlen}")))
(defwidget network--secure
[]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 0
(label :class "highlight"
:text "- insecure"
:visible {!
network--data.secure })
(label :class "green"
:text "- secured via ${network--data.secure_msg}"
:visible {network--data.secure})))
(defwidget vpn-network
[]
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data
!=
''}
(label :class "highlight"
:text "offline"
:visible {!
network--data.interfaces.ezrinet.online })
(label :class "green"
:text "connected"
:visible {network--data.interfaces.ezrinet.online})
"personal network"))
(defwidget network
[]
(button :onclick "eww update network--show-details=${!network--show-details}"
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
:visible {network--data != ''}
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 10
(network--lan :device {network--data.default_interface}))
"communications")))
(defwidget network--public-ip
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"public ip:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "highlight"
:text "no response"
:visible {network--data.online && !network--data.have_public_ip})
(label :class "special"
:text {network--data.public_ip.ip}
:visible {network--data.online && network--data.have_public_ip}))))
(defwidget network--default-route
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"route on:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "highlight"
:text "no route"
:visible {network--data.online && !network--data.have_default_route})
(label :class "special"
:text {network--data.default_route}
:visible {network--data.online && network--data.have_default_route}))))
(defwidget network--gateway
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"gateway:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "no response"
:visible {!network--data.have_gateway})
(label :class "special"
:text {network--data.gateway}
:visible {network--data.have_gateway}))))
(defwidget network--status-summary
[]
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"status:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class "highlight"
:text "offline"
:visible {!network--data.online})
(label :class "special"
:text "online"
:visible {network--data.online && !network--data.secure})
(label :class "green"
:text {network--data.secure_msg == "usu" ? "vpn online" : "secure"}
:visible {network--data.online && network--data.secure}))))
(defwidget network-detail
[]
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
(network--status-summary)
(network--public-ip)
(network--default-route)
(network--gateway)
(centerbox :orientation "h"
:halign "start"
:width 200
(box :halign "start"
"last update:")
""
(box :halign "end"
:spacing 0
:space-evenly false
(label :class {network--data.last_update.unix < clock--data.unix - 30 ? "highlight" : "special"}
:text "${network--data.last_update.month}-${network--data.last_update.day} ${network--data.last_update.hour}:${network--data.last_update.minute}:${network--data.last_update.second}")))
))

View File

@ -0,0 +1,60 @@
;; -*-lisp-*-
(deflisten system--data :initial "{}"
`~/.config/eww/scripts/system.py`)
(defwidget system-battery [battery]
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'green' : EWW_BATTERY[battery].capacity <= 25 ? 'highlight' : 'special'}
:text "${EWW_BATTERY[battery].capacity}%")
(label :text "${EWW_BATTERY[battery].status == 'Charging' || EWW_BATTERY[battery].status == 'Full' ? 'external' : 'internal'} power")))
(defwidget system-name []
(label :halign "center"
:valign "center"
:class "module text big nebula"
:text {system--data.hostname}))
(defwidget system-cpu-avg []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
:spacing 0
(label :class {system--data.cpu.avg > 90 ? 'highlight' : 'special'}
:text "${system--data.cpu.avg_display}%")
(label :text "cpu utilization")))
(defwidget system--cpu-core [core]
(label :class {core.value > 90 ? "highlight" : "special"}
:text "${core.display}%"))
(defwidget system-cpu-percore []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
;; (box :orientation "h"
;; :halign "center"
;; :space-evenly false
;; (for core in {system--data.cpu.cores}
;; (system--cpu-core :core core)))
(label :class "special"
:text {system--data.cpu.cores_display})
(label :text "per-core cpu utilization")
))
(defwidget system-memory []
(box :orientation "v"
:halign "start"
:class "module text"
:space-evenly false
(label :class {system--data.memory.percent > 85 ? "highlight" : "special"}
:text "${round(system--data.memory.used / 1024 / 1024 / 1024, 2)} / ${round(system--data.memory.total / 1024 / 1024 / 1024, 2)} GiB")
(label :text "system memory")))

View File

@ -0,0 +1,12 @@
;; -*-lisp-*-
(deflisten timer--text :initial 'loading...'
`~/.config/eww/scripts/timer.py`)
(defwidget timer []
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text {timer--text})
(label :text "baldur's gate 3")))

View File

@ -0,0 +1,29 @@
;; -*-lisp-*-
(deflisten volume--data
`~/.config/eww/scripts/volume.py`)
(defwidget volume-h []
(box :orientation "h"
:halign "start"
:class "module ${volume--data['mute'] ? 'offline' : ''}"
:space-evenly false
:spacing 0
(label :visible {!volume--data["mute"]} :text "")
(label :visible { volume--data["mute"]} :text "")
(label :text " ${volume--data['volume']}")))
(defwidget audio []
(box :orientation "v"
:halign "center"
:class "module text"
:space-evenly false
:spacing 0
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 15
(label :class {volume--data.output.mute ? "offline" : "special"}
:text "${volume--data.output.volume}%")
(label :class {volume--data.input.mute ? "offline" : "special"}
:text "${volume--data.input.volume}%"))
"audio system"))

View File

@ -0,0 +1,13 @@
;; -*-lisp-*-
(defpoll weather--data :interval "30m"
`curl wttr.in/84321?format=j1 | jq -c `)
(defwidget weather
[]
(box :class "module text"
:spacing 0
:orientation "v"
(label :class "special"
:text "${weather--data.current_condition[0].weatherDesc[0].value} ${weather--data.current_condition[0].temp_F}°F")
(label :text "current weather")))

View File

@ -1,29 +1,30 @@
;; -*-lisp-*-
(deflisten sway--data :initial '{"mode": "default"}' (deflisten sway--data :initial '{"mode": "default"}'
`~/.config/eww/modules/workspaces/sway.py`) `~/.config/eww/scripts/sway.py`)
(defvar hypr--data '{}') (defvar hypr--data '{}')
(defwidget sway--workspace [ws] (defwidget sway--workspace [ws]
(button :onclick "swaymsg workspace ${ws['index']}" (button :onclick "swaymsg workspace ${ws['index']}"
(circular-progress (circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused" : ""} ${ws.alerted ? "sway--alerted" : ""}' :class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused" : ""} ${ws.alerted ? "sway--alerted" : ""}'
:value 100 :value 100
:start-at 0 :start-at 0
:clockwise true :clockwise true
:width 16 :width 16
:thickness 1 :thickness 1
(box :class 'fill' )))) (box :class 'fill' ))))
(defwidget hypr--workspace [ws] (defwidget hypr--workspace [ws]
(button :onclick "hyprmsg dispatch workspace ${ws['index']}" (button :onclick "hyprmsg dispatch workspace ${ws['index']}"
(circular-progress (circular-progress
:class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused": ""}' :class 'indicator-circle sway--ws ${ws.active ? "sway--active" : ""} ${ws.visible ? "sway--visible" : ""} ${ws.focused ? "sway--focused": ""}'
:value 100 :value 100
:start-at 0 :start-at 0
:clockwise true :clockwise true
:width 15 :width 15
:thickness 1 :thickness 1
(box :class 'fill' :visible {ws.focused})))) (box :class 'fill' :visible {ws.focused}))))
(defwidget sway-mode [] (defwidget sway-mode []
(box :orientation "v" (box :orientation "v"
@ -33,18 +34,18 @@
:class "module text" :class "module text"
:visible {sway--data != '' && sway--data.mode != "default"} :visible {sway--data != '' && sway--data.mode != "default"}
(label :class "special" (label :class "special"
:text "${hypr--data.mode}") :text "${hypr--data.mode}")
"sway mode")) "sway mode"))
(defwidget sway-workspace [group] (defwidget sway-workspace [group]
(box :orientation "v" (box :orientation "v"
:halign "center" :halign "center"
:valign "center" :valign "center"
:space-evenly false :space-evenly false
:spacing 0 :spacing 0
:class 'module text' :class 'module text'
(label :class '${sway--data.visible[group].focused ? "special" : "offline"} nebula medium small' (label :class '${sway--data.visible[group].focused ? "special" : "offline"} nebula medium small'
:text '${sway--data.visible[group].name}'))) :text '${sway--data.visible[group].name}')))
; (label :text "current workspace"))) ; (label :text "current workspace")))
(defwidget hypr-workspace [group] (defwidget hypr-workspace [group]
@ -54,18 +55,18 @@
:spacing 0 :spacing 0
:class 'module text' :class 'module text'
(label :class '${hypr--data.visible[group].focused ? "special" : "offline"}' (label :class '${hypr--data.visible[group].focused ? "special" : "offline"}'
:text '${hypr--data.visible[group].name}') :text '${hypr--data.visible[group].name}')
(label :text "current workspace"))) (label :text "current workspace")))
(defwidget sway-workspaces [group] (defwidget sway-workspaces [group]
(box :orientation "h" (box :orientation "h"
:halign "start" :halign "start"
:visible {sway--data != ''} :visible {sway--data != ''}
:space-evenly false :space-evenly false
:spacing 5 :spacing 5
:class "sway--root" :class "sway--root"
(for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]} (for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]}
(sway--workspace :ws workspace)))) (sway--workspace :ws workspace))))
(defwidget hypr-workspaces [group] (defwidget hypr-workspaces [group]
(box :orientation "h" (box :orientation "h"
@ -74,4 +75,4 @@
:spacing 5 :spacing 5
:class "sway--root" :class "sway--root"
(for workspace in {hypr--data.ws[hypr--data.context ?: "personal"][group]} (for workspace in {hypr--data.ws[hypr--data.context ?: "personal"][group]}
(hypr--workspace :ws workspace)))) (hypr--workspace :ws workspace))))

View File

@ -0,0 +1 @@
network.py##hostname.tycho

View File

@ -218,7 +218,6 @@ last_request = None
last_first_hop = None last_first_hop = None
while True: while True:
start = now()
try: try:
online = ping("1.1.1.1") online = ping("1.1.1.1")
except: except:
@ -278,10 +277,3 @@ while True:
), ),
flush=True, flush=True,
) )
end = now()
delta = end - start
if delta > 5:
print("Warning: took longer than 5 seconds to run", file=sys.stderr, flush=True)
else:
sleep(5 - delta)

150
.config/eww/windows.yuck Normal file
View File

@ -0,0 +1,150 @@
;;;; -*-lisp-*- ;;;;
;; Top-Level Module Definitions ;;
;;;; ;;;;
;;; ;;;
;; Bars for Rocinante ;;
;;; ;;;
(defwidget rocinante-builtinbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "builtin")
(sway-workspace :group "builtin")))
(defwidget rocinante-builtinbar--center []
(box :orientation "h"
:halign "center"
:space-evenly false
:spacing 20
:class "centerbox"
(system-name)))
(defwidget rocinante-builtinbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(vpn-network)
(network)
(system-battery :battery "BAT1")
(audio)
(clock)))
;;; ;;;
;; Bars for S.S.V. Normandy ;;
;;; ;;;
(defwidget normandy-leftbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(system-name)))
(defwidget normandy-leftbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(sway-workspace :group "left")
(sway-workspaces :group "left")))
(defwidget normandy-rightbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspace :group "right")
(sway-workspaces :group "right")))
(defwidget normandy-rightbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(system-name)))
(defwidget normandy-sidebar []
(box :orientation "v"
:valign "start"
:space-evenly false
:spacing 20
:class "sidebar"
(sideclock)
(network-sidebar-details)
(cpu-mem-gauges)
(gpu-gauges)))
;;; ;;;
;; Bars for Tycho Station ;;
;;; ;;;
(defwidget tycho-leftbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(clock)
(network)
(vpn-network)
(aggietime-shift)))
(defwidget tycho-leftbar--center []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "centerbox"
(system-name)))
(defwidget tycho-leftbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(sway-workspace :group "left")
(sway-workspaces :group "left")))
(defwidget tycho-rightbar--left []
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 20
:class "leftbox"
(sway-workspaces :group "right")
(sway-workspace :group "right")))
(defwidget tycho-rightbar--center []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "centerbox"
(system-name)))
(defwidget tycho-rightbar--right []
(box :orientation "h"
:halign "end"
:space-evenly false
:spacing 20
:class "rightbox"
(mpris2)
(system-memory)
(system-cpu-avg)
(clock)))