From 089464890c9f4bbe64c58f57853c50e5144715d1 Mon Sep 17 00:00:00 2001 From: "E. Almqvist" Date: Wed, 21 Dec 2022 21:40:29 +0100 Subject: [PATCH] Added half-baked eww bar --- eww/.config/eww/eww.scss | 75 +++++++ eww/.config/eww/eww.yuck | 90 ++++++++ .../__pycache__/workspace.cpython-310.pyc | Bin 0 -> 1742 bytes eww/.config/eww/scripts/check-all-updates.sh | 20 ++ eww/.config/eww/scripts/cmus.sh | 20 ++ eww/.config/eww/scripts/get_spotify_status.sh | 50 +++++ eww/.config/eww/scripts/getram | 2 + eww/.config/eww/scripts/getvol | 2 + eww/.config/eww/scripts/pavolume.sh | 194 ++++++++++++++++++ .../eww/scripts/scroll_spotify_status.sh | 12 ++ eww/.config/eww/scripts/updates.sh | 20 ++ eww/.config/eww/scripts/workspace.py | 108 ++++++++++ 12 files changed, 593 insertions(+) create mode 100644 eww/.config/eww/eww.scss create mode 100644 eww/.config/eww/eww.yuck create mode 100644 eww/.config/eww/scripts/__pycache__/workspace.cpython-310.pyc create mode 100755 eww/.config/eww/scripts/check-all-updates.sh create mode 100755 eww/.config/eww/scripts/cmus.sh create mode 100755 eww/.config/eww/scripts/get_spotify_status.sh create mode 100755 eww/.config/eww/scripts/getram create mode 100755 eww/.config/eww/scripts/getvol create mode 100755 eww/.config/eww/scripts/pavolume.sh create mode 100755 eww/.config/eww/scripts/scroll_spotify_status.sh create mode 100755 eww/.config/eww/scripts/updates.sh create mode 100755 eww/.config/eww/scripts/workspace.py diff --git a/eww/.config/eww/eww.scss b/eww/.config/eww/eww.scss new file mode 100644 index 0000000..855be04 --- /dev/null +++ b/eww/.config/eww/eww.scss @@ -0,0 +1,75 @@ +// Font stuff +$font-size: 16px; + +// Basic color +$bg-color: #181818; +$bg-alt-color: #242424; +$fg-color: #ebdbb2; +$fg-alt-color: #635c4b; +$border-color: #484848; + +// Colors +$black: #121212; +$red: #f7768c; +$green: #9ece6a; +$yellow: #e0af68; +$blue: #aabbff; +$magenta: #ad8ee6; +$cyan: #449dab; +$white: #787c99; + +* { + all: unset; //Unsets everything so you can style everything from scratch + font-family: "Hack Mono"; + // color: $fg-color; +} + +// Bar styles +.time-thing { + opacity: 0.2; +} + +.bar-1, .bar-2 { + background-color: $bg-color; + color: $fg-color; + border-right: solid 1px $border-color; +} + +// Styles on classes (see eww.yuck for more information) + +button.ws { + color: $fg-color; + font-size: $font-size; + margin: 4px; + transition: opacity 300ms; +} + +button.ws:hover { + color: $yellow; + opacity: 1.0; +} + +.logo { + margin-top: $font-size; + font-size: 24px; + opacity: 0.8; + +} + +logo:hover { + color: red; +} + +.workspaces { + // background-color: $black; + // border-radius: $font-size; + // border: 1px solid $border-color; +} + +.ws-active { + font-weight: bold; +} + +.ws-inactive { + opacity: 0.2; +} diff --git a/eww/.config/eww/eww.yuck b/eww/.config/eww/eww.yuck new file mode 100644 index 0000000..6e148f3 --- /dev/null +++ b/eww/.config/eww/eww.yuck @@ -0,0 +1,90 @@ +(defwidget bar [screen] + (centerbox :orientation "v" + (box :class "segment-start" :valign "start" + (logo) + ) + (box :class "segment-mid" :valign "middle" + (workspaces :wsp workspaces-data :ori "v") + ) + (box :class "segment-end" :valign "end" + ;; (music) + ;; (sidestuff) + ;; (volum) + ) + ) +) + +;; Logo +(defwidget logo [] + (button :class "logo" + "Λ" + )) + +;; Workspaces container +(defwidget workspaces [wsp] + (box :space-evenly true :spacing 4 :orientation "v" :class "workspaces" + (for ws in wsp + (workspace :data ws) + ))) + +;; Workspace widget +(defwidget workspace [data] + (button :onclick "wmctrl -s ${data['index']}" + :class {data["iscurrent"] == true ? "ws ws-active" : "ws ws-inactive"} + "${data['name']}" + )) +(deflisten workspaces-data "scripts/workspace.py") + + +(defwidget metric [label value onchange] + (box :orientation "v" + :class "metric" + :space-evenly false + (box :class "label" label) + (scale :min 0 + :max 101 + ;; :orientation "v" + :active {onchange != ""} + :value {value == "" ? "0" : value} + :onchange onchange))) + +(defwidget time [] + (box + "${time}")) +(defpoll time :interval "500ms" + "date '+%H%M.%S %Y-%m-%d'") + +;; WINDOWS +(defwindow bar-1 + :monitor 0 + :windowtype "dock" + :geometry (geometry :x "0%" + :y "0%" + :width "42px" + :height "100%" + :anchor "left center") + :reserve (struts :side "left" :distance "42px") + (bar :screen 1)) + +(defwindow bar-2 + :monitor 1 + :windowtype "dock" + :geometry (geometry :x "0%" + :y "0%" + :width "42px" + :height "100%" + :anchor "left center") + :reserve (struts :side "left" :distance "42px") + (bar :screen 2)) + +(defwindow time-thing + :monitor 0 + :geometry (geometry :x "0%" + :y "0%" + :width "182px" + :height "32px" + :anchor "right top" + ) + :reserve (struts :side "right" :distance "0px" :orientation "h") + (time)) + diff --git a/eww/.config/eww/scripts/__pycache__/workspace.cpython-310.pyc b/eww/.config/eww/scripts/__pycache__/workspace.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3767749442133f46d71c5d494cc7bab7bdc35f6 GIT binary patch literal 1742 zcmZV;U2oh(aCg1-oiBH38byVGD5ij@8zn*FrATR16ru_Qp~^)nvI3Ul-AgX<+3xOM zLr=b^MB)klK!ud!t$%4>dFoG~5)w1MCQXx-c6N4VcfMzePNzj+ef{s>>F=D7fADg7 z0gXI_tqlM{1kFe^J!wSY&N4P|B8L*;L|pL56|VGzC%qmQ4beR1QR5L2zG$5i(K=yK zQ_P6=DT#d95}hNa?o0oKL^G0}wdKr&MjbgTJ0}$6(QduN*;k;MY=zXe(*v0v#l_H+ zLo@P^2dPn6uq;L&{(5&;EQPyz>F(~mYIiwYS*r2lrSLP$_f@H_r=%IGJf$e?%|aag z+kmZa12Cilor~mz!pRo#<}4Dyk66#?lF;2!_~jKtfS9HCz$~Yqn~*982rr59;ds5Y zdQc4Hs?3sXbtNtGUVnd89v`pjRP{@vSC0#Iq{}3gE9Gd!ugI_0sK-hh7pk@6h=bA?!w*puj zS)z5&D^!pK7gp6A>-KXYf3rMK2GaU{oeq_fxk)i(=L>PPwhrMfKq?4bOezMDRt`WW zNSC~%TcM*mz*n;fZU6|mQhj3AIaEI~$2Sh&w2LPwVHTTxCWUwca^^fp3hSDRWJ8xYx#rNHx zwpP}%B26;A4#@QRPRMLS$X+tcOyuiAnfORP*FfcHsddG0P--a4n;`P4Qg14C@m%Es zAI)7=xfS|oIwn7kZ7Yrkg&1atx8wNfFv;F<8sJ`$#<6OGH0x-iEZ-}NOwFTWRB=f= zHiyErsx|9ILEG;soX!w*sEX= zRo(*_M=8|w*~7DC!qeZ{ZZG9|62WunppJM;LP?e1p0z4>VKXX{P--@2uOc~bX&9S-Xy zWhrwJHX;}_rEOhwskR(t+QuL;Fd20{fh-q^NvwbI>QeOUewv$3n+v`UzyXb|I}2UK zS(~+KlP{3uL)wSZ4CA z8?_kq0rHm+ybmDqu~cI;ScOQe%i}GW_W# /dev/null | wc -l ); then + updates_arch=0 +fi + +# if ! updates_aur=$(cower -u 2> /dev/null | wc -l); then +if ! updates_aur=$(trizen -Su --aur --quiet | wc -l); then + updates_aur=0 +fi + +updates=$(("$updates_arch" + "$updates_aur")) + +if [ "$updates" -gt 0 ]; then + echo " $updates" +else + echo "0" +fi diff --git a/eww/.config/eww/scripts/cmus.sh b/eww/.config/eww/scripts/cmus.sh new file mode 100755 index 0000000..7917d4c --- /dev/null +++ b/eww/.config/eww/scripts/cmus.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +prepend_zero () { + seq -f "%02g" $1 $1 +} + +artist=$(echo -n $(cmus-remote -C status | grep "tag artist" | cut -c 12-)) + +if [[ $artist = *[!\ ]* ]]; then + song=$(echo -n $(cmus-remote -C status | grep title | cut -c 11-)) + position=$(cmus-remote -C status | grep position | cut -c 10-) + minutes1=$(prepend_zero $(($position / 60))) + seconds1=$(prepend_zero $(($position % 60))) + duration=$(cmus-remote -C status | grep duration | cut -c 10-) + minutes2=$(prepend_zero $(($duration / 60))) + seconds2=$(prepend_zero $(($duration % 60))) + echo -n "$artist - $song [$minutes1:$seconds1/$minutes2:$seconds2]" +else + echo +fi diff --git a/eww/.config/eww/scripts/get_spotify_status.sh b/eww/.config/eww/scripts/get_spotify_status.sh new file mode 100755 index 0000000..e37c4fa --- /dev/null +++ b/eww/.config/eww/scripts/get_spotify_status.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# The name of polybar bar which houses the main spotify module and the control modules. +PARENT_BAR="now-playing" +PARENT_BAR_PID=$(pgrep -a "polybar" | grep "$PARENT_BAR" | cut -d" " -f1) + +# Set the source audio player here. +# Players supporting the MPRIS spec are supported. +# Examples: spotify, vlc, chrome, mpv and others. +# Use `playerctld` to always detect the latest player. +# See more here: https://github.com/altdesktop/playerctl/#selecting-players-to-control +PLAYER="spotify" + +# Format of the information displayed +# Eg. {{ artist }} - {{ album }} - {{ title }} +# See more attributes here: https://github.com/altdesktop/playerctl/#printing-properties-and-metadata +FORMAT="{{ title }} - {{ artist }}" + +# Sends $2 as message to all polybar PIDs that are part of $1 +update_hooks() { + while IFS= read -r id + do + polybar-msg -p "$id" hook spotify-play-pause $2 1>/dev/null 2>&1 + done < <(echo "$1") +} + +PLAYERCTL_STATUS=$(playerctl --player=$PLAYER status 2>/dev/null) +EXIT_CODE=$? + +if [ $EXIT_CODE -eq 0 ]; then + STATUS=$PLAYERCTL_STATUS +else + STATUS="No player is running" +fi + +if [ "$1" == "--status" ]; then + echo "$STATUS" +else + if [ "$STATUS" = "Stopped" ]; then + echo "No music is playing" + elif [ "$STATUS" = "Paused" ]; then + update_hooks "$PARENT_BAR_PID" 2 + playerctl --player=$PLAYER metadata --format "$FORMAT" + elif [ "$STATUS" = "No player is running" ]; then + echo "$STATUS" + else + update_hooks "$PARENT_BAR_PID" 1 + playerctl --player=$PLAYER metadata --format "$FORMAT" + fi +fi \ No newline at end of file diff --git a/eww/.config/eww/scripts/getram b/eww/.config/eww/scripts/getram new file mode 100755 index 0000000..791a5a5 --- /dev/null +++ b/eww/.config/eww/scripts/getram @@ -0,0 +1,2 @@ +#!/bin/sh +printf "%.0f\n" $(free -m | grep Mem | awk '{print ($3/$2)*100}') diff --git a/eww/.config/eww/scripts/getvol b/eww/.config/eww/scripts/getvol new file mode 100755 index 0000000..6a95077 --- /dev/null +++ b/eww/.config/eww/scripts/getvol @@ -0,0 +1,2 @@ +#!/bin/sh +amixer -D pulse sget Master | grep 'Left:' | awk -F'[][]' '{ print $2 }' | tr -d '%' | head -1 diff --git a/eww/.config/eww/scripts/pavolume.sh b/eww/.config/eww/scripts/pavolume.sh new file mode 100755 index 0000000..777d6d3 --- /dev/null +++ b/eww/.config/eww/scripts/pavolume.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env bash + +# finds the active sink for pulse audio and increments the volume. useful when you have multiple audio outputs and have a key bound to vol-up and down + +osd='no' +inc='2' +capvol='no' +maxvol='100' +autosync='yes' + +# Muted status +# yes: muted +# no : not muted +curStatus="no" +active_sink="" +limit=$((100 - inc)) +maxlimit=$((maxvol - inc)) + +reloadSink() { + active_sink=$(pacmd list-sinks | awk '/* index:/{print $3}') +} + +function volUp { + + getCurVol + + if [ "$capvol" = 'yes' ] + then + if [ "$curVol" -le 100 ] && [ "$curVol" -ge "$limit" ] + then + pactl set-sink-volume "$active_sink" -- 100% + elif [ "$curVol" -lt "$limit" ] + then + pactl set-sink-volume "$active_sink" -- "+$inc%" + fi + elif [ "$curVol" -le "$maxvol" ] && [ "$curVol" -ge "$maxlimit" ] + then + pactl set-sink-volume "$active_sink" "$maxvol%" + elif [ "$curVol" -lt "$maxlimit" ] + then + pactl set-sink-volume "$active_sink" "+$inc%" + fi + + getCurVol + + if [ ${osd} = 'yes' ] + then + qdbus org.kde.kded /modules/kosd showVolume "$curVol" 0 + fi + + if [ ${autosync} = 'yes' ] + then + volSync + fi +} + +function volDown { + + pactl set-sink-volume "$active_sink" "-$inc%" + getCurVol + + if [ ${osd} = 'yes' ] + then + qdbus org.kde.kded /modules/kosd showVolume "$curVol" 0 + fi + + if [ ${autosync} = 'yes' ] + then + volSync + fi + +} + +function getSinkInputs { + input_array=$(pacmd list-sink-inputs | grep -B 4 "sink: $1 " | awk '/index:/{print $2}') +} + +function volSync { + getSinkInputs "$active_sink" + getCurVol + + for each in $input_array + do + pactl set-sink-input-volume "$each" "$curVol%" + done +} + +function getCurVol { + curVol=$(pacmd list-sinks | grep -A 15 "index: $active_sink$" | grep 'volume:' | grep -E -v 'base volume:' | awk -F : '{print $3}' | grep -o -P '.{0,3}%'| sed s/.$// | tr -d ' ') +} + +function volMute { + case "$1" in + mute) + pactl set-sink-mute "$active_sink" 1 + curVol=0 + status=1 + ;; + unmute) + pactl set-sink-mute "$active_sink" 0 + getCurVol + status=0 + ;; + esac + + if [ ${osd} = 'yes' ] + then + qdbus org.kde.kded /modules/kosd showVolume ${curVol} ${status} + fi + +} + +function volMuteStatus { + curStatus=$(pacmd list-sinks | grep -A 15 "index: $active_sink$" | awk '/muted/{ print $2}') +} + +# Prints output for bar +# Listens for events for fast update speed +function listen { + firstrun=0 + + pactl subscribe 2>/dev/null | { + while true; do + { + # If this is the first time just continue + # and print the current state + # Otherwise wait for events + # This is to prevent the module being empty until + # an event occurs + if [ $firstrun -eq 0 ] + then + firstrun=1 + else + read -r event || break + if ! echo "$event" | grep -e "on card" -e "on sink" + then + # Avoid double events + continue + fi + fi + } &>/dev/null + output + done + } +} + +function output() { + reloadSink + getCurVol + volMuteStatus + if [ "${curStatus}" = 'yes' ] + then + echo " ---%" + else + echo " $curVol%" + fi +} #}}} + +reloadSink +case "$1" in + --up) + volUp + ;; + --down) + volDown + ;; + --togmute) + volMuteStatus + if [ "$curStatus" = 'yes' ] + then + volMute unmute + else + volMute mute + fi + ;; + --mute) + volMute mute + ;; + --unmute) + volMute unmute + ;; + --sync) + volSync + ;; + --listen) + # Listen for changes and immediately create new output for the bar + # This is faster than having the script on an interval + listen + ;; + *) + # By default print output for bar + output + ;; +esac diff --git a/eww/.config/eww/scripts/scroll_spotify_status.sh b/eww/.config/eww/scripts/scroll_spotify_status.sh new file mode 100755 index 0000000..1e154d7 --- /dev/null +++ b/eww/.config/eww/scripts/scroll_spotify_status.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# see man zscroll for documentation of the following parameters +zscroll -l 30 \ + --delay 0.1 \ + --scroll-padding "  " \ + --match-command "$HOME/.config/polybar/scripts/get_spotify_status.sh --status" \ + --match-text "Playing" "--scroll 1" \ + --match-text "Paused" "--scroll 0" \ + --update-check true "$HOME/.config/polybar/scripts/get_spotify_status.sh" & + +wait diff --git a/eww/.config/eww/scripts/updates.sh b/eww/.config/eww/scripts/updates.sh new file mode 100755 index 0000000..cea1e8d --- /dev/null +++ b/eww/.config/eww/scripts/updates.sh @@ -0,0 +1,20 @@ +#!/bin/sh +#source https://github.com/x70b1/polybar-scripts + + +if ! updates_arch=$(checkupdates 2> /dev/null | wc -l ); then + updates_arch=0 +fi + +# if ! updates_aur=$(cower -u 2> /dev/null | wc -l); then +if ! updates_aur=$(yay -Su --aur --quiet | wc -l); then + updates_aur=0 +fi + +updates=$(("$updates_arch" + "$updates_aur")) + +if [ "$updates" -gt 0 ]; then + echo " $updates" +else + echo "0" +fi diff --git a/eww/.config/eww/scripts/workspace.py b/eww/.config/eww/scripts/workspace.py new file mode 100755 index 0000000..cd0cbc4 --- /dev/null +++ b/eww/.config/eww/scripts/workspace.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +""" +Script to get current workspaces and related +data using wmctrl. +""" + +import re +import sys +import json +from subprocess import check_output + +# Config +HIDE_EMPTY_WS = True # Exclude empty workspaces +OVERIDE_ALL_NAMES = False +OVERIDE_ALL_NAME = "" +NAME_MAPS = { + # 0: "", + # 1: "" +} + + +# NOTE: DO NOT TOUCH +WMCTRL_SCRIPT = "wmctrl -d" +PARSE_REGEX = r"^(\d+)\s+(\*|\-).+\s+(\w+)$" + +NONEMPTY_REGEX = r"^\w+\s+(\w+|\d+).+$" +WMCTRL_NONEMPTY_SCRIPT = "wmctrl -l" + + +def parse_groups(grps: tuple) -> tuple: + """ + Parses the given regex groups + """ + return int(grps[0]), grps[2], grps[1] == "*" + + +class Workspace: + """ + Class for a workspace + """ + + def __init__(self, index: int, name: str, iscurrent: bool, isempty: bool): + self.index = index + if OVERIDE_ALL_NAMES: + self.name = OVERIDE_ALL_NAME + elif index in NAME_MAPS.keys(): + self.name = NAME_MAPS[index] + else: + self.name = name + self.iscurrent = iscurrent + self.isempty = isempty + + def to_json(self): + """ + Converts the given object to json + """ + return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True) + + +def parse_workspaces(): + """ + Function to get all the workspaces + """ + + inp = check_output(WMCTRL_SCRIPT.split(" ")) + inp = inp.decode("utf-8") + + nonempty = check_output(WMCTRL_NONEMPTY_SCRIPT.split(" ")) + nonempty = nonempty.decode("utf-8") + + nonempty_workspaces = re.findall(NONEMPTY_REGEX, + nonempty, + flags=re.MULTILINE) + nonempty_workspaces = list(map(int, nonempty_workspaces)) + + out = [] + + for line in inp.splitlines(): + matches = re.search(PARSE_REGEX, line) + grps = matches.groups() + data = parse_groups(grps) + workspace = Workspace(*data, data[0] not in nonempty_workspaces) + + out.append(workspace) + + return out + + +if __name__ == "__main__": + args = sys.argv + + # NOTE: use deflisten + LAST_STRING = "" + while True: + workspaces = parse_workspaces() + workspaces = list(filter(lambda ws: + (ws.iscurrent) + or (not ws.isempty) + or (not HIDE_EMPTY_WS), + workspaces)) + + json_str = json.dumps(workspaces, default=lambda ws: ws.to_json()) + + if json_str != LAST_STRING: + print(f"{json_str}", flush=True) # Output to eww + + LAST_STRING = json_str