Added rocinante eww config

This commit is contained in:
Ezri 2024-03-07 13:10:01 -07:00
parent bbb65f61c3
commit e5cc36a647
19 changed files with 1194 additions and 1 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,11 @@
(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.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

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

View File

@ -0,0 +1,81 @@
#!/usr/bin/env python3
import subprocess
import json
from time import sleep
TRUSTED_NETWORKS = ['gayer people']
def wifi():
ssid_cmd = subprocess.run(['iwgetid', '-r'], capture_output = True)
if ssid_cmd.returncode != 0:
return {"connected": False, "ssid": None}
ssid = ssid_cmd.stdout.decode('utf-8').strip()
ssid = ssid if len(ssid) <= 15 else f"{ssid[:14]}"
return {"connected": True, "ssid": ssid}
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,
"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
def ping(host: str):
ping_cmd = subprocess.Popen(['/usr/bin/ping', '-c1', '-W2', host], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return ping_cmd
counter = 0
ezrinet_last = False
internet_last = False
ezrinet_ping = None
internet_ping = None
while True:
if counter == 0:
ezrinet_ping = ping('10.242.3.1')
internet_ping = ping('1.1.1.1')
if ezrinet_ping.poll() is not None:
ezrinet_last = ezrinet_ping.returncode == 0
if internet_ping.poll() is not None:
internet_last = internet_ping.returncode == 0
wifi_data = wifi()
result = {
"wifi": wifi_data,
"network": {
"wlan0": netdev("wlan0"),
"ezrinet": netdev("ezrinet"),
"wg-mullvad": netdev("mullvad"),
},
"connection": {
"ezrinet": ezrinet_last,
"internet": internet_last
},
"trusted": trusted(wifi_data.get("ssid", None))
}
print(json.dumps(result), flush=True)
counter += 1
# Send pings every 10 seconds
counter %= 3
sleep(1)

View File

@ -0,0 +1,76 @@
(deflisten network--data
`~/.config/eww/modules/network/network.py`)
(defwidget network--wlan [device]
(box :orientation "h"
:halign "start"
:space-evenly false
:spacing 10
(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['wifi']['ssid']}")
(label :visible {!network--data.connection.internet && network--data.network[device].online}
:class "highlight"
:text "- no internet"
)))
(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.connection.internet && (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 vpn-network []
(box :orientation "v"
:halign "start"
:space-evenly false
:spacing 0
(label :class "highlight"
:text "offline"
:visible {!network--data.connection.ezrinet})
(label :class "green"
:text "connected"
:visible {network--data.connection.ezrinet})
"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--wlan :device "wlan0")
(network--proxy-vpn :device "wg-mullvad" :required {!network--data.trusted}))
"communications"))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1 +0,0 @@
swayidle##class.desktop