commit 1eca57b40e906e463d45a08fdb96a86d46520f34 Author: Shadow Cat Date: Mon Jun 5 11:52:04 2023 -0400 initial commit diff --git a/bar/bar.yuck b/bar/bar.yuck new file mode 100644 index 0000000..97cda8f --- /dev/null +++ b/bar/bar.yuck @@ -0,0 +1,24 @@ +(include "bar/widget.yuck") + +(include "bar/widgets/sys.yuck") +(include "bar/widgets/wss.yuck") +(include "bar/widgets/info.yuck") + +(defwidget bar [monitor] + (centerbox :class "bar" :orientation "h" + (bar-left) + (bar-center :monitor monitor) + (bar-right))) + +(defwidget bar-left [] + (box :class "bar-left" :space-evenly false :halign "start" + (bat) (cpu) (temp) (mem) (disk))) + +(defwidget bar-center [monitor] + (box :class "bar-center" :space-evenly false + (workspaces :monitor monitor))) + +(defwidget bar-right [] + (box :class "bar-right" :space-evenly false :halign "end" + (brightness) (vol) (net) (date) (time))) + diff --git a/bar/widget.yuck b/bar/widget.yuck new file mode 100644 index 0000000..b3b0005 --- /dev/null +++ b/bar/widget.yuck @@ -0,0 +1,62 @@ +(defvar eww "eww") + +(defwidget metric [label value min max onchange] + (box :orientation "h" + :class "metric mod" + :space-evenly false + (box :class "label" label) + (scale :min min + :max max + :active {onchange != ""} + :value value + :onchange onchange))) + +(defwidget hover-metric [icon value ?class revealname reveal onchange] + (eventbox :onhover "${eww} update ${revealname}=true" + :onhoverlost "${eww} update ${revealname}=false" + (box :orientation "h" + :class "metric mod" + :space-evenly false + (box :class {class ?: ""} {icon}) + (revealer :transition "slideleft" + :reveal reveal + :duration "300ms" + (scale :min 0 + :max 100 + :value value + :onchange onchange))))) + +(defwidget hover-text [icon value ?class revealname reveal] + (eventbox :onhover "${eww} update ${revealname}=true" + :onhoverlost "${eww} update ${revealname}=false" + (box :orientation "h" + :class "metric mod" + :space-evenly false + (box :class {class ?: ""} {icon}) + (revealer :transition "slideleft" + :reveal net_reveal + :duration "300ms" + (label :text {value} + :class "purple"))))) + +(defwidget status [label poll] + (box :orientation "h" + :class "metric mod" + :space-evenly false + (box :class "label" label) + (text :poll poll))) + +(defwidget text [poll] + (box :class "text mod" + poll)) + +(defwidget circle [value ?icon class] + (box :class "mod" + (circular-progress :value value + :width 30 + :class "circle-bar ${class}" + :thickness 4 + :start-at 75 + (label :text {icon ?: ""} + :class "circle ${class}")))) + diff --git a/bar/widgets/info.yuck b/bar/widgets/info.yuck new file mode 100644 index 0000000..3c049db --- /dev/null +++ b/bar/widgets/info.yuck @@ -0,0 +1,38 @@ +(defvar vol_reveal false) +(defvar bright_reveal false) +(defvar net_reveal false) + +(defpoll vol :interval "2s" "wpctl get-volume @DEFAULT_AUDIO_SINK@ | awk '{print $2 * 100}'") +(defwidget vol [] + (hover-metric :icon {vol < 33 ? "" : vol < 66 ? "" : "󰕾"} + :value vol + :class "green" + :revealname "vol_reveal" + :reveal vol_reveal + :onchange "wpctl set-volume @DEFAULT_SINK@ {}% && eww update vol={}")) + +(defpoll bright :interval "10s" "light") +(defwidget brightness [] + (hover-metric :icon "" + :value bright + :class "yellow" + :revealname "bright_reveal" + :reveal bright_reveal + :onchange "light -S {}%")) + +(defpoll net :interval "2s" "iw dev wlan0 link | awk 'NR==2 {print $2}'") +(defwidget net [] + (hover-text :icon " " + :value net + :class "cyan" + :revealname "net_reveal" + :reveal net_reveal)) + +(defpoll time :interval "1s" "date '+%H:%M:%S'") +(defwidget time [] + (text :poll time)) + +(defpoll date :interval "10s" "date '+%y-%m-%d'") +(defwidget date [] + (text :poll date)) + diff --git a/bar/widgets/sys.yuck b/bar/widgets/sys.yuck new file mode 100644 index 0000000..037f436 --- /dev/null +++ b/bar/widgets/sys.yuck @@ -0,0 +1,25 @@ +(defwidget cpu [] + (circle :value {EWW_CPU.avg} + :icon "" + :class "cyan")) + +(defwidget temp [] + (circle :value {EWW_TEMPS.CORETEMP_PACKAGE_ID_0} + :icon "" + :class "magenta")) + +(defwidget mem [] + (circle :value {EWW_RAM.used_mem_perc} + :icon "" + :class "yellow")) + +(defwidget disk [] + (circle :value {round((1 - (EWW_DISK["/"].free / EWW_DISK["/"].total)) * 100, 0)} + :icon "" + :class "red")) + +(defwidget bat [] + (circle :value {EWW_BATTERY.BAT0.capacity} + :icon "⏻" + :class "green")) + diff --git a/bar/widgets/wss.yuck b/bar/widgets/wss.yuck new file mode 100644 index 0000000..b71fe09 --- /dev/null +++ b/bar/widgets/wss.yuck @@ -0,0 +1,23 @@ +;; (deflisten wslist0 +;; "scripts/getwss eDP-1") +;; (deflisten wslist1 +;; "scripts/getwss DP-") +(deflisten wslist0 + "scripts/getwss 0") +(deflisten wslist1 + "scripts/getwss 1") +(defwidget workspaces [monitor] + (box :class "workspaces" + (for entry in {monitor == 0 ? wslist0 : wslist1} + (button :class "${ + entry.urgent ? "urgent" + : entry.focused ? "focused" + : "unfocused" + } id${entry.id}" + :onclick "hyprctl dispatch workspace ${entry.id}" + {entry.name} + ) + ) + ) +) + diff --git a/eww.scss b/eww.scss new file mode 100644 index 0000000..c5392f3 --- /dev/null +++ b/eww.scss @@ -0,0 +1,130 @@ +$white: #BAC2DE; +$black: #45475A; +$black2: #585B70; +$red: #F38BA8; +$green: #A6E3A1; +$yellow: #F9E2AF; +$blue: #89B4FA; +$magenta: #F5C2E7; +$cyan: #94E2D5; + +$magenta3: #e6aaee; +$purple: #b0b0e8; + +$text: $white; +$mod-bg: #505060; +$trough: #464666; +$bg: rgba(#1e1e2e, .7); +$hover-bg: $black; + +* { + all: unset; +} + +.bar { + margin-top: 10px; + color: $text; + font-size: 20px; + font-family: "Symbols Nerd Font", "Comic Code Ligatures"; + margin-left: 15px; + margin-right: 15px; +} + +.mod { + padding-left: 10px; + padding-right: 10px; +} + +.metric scale trough highlight { + background-color: $magenta; + border-radius: 10px; +} + +.metric scale trough { + background-color: $trough; + border-radius: 50px; + min-height: 6px; + min-width: 50px; + margin-left: 10px; +} + +.workspaces button:hover { + background-color: $hover-bg; +} + +.workspaces { + // un... un bro momento + .id1 { + font-size: 15px; + } + .id2 { + font-size: 16px; + } + .id3 { + font-size: 15px; + } + .id6 { + font-size: 13px; + } + .id7 { + font-size: 14px; + } + .id8 { + font-size: 15px; + } + + button { + padding: 0 7px; + margin: 0 3px; + border-radius: 50%; + color: $text; + border: 2px solid; + border-color: $black2; + } + button.focused { + border-color: $magenta3; + color: $purple; + } + button.urgent { + background-color: $magenta; + color: $black; + } +} + +.circle { + font-size: 14px; + margin: 8px; +} + +.red { + color: $red; +} + +.green { + color: $green; +} + +.yellow { + color: $yellow; +} + +.blue { + color: $blue; +} + +.magenta { + color: $magenta; +} + +.cyan { + color: $cyan; +} + +.purple { + color: $purple; +} + +.circle-bar { + background-color: $bg; +} + diff --git a/eww.yuck b/eww.yuck new file mode 100644 index 0000000..a3f9809 --- /dev/null +++ b/eww.yuck @@ -0,0 +1,21 @@ +(include "bar/bar.yuck") + +(defwindow bar-eDP + :monitor 0 + :exclusive true + :geometry (geometry :x "0%" + :y "0%" + :width "100%" + :height "30px" + :anchor "top center") + (bar :monitor 0)) + +(defwindow bar-HDMI + :monitor 1 + :exclusive true + :geometry (geometry :x "0%" + :y "0%" + :width "100%" + :height "30px" + :anchor "top center") + (bar :monitor 1)) diff --git a/scripts/getwss b/scripts/getwss new file mode 100755 index 0000000..4dab8b2 --- /dev/null +++ b/scripts/getwss @@ -0,0 +1,118 @@ +#!/bin/env python3 +import os +import sys +import subprocess +import json +import socket +from dataclasses import dataclass + +NAME = [ + "?", + "", + "󰄛", + "󰴈", + "♪", + "", + "", + "󰑴", + "", +] + +@dataclass +class State: + wss: dict + mname: str + focused: bool + prev_active: int + +def handle(state: State, event: str, data: str = None): + wss = state.wss + changed = True + + if event == "focusedmon": + state.focused = data[:-2] == state.mname + if not state.focused: + return + + if event == "workspace": + wid = int(data) + if state.prev_active in wss.keys(): + wss[state.prev_active]['focused'] = False + wss[wid]['focused'] = True + state.prev_active = wid + return output(state) + if event == "createworkspace": + wss[int(data)] = new_ws(int(data), True, False) + state.wss = dict(sorted(wss.items())) + return output(state) + if event == "destroyworkspace": + del wss[int(data)] + return output(state) + +def output(state: State): + print(json.dumps(list(state.wss.values())), flush=True) + +def main(mid: str): + state = get_state(mid) + output(state) + + isig = os.getenv("HYPRLAND_INSTANCE_SIGNATURE") + client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + client.connect(f"/tmp/hypr/{isig}/.socket2.sock") + while True: + r = client.recv(1024) + if not r: + break + msgs = r.decode().strip().split("\n") + for msg in msgs: + parts = msg.split(">>") + handle(state, *parts) + +def get_state(mid: str): + mid = int(mid) + res = subprocess.run( + ["hyprctl", "monitors", "-j"], + capture_output=True + ) + raw_mons = json.loads(res.stdout) + res = subprocess.run( + ["hyprctl", "workspaces", "-j"], + capture_output=True + ) + raw_wss = json.loads(res.stdout) + + mname: str = None + activews: int = None + focused: bool = None + for m in raw_mons: + if m['id'] == mid: + activews = int(m['activeWorkspace']['id']) + mname = m['name'] + focused = m['focused'] + break + if mname is None: + print("Error: monitor not found") + sys.exit(1) + + wss = dict() + for ws in raw_wss: + if ws['monitor'] == mname: + wid = int(ws['id']) + wss[wid] = new_ws(wid, wid == activews, False) + wss = dict(sorted(wss.items())) + return State(wss, mname, focused, activews) + +def new_ws(wid, focused, urgent): + return { + 'id': wid, + 'name': NAME[wid], + 'focused': focused, + 'urgent': urgent + } + +if __name__ == '__main__': + try: + main(*sys.argv[1:]) + except KeyboardInterrupt: + pass + diff --git a/scripts/getwsss b/scripts/getwsss new file mode 100755 index 0000000..2081124 Binary files /dev/null and b/scripts/getwsss differ