; sway shell popups ; ============================================================================= ; variables ; ============================================================================= (defpoll sys :interval "5s" :initial '{"cpu":0,"ram_percent":0,"ram_used":"0Gi","ram_total":"0Gi","temp":0,"disk_percent":0,"disk_used":"0","disk_total":"0","swap":"0/0","load":"0 0 0","uptime":""}' "~/.config/eww/scripts/system.sh") (defpoll bat :interval "30s" :initial '{"capacity":0,"status":"Unknown","power":"0","time":"","cycles":0,"profile":"unknown"}' "~/.config/eww/scripts/battery.sh") (defpoll vol :interval "5s" :initial '{"volume":0,"muted":false,"mic_volume":0,"mic_muted":false,"brightness":0,"sinks":[],"sources":[],"sink_count":0,"source_count":0}' "~/.config/eww/scripts/volume.sh") (defpoll bt :interval "15s" :initial '{"powered":false,"count":0,"devices":[]}' "~/.config/eww/scripts/bluetooth.sh") (defpoll net :interval "10s" :initial '{"type":"none","iface":"none","ip":"none","gateway":"none","ssid":"","signal":0,"conn_name":"","count":0,"networks":[],"unknown_count":0,"unknown":[]}' "~/.config/eww/scripts/network.sh") (defpoll vpn_data :interval "15s" :initial '{"tailscale":{"running":false,"ip":"","hostname":"","login":"","exit_nodes":[],"exit_count":0,"peers":[],"peer_count":0},"wireguard":{"active":false,"iface":""}}' "~/.config/eww/scripts/vpn.sh") (defpoll kbd :interval "10s" :initial '{"current":"unknown","layouts":[],"layout_count":0,"keyboards":[],"kb_count":0}' "~/.config/eww/scripts/keyboard.sh") (defpoll media :interval "5s" :initial '{"count":0,"players":[]}' "~/.config/eww/scripts/media.sh") ; ============================================================================= ; media popup ; ============================================================================= (defwidget media-widget [] (box :class "popup" :orientation "v" :space-evenly false :spacing 8 (label :class "title" :text "media" :halign "start") (box :visible {media.count == 0} (label :class "empty" :text "no active players")) (box :orientation "v" :space-evenly false :spacing 4 (for player in {media.players} (box :class "device-row" :orientation "v" :space-evenly false :spacing 2 (box :orientation "h" :space-evenly false :spacing 8 (label :class "label ${player.status == 'Playing' ? 'playing' : ''}" :text {player.display} :halign "start" :hexpand true) (button :class "toggle-btn ${player.status == 'Playing' ? 'active' : ''}" :onclick "~/.config/eww/scripts/media.sh play-pause '${player.name}'" {player.status == "Playing" ? "pause" : "play"}) (button :class "close-btn" :onclick "~/.config/eww/scripts/media.sh prev '${player.name}'" "prev") (button :class "close-btn" :onclick "~/.config/eww/scripts/media.sh next '${player.name}'" "next")) (label :class "value" :text "${player.artist}${player.artist != '' ? ' - ' : ''}${player.title}" :halign "start" :limit-width 45)))))) ; ============================================================================= ; system popup ; ============================================================================= (defwidget system-widget [] (box :class "popup" :orientation "v" :space-evenly false :spacing 8 (label :class "title" :text "system" :halign "start") ; cpu (box :class "row" :orientation "v" :space-evenly false :spacing 2 (box :orientation "h" (label :class "label" :text "cpu" :halign "start" :hexpand true) (label :class "value" :text "${sys.cpu}%")) (progress :class "bar" :value {sys.cpu})) ; ram (box :class "row" :orientation "v" :space-evenly false :spacing 2 (box :orientation "h" (label :class "label" :text "ram" :halign "start" :hexpand true) (label :class "value" :text "${sys.ram_used}/${sys.ram_total}")) (progress :class "bar" :value {sys.ram_percent})) ; temp (box :class "row" :orientation "h" (label :class "label" :text "temp" :halign "start" :hexpand true) (label :class "value" :text "${sys.temp}°")) ; disk (box :class "row" :orientation "v" :space-evenly false :spacing 2 (box :orientation "h" (label :class "label" :text "disk" :halign "start" :hexpand true) (label :class "value" :text "${sys.disk_used}/${sys.disk_total}")) (progress :class "bar" :value {sys.disk_percent})) ; details (box :class "details" :orientation "v" :space-evenly false :spacing 2 (label :class "detail" :text "swap ${sys.swap}" :halign "start") (label :class "detail" :text "load ${sys.load}" :halign "start") (label :class "detail" :text "up ${sys.uptime}" :halign "start")))) ; ============================================================================= ; battery popup ; ============================================================================= (defwidget battery-widget [] (box :class "popup" :orientation "v" :space-evenly false :spacing 8 (label :class "title" :text "battery" :halign "start") ; capacity bar (box :class "row" :orientation "v" :space-evenly false :spacing 2 (box :orientation "h" (label :class "label" :text {bat.status} :halign "start" :hexpand true) (label :class "value" :text "${bat.capacity}%")) (progress :class "bar ${bat.capacity < 15 ? 'critical' : bat.capacity < 30 ? 'warning' : ''}" :value {bat.capacity})) ; power + time (box :class "row" :orientation "h" (label :class "label" :text "power" :halign "start" :hexpand true) (label :class "value" :text "${bat.power}W")) (box :class "row" :orientation "h" :visible {bat.time != ""} (label :class "label" :text "remaining" :halign "start" :hexpand true) (label :class "value" :text {bat.time})) (box :class "row" :orientation "h" (label :class "label" :text "cycles" :halign "start" :hexpand true) (label :class "value" :text {bat.cycles})) ; power profile selector (box :class "separator") (label :class "title" :text "profile" :halign "start") (box :class "profiles" :orientation "h" :space-evenly true :spacing 4 (button :class "profile-btn ${bat.profile == 'power-saver' ? 'active' : ''}" :onclick "~/.config/eww/scripts/battery.sh set-profile power-saver" "saver") (button :class "profile-btn ${bat.profile == 'balanced' ? 'active' : ''}" :onclick "~/.config/eww/scripts/battery.sh set-profile balanced" "balanced") (button :class "profile-btn ${bat.profile == 'performance' ? 'active' : ''}" :onclick "~/.config/eww/scripts/battery.sh set-profile performance" "perform")))) ; ============================================================================= ; volume popup ; ============================================================================= (defwidget volume-widget [] (box :class "popup" :orientation "v" :space-evenly false :spacing 8 ; output section (box :orientation "v" :space-evenly false :spacing 4 (label :class "title" :text "output" :halign "start") (box :class "row slider-row" :orientation "h" :space-evenly false :spacing 8 (button :class "toggle-btn ${vol.muted ? 'active' : ''}" :onclick "~/.config/eww/scripts/volume.sh toggle-mute" {vol.muted ? "muted" : "vol"}) (scale :class "slider" :min 0 :max 100 :value {vol.volume} :onchange "pamixer --set-volume {}" :hexpand true) (label :class "value" :text "${vol.volume}%")) (for sink in {vol.sinks} (button :class "device-btn ${sink.active ? 'active' : ''}" :onclick "~/.config/eww/scripts/volume.sh set-sink '${sink.sink_name}'" (label :text {sink.name} :halign "start")))) ; input section (box :class "separator") (box :orientation "v" :space-evenly false :spacing 4 (label :class "title" :text "input" :halign "start") (box :class "row slider-row" :orientation "h" :space-evenly false :spacing 8 (button :class "toggle-btn ${vol.mic_muted ? 'active' : ''}" :onclick "~/.config/eww/scripts/volume.sh toggle-mic" {vol.mic_muted ? "muted" : "mic"}) (scale :class "slider" :min 0 :max 100 :value {vol.mic_volume} :onchange "pamixer --default-source --set-volume {}" :hexpand true) (label :class "value" :text "${vol.mic_volume}%")) (for source in {vol.sources} (button :class "device-btn ${source.active ? 'active' : ''}" :onclick "~/.config/eww/scripts/volume.sh set-source '${source.source_name}'" (label :text {source.name} :halign "start")))) ; brightness section (box :class "separator") (label :class "title" :text "brightness" :halign "start") (box :class "row slider-row" :orientation "h" :space-evenly false :spacing 8 (label :class "label" :text "bl") (scale :class "slider" :min 0 :max 100 :value {vol.brightness} :onchange "brightnessctl set {}%" :hexpand true) (label :class "value" :text "${vol.brightness}%")))) ; ============================================================================= ; bluetooth popup ; ============================================================================= (defwidget bluetooth-widget [] (box :class "popup" :orientation "v" :space-evenly false :spacing 8 (box :class "row" :orientation "h" (label :class "title" :text "bluetooth" :halign "start" :hexpand true) (button :class "toggle-btn ${bt.powered ? 'active' : ''}" :onclick "~/.config/eww/scripts/bluetooth.sh toggle-power" {bt.powered ? "on" : "off"})) (box :visible {bt.powered} :orientation "v" :space-evenly false :spacing 4 (for device in {bt.devices} (box :class "device-row" :orientation "h" :space-evenly false :spacing 8 (label :class "label" :text {device.name} :halign "start" :hexpand true) (label :class "value dim" :visible {device.battery >= 0} :text "${device.battery}%") (button :class "close-btn" :onclick "~/.config/eww/scripts/bluetooth.sh disconnect '${device.mac}'" "x"))) (label :visible {bt.count == 0} :class "empty" :text "no devices connected")))) ; ============================================================================= ; network popup ; ============================================================================= (defwidget network-widget [] (box :class "popup" :orientation "v" :space-evenly false :spacing 8 (label :class "title" :text "network" :halign "start") ; connection info (box :class "row" :orientation "h" (label :class "label" :text "interface" :halign "start" :hexpand true) (label :class "value" :text {net.iface})) (box :class "row" :orientation "h" (label :class "label" :text "ip" :halign "start" :hexpand true) (label :class "value" :text {net.ip})) (box :class "row" :orientation "h" (label :class "label" :text "gateway" :halign "start" :hexpand true) (label :class "value" :text {net.gateway})) (box :class "row" :orientation "h" :visible {net.type == "wifi"} (label :class "label" :text "ssid" :halign "start" :hexpand true) (label :class "value" :text "${net.ssid} ${net.signal}%")) ; saved wifi networks nearby (box :visible {net.count > 0} :orientation "v" :space-evenly false :spacing 4 (box :class "separator") (label :class "title" :text "saved" :halign "start") (box :orientation "v" :space-evenly false :spacing 0 (for network in {net.networks} (button :class "device-btn ${network.active ? 'active' : ''}" :onclick {network.active ? "~/.config/eww/scripts/network.sh disconnect '${network.ssid}'" : "~/.config/eww/scripts/network.sh connect '${network.ssid}'"} (box :orientation "h" :space-evenly false (label :class "label" :text {network.ssid} :halign "start" :hexpand true) (label :class "value dim" :text "${network.signal}%")))))) ; unknown wifi networks nearby (box :visible {net.unknown_count > 0} :orientation "v" :space-evenly false :spacing 4 (box :class "separator") (label :class "title" :text "nearby" :halign "start") (box :orientation "v" :space-evenly false :spacing 0 (for network in {net.unknown} (button :class "device-btn" :onclick "~/.config/eww/scripts/network.sh connect-new '${network.ssid}'" (box :orientation "h" :space-evenly false (label :class "label" :text {network.ssid} :halign "start" :hexpand true) (label :class "value dim" :text "${network.signal}%")))))))) ; ============================================================================= ; vpn popup ; ============================================================================= (defwidget vpn-widget [] (box :class "popup" :orientation "v" :space-evenly false :spacing 8 ; tailscale (box :class "row" :orientation "h" (label :class "title" :text "tailscale" :halign "start" :hexpand true) (button :class "toggle-btn ${vpn_data.tailscale.running ? 'active' : ''}" :onclick "~/.config/eww/scripts/vpn.sh ${vpn_data.tailscale.running ? 'ts-down' : 'ts-up'}" {vpn_data.tailscale.running ? "on" : "off"})) (box :visible {vpn_data.tailscale.running} :orientation "v" :space-evenly false :spacing 4 (box :class "row" :orientation "h" (label :class "label" :text "ip" :halign "start" :hexpand true) (label :class "value" :text {vpn_data.tailscale.ip})) (box :class "row" :orientation "h" (label :class "label" :text "host" :halign "start" :hexpand true) (label :class "value" :text {vpn_data.tailscale.hostname})) (box :class "row" :orientation "h" (label :class "label" :text "network" :halign "start" :hexpand true) (label :class "value" :text {vpn_data.tailscale.login})) ; exit nodes (box :visible {vpn_data.tailscale.exit_count > 0} :orientation "v" :space-evenly false :spacing 4 (box :class "separator") (label :class "subtitle" :text "exit node" :halign "start") (box :orientation "v" :space-evenly false :spacing 0 (for node in {vpn_data.tailscale.exit_nodes} (button :class "device-btn ${node.active ? 'active' : ''}" :onclick "~/.config/eww/scripts/vpn.sh ts-exit '${node.active ? '' : node.ip}'" (label :text {node.name} :halign "start"))))) ; peers (box :orientation "v" :space-evenly false :spacing 4 (box :class "separator") (label :class "subtitle" :text "devices" :halign "start") (for peer in {vpn_data.tailscale.peers} (box :class "device-row" :orientation "h" :space-evenly false :spacing 8 (label :class "indicator ${peer.online ? 'online' : 'offline'}" :text {peer.online ? "●" : "○"}) (label :class "label" :text {peer.name} :halign "start" :hexpand true) (label :class "value dim" :text {peer.ip}))))) ; wireguard (box :class "separator") (box :class "row" :orientation "h" (label :class "title" :text "wireguard" :halign "start" :hexpand true) (button :class "toggle-btn ${vpn_data.wireguard.active ? 'active' : ''}" :onclick "~/.config/eww/scripts/vpn.sh ${vpn_data.wireguard.active ? 'wg-down' : 'wg-up'}" {vpn_data.wireguard.active ? "on" : "off"})))) ; ============================================================================= ; keyboard popup ; ============================================================================= (defwidget keyboard-widget [] (box :class "popup" :orientation "v" :space-evenly false :spacing 8 (label :class "title" :text "keyboard" :halign "start") ; layout selector (label :class "subtitle" :text "layout" :halign "start") (for layout in {kbd.layouts} (button :class "device-btn ${layout == kbd.current ? 'active' : ''}" :onclick "~/.config/eww/scripts/keyboard.sh switch" (label :text {layout} :halign "start"))) ; keyboard devices (box :visible {kbd.kb_count > 1} :orientation "v" :space-evenly false :spacing 4 (box :class "separator") (label :class "subtitle" :text "devices" :halign "start") (for kb in {kbd.keyboards} (box :class "device-row" :orientation "h" :space-evenly false :spacing 8 (label :class "label" :text {kb.name} :halign "start" :hexpand true) (label :class "value dim" :text {kb.layout})))))) ; ============================================================================= ; backdrop (click-away to close) ; ============================================================================= (defwidget backdrop-widget [] (eventbox :onclick "~/.config/eww/scripts/popup.sh close-all" (box :class "backdrop" :hexpand true :vexpand true))) (defwindow backdrop :monitor 0 :geometry (geometry :x "0px" :y "0px" :width "100%" :height "100%" :anchor "top left") :stacking "overlay" :exclusive false :focusable true (backdrop-widget)) ; ============================================================================= ; windows ; ============================================================================= (defwindow system-popup :monitor 0 :geometry (geometry :x "380px" :y "3px" :width "300px" :anchor "top right") :stacking "overlay" :exclusive false :focusable false (system-widget)) (defwindow battery-popup :monitor 0 :geometry (geometry :x "260px" :y "3px" :width "300px" :anchor "top right") :stacking "overlay" :exclusive false :focusable false (battery-widget)) (defwindow volume-popup :monitor 0 :geometry (geometry :x "140px" :y "3px" :width "320px" :anchor "top right") :stacking "overlay" :exclusive false :focusable false (volume-widget)) (defwindow bluetooth-popup :monitor 0 :geometry (geometry :x "500px" :y "3px" :width "280px" :anchor "top right") :stacking "overlay" :exclusive false :focusable false (bluetooth-widget)) (defwindow network-popup :monitor 0 :geometry (geometry :x "560px" :y "3px" :width "320px" :anchor "top right") :stacking "overlay" :exclusive false :focusable false (network-widget)) (defwindow vpn-popup :monitor 0 :geometry (geometry :x "480px" :y "3px" :width "320px" :anchor "top right") :stacking "overlay" :exclusive false :focusable false (vpn-widget)) (defwindow keyboard-popup :monitor 0 :geometry (geometry :x "50px" :y "3px" :width "280px" :anchor "top right") :stacking "overlay" :exclusive false :focusable false (keyboard-widget)) (defwindow media-popup :monitor 0 :geometry (geometry :x "700px" :y "3px" :width "350px" :anchor "top right") :stacking "overlay" :exclusive false :focusable false (media-widget))