Unified EWW config
This commit is contained in:
parent
e5cc36a647
commit
1dd4f8d8e4
@ -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;
|
||||
}
|
||||
@ -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))
|
||||
@ -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 |
@ -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())
|
||||
@ -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"]}%'))
|
||||
|
||||
@ -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"
|
||||
|
||||
)))))))
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
@ -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())
|
||||
@ -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]})
|
||||
))
|
||||
|
||||
@ -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()
|
||||
@ -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']}")))
|
||||
@ -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)
|
||||
@ -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"))))
|
||||
))
|
||||
@ -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
|
||||
@ -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)
|
||||
@ -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"]}')
|
||||
))
|
||||
@ -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)
|
||||
@ -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 "%"))
|
||||
@ -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)
|
||||
@ -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")))
|
||||
|
||||
@ -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"))
|
||||
@ -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())
|
||||
@ -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))))
|
||||
@ -1 +0,0 @@
|
||||
eww-modules
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
@ -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))
|
||||
@ -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 |
@ -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']}")))
|
||||
@ -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)
|
||||
@ -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}))
|
||||
@ -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())
|
||||
@ -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"))
|
||||
@ -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())
|
||||
@ -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())
|
||||
@ -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))))
|
||||
@ -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))))
|
||||
@ -1 +0,0 @@
|
||||
eww-modules
|
||||
@ -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;
|
||||
@ -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))
|
||||
@ -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))
|
||||
@ -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"))
|
||||
@ -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 |
@ -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)))
|
||||
@ -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)
|
||||
@ -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}")))
|
||||
))
|
||||
@ -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")))
|
||||
|
||||
|
||||
|
||||
@ -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")))
|
||||
|
||||
@ -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())
|
||||
@ -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"))
|
||||
@ -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")))
|
||||
@ -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
108
.config/eww/eww.scss
Normal 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
1
.config/eww/eww.yuck
Symbolic link
@ -0,0 +1 @@
|
||||
eww.yuck##hostname.tycho
|
||||
24
.config/eww/eww.yuck##hostname.rocinante
Normal file
24
.config/eww/eww.yuck##hostname.rocinante
Normal 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)))
|
||||
55
.config/eww/eww.yuck##hostname.tycho
Normal file
55
.config/eww/eww.yuck##hostname.tycho
Normal 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)))
|
||||
|
||||
19
.config/eww/modules/aggietime.yuck
Normal file
19
.config/eww/modules/aggietime.yuck
Normal 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"))
|
||||
@ -1,10 +1,11 @@
|
||||
;; -*-lisp-*-
|
||||
(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 []
|
||||
(box :class "module text"
|
||||
:spacing 0
|
||||
:orientation "v"
|
||||
(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}")))
|
||||
29
.config/eww/modules/mpris.yuck
Normal file
29
.config/eww/modules/mpris.yuck
Normal 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)))
|
||||
1
.config/eww/modules/network.yuck
Symbolic link
1
.config/eww/modules/network.yuck
Symbolic link
@ -0,0 +1 @@
|
||||
network.yuck##hostname.tycho
|
||||
@ -1,5 +1,6 @@
|
||||
;; -*-lisp-*-
|
||||
(deflisten network--data
|
||||
`~/.config/eww/modules/network/network.py`)
|
||||
`~/.config/eww/scripts/network.py`)
|
||||
|
||||
(defwidget network--wlan [device]
|
||||
(box :orientation "h"
|
||||
@ -7,18 +8,18 @@
|
||||
:space-evenly false
|
||||
:spacing 10
|
||||
(label :class "offline"
|
||||
:visible {network--data["network"][device]["offline"]}
|
||||
:text "offline")
|
||||
:visible {network--data["network"][device]["offline"]}
|
||||
:text "offline")
|
||||
(label :visible {network--data["network"][device]["connecting"]}
|
||||
:class "highlight"
|
||||
:text "connecting...")
|
||||
:class "highlight"
|
||||
:text "connecting...")
|
||||
(label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting}
|
||||
:class "special"
|
||||
:text "${network--data['wifi']['ssid']}")
|
||||
:class "special"
|
||||
:text "${network--data['wifi']['ssid']}")
|
||||
(label :visible {!network--data.connection.internet && network--data.network[device].online}
|
||||
:class "highlight"
|
||||
:text "- no internet"
|
||||
)))
|
||||
:class "highlight"
|
||||
:text "- no internet"
|
||||
)))
|
||||
|
||||
(defwidget network--lan [device]
|
||||
(box :orientation "h"
|
||||
@ -26,14 +27,14 @@
|
||||
:space-evenly false
|
||||
:spacing 0
|
||||
(label :class "offline"
|
||||
:visible {network--data["network"][device]["offline"]}
|
||||
:text "offline")
|
||||
:visible {network--data["network"][device]["offline"]}
|
||||
:text "offline")
|
||||
(label :visible {network--data["network"][device]["connecting"]}
|
||||
:class "highlight"
|
||||
:text "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']}")))
|
||||
:class "special"
|
||||
:text "${network--data['network'][device]['ip4_addr']}/${network--data['network'][device]['ip4_prefix']}")))
|
||||
|
||||
(defwidget network--proxy-vpn [device ?required]
|
||||
(box :orientation "h"
|
||||
@ -42,11 +43,11 @@
|
||||
:spacing 0
|
||||
:visible {network--data.connection.internet && (network--data["network"][device]["exists"] || required)}
|
||||
(label :class "highlight"
|
||||
:text "- insecure"
|
||||
:visible {! network--data["network"][device]["exists"]})
|
||||
:text "- insecure"
|
||||
:visible {! network--data["network"][device]["exists"]})
|
||||
(label :class "green"
|
||||
:text "- secured"
|
||||
:visible {network--data["network"][device]["exists"]})))
|
||||
:text "- secured"
|
||||
:visible {network--data["network"][device]["exists"]})))
|
||||
|
||||
(defwidget vpn-network []
|
||||
(box :orientation "v"
|
||||
@ -54,11 +55,11 @@
|
||||
:space-evenly false
|
||||
:spacing 0
|
||||
(label :class "highlight"
|
||||
:text "offline"
|
||||
:visible {!network--data.connection.ezrinet})
|
||||
:text "offline"
|
||||
:visible {!network--data.connection.ezrinet})
|
||||
(label :class "green"
|
||||
:text "connected"
|
||||
:visible {network--data.connection.ezrinet})
|
||||
:text "connected"
|
||||
:visible {network--data.connection.ezrinet})
|
||||
"personal network"))
|
||||
|
||||
(defwidget network []
|
||||
@ -67,10 +68,10 @@
|
||||
:space-evenly false
|
||||
:spacing 0
|
||||
(box :orientation "h"
|
||||
:halign "center"
|
||||
:space-evenly false
|
||||
:spacing 10
|
||||
(network--wlan :device "wlan0")
|
||||
(network--proxy-vpn :device "wg-mullvad" :required {!network--data.trusted}))
|
||||
:halign "center"
|
||||
:space-evenly false
|
||||
:spacing 10
|
||||
(network--wlan :device "wlan0")
|
||||
(network--proxy-vpn :device "wg-mullvad" :required {!network--data.trusted}))
|
||||
"communications"))
|
||||
|
||||
236
.config/eww/modules/network.yuck##hostname.tycho
Normal file
236
.config/eww/modules/network.yuck##hostname.tycho
Normal 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}")))
|
||||
))
|
||||
60
.config/eww/modules/system.yuck
Normal file
60
.config/eww/modules/system.yuck
Normal 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")))
|
||||
|
||||
|
||||
|
||||
12
.config/eww/modules/timer.yuck
Normal file
12
.config/eww/modules/timer.yuck
Normal 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")))
|
||||
|
||||
29
.config/eww/modules/volume.yuck
Normal file
29
.config/eww/modules/volume.yuck
Normal 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"))
|
||||
13
.config/eww/modules/weather.yuck
Normal file
13
.config/eww/modules/weather.yuck
Normal 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")))
|
||||
@ -1,29 +1,30 @@
|
||||
;; -*-lisp-*-
|
||||
(deflisten sway--data :initial '{"mode": "default"}'
|
||||
`~/.config/eww/modules/workspaces/sway.py`)
|
||||
`~/.config/eww/scripts/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' ))))
|
||||
(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' ))))
|
||||
|
||||
(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}))))
|
||||
(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"
|
||||
@ -33,18 +34,18 @@
|
||||
:class "module text"
|
||||
:visible {sway--data != '' && sway--data.mode != "default"}
|
||||
(label :class "special"
|
||||
:text "${hypr--data.mode}")
|
||||
:text "${hypr--data.mode}")
|
||||
"sway mode"))
|
||||
|
||||
(defwidget sway-workspace [group]
|
||||
(box :orientation "v"
|
||||
:halign "center"
|
||||
:valign "center"
|
||||
:valign "center"
|
||||
:space-evenly false
|
||||
:spacing 0
|
||||
:class 'module text'
|
||||
(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")))
|
||||
|
||||
(defwidget hypr-workspace [group]
|
||||
@ -54,18 +55,18 @@
|
||||
:spacing 0
|
||||
:class 'module text'
|
||||
(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")))
|
||||
|
||||
(defwidget sway-workspaces [group]
|
||||
(box :orientation "h"
|
||||
:halign "start"
|
||||
:visible {sway--data != ''}
|
||||
:space-evenly false
|
||||
:spacing 5
|
||||
:class "sway--root"
|
||||
(for workspace in {sway--data.ws[sway--data.context ?: "personal"][group]}
|
||||
(sway--workspace :ws workspace))))
|
||||
(box :orientation "h"
|
||||
:halign "start"
|
||||
:visible {sway--data != ''}
|
||||
: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"
|
||||
@ -74,4 +75,4 @@
|
||||
:spacing 5
|
||||
:class "sway--root"
|
||||
(for workspace in {hypr--data.ws[hypr--data.context ?: "personal"][group]}
|
||||
(hypr--workspace :ws workspace))))
|
||||
(hypr--workspace :ws workspace))))
|
||||
1
.config/eww/scripts/network.py
Symbolic link
1
.config/eww/scripts/network.py
Symbolic link
@ -0,0 +1 @@
|
||||
network.py##hostname.tycho
|
||||
@ -218,7 +218,6 @@ last_request = None
|
||||
last_first_hop = None
|
||||
|
||||
while True:
|
||||
start = now()
|
||||
try:
|
||||
online = ping("1.1.1.1")
|
||||
except:
|
||||
@ -278,10 +277,3 @@ while 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
150
.config/eww/windows.yuck
Normal 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)))
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user