diff --git a/README-Wayland.org b/README-Wayland.org index 876bff3..e26602b 100644 --- a/README-Wayland.org +++ b/README-Wayland.org @@ -22,8 +22,7 @@ recommended. * Status Bar and Tray -- ~waybar~: Status bar, use ~waybar-hyprland-git~ AUR repo to enable clicking! -- ~eww-wayland~: Another status bar, requires ~socat~ to listen for hyprland events. +- ~eww-wayland~: Requires ~socat~ to listen for hyprland events. * Sway @@ -57,7 +56,6 @@ This is another choice of a compositor. Note: Setup does not work with NVIDIA GPU without some tweaks. - [[https://wiki.archlinux.org/title/Hyprland][hyprland]]: window manager - Until [[https://github.com/elkowar/eww/issues/111][tray support]] has been added to ~eww~ in a stable manner, tray will be handled with waybar. - ~hyprpaper~: Wallpaper engine The command to set a wallpaper: @@ -79,12 +77,14 @@ convert $IN \ #+end_src - ~swaync~: Notification server - ~wofi~: finding programs, drop in replacement for ~rofi~ -- ~grimblast~: Screenshot engine - ~dolphin~: File explorer - ~swaylock-effects~: A simple lockscreen - ~wl-clipboard~: Provides copying - ~blueman~: Bluetooth connector +- ~grim~: Screenshot engine +- ~flameshot~: Screenshot utility; On Arch Linux, install ~flameshot-git~. + ** Configuration - ~lxappearance~: Used to configure GTK3 themes diff --git a/eww/bar/eww.scss b/eww/bar/eww.scss index 53d49a1..a0b7101 100644 --- a/eww/bar/eww.scss +++ b/eww/bar/eww.scss @@ -12,32 +12,76 @@ $workspace_hover: #2E5DFF; $widget_bg: rgba(40, 40, 40, 0.5); $weather: rgba(180, 220, 235, 0.8); $weather_end: rgba(171, 233, 179, 0.8); -$clock: rgba(171, 233, 179, 1.0); -$media: rgba(224, 232, 224, 0.7); +$trough: rgba(0, 0, 0, 0.5); -$tray_background: rgba(204, 204, 204, 0.1); +$media-progress-bg: rgba(224, 232, 224, 0.1); +$media-paused-progress-bg: rgba(224, 200, 200, 0.1); +$media: rgba(224, 232, 224, 0.7); +$media-paused: rgba(224, 200, 200, 0.7); +$media-stopped: rgba(200, 200, 200, 0.5); + +// Dims the desktop background so status icons can be seen against darker wallpapers +$status_bg: rgba(0, 0, 0, 0.3); +$tray-bg: rgba(204, 204, 204, 0.3); $tray: #c9cbff; $keyboard: #f2cdcd; -$language: #e8a2af; $idle_inhibitor: #f28fad; -$audio: #fae3b0; -$backlight: #f8bd96; -$bluetooth: #caa9c7; -$network: #bd93f9; +$volume: #fae3b0; +$microphone: #e8a2af; +$network: #f8bd96; +$backlight: #bd93f9; + +// Unused in favour of bluetooth widget +$bluetooth: #88bbeb; $cpu: #96cdfb; -$memory: #88bbeb; -$temperature: #ddb6f2; -$temperature_critical: #ff6666; -$battery: #b6b2b3; +$cpu-bg: rgba(150, 205, 251, 0.3); +// previously bluetooth colour +$memory: #caa9c7; +$memory-bg: rgba(202, 169, 199, 0.3); +$temperature-bg: rgba(180, 180, 180, 0.5); +$temperature: #b6b2b3; +$temperature-critical: #ff6666; +$battery: #ddb6f2; +$clock: rgba(171, 233, 179, 1.0); -* { all: unset; } +// Styles all scales +progressbar trough { + all: unset; + background-color: $trough; + border-radius: 5px; + min-height: 80px; + min-width: 2px; + //margin: .3rem 0 .3rem 0; +} +trough progress { + all: unset; + background-color: #00ff00; // Diagnostics colour + border-radius: 5px; + min-width: 2px; +} +scale trough { + all: unset; + background-color: $trough; + border-radius: 5px; + min-height: 80px; + min-width: 2px; +} +trough highlight { + all: unset; + background-color: #ff0000; // Diagnostics colour + border-radius: 5px; +} +trough slider { + background-color: transparent; + border-width: 0px; + border-radius: 10px; +} -.bar { - //background-color: transparent; - margin-left: 5px; - font-size: 15px; +.vbar { + background-color: transparent; + font-size: 20px; font-family: monospace; } @@ -46,13 +90,16 @@ $battery: #b6b2b3; } .launcher { + all: unset; font-size: 40px; - margin: -7px -5px 15px -5px; + margin: -2px -5px 5px 0px; } box .workspaces { + all: unset; border-radius: 10px; button { + all: unset; font-size: 30px; padding-left: 2px; margin: -5px -5px -5px -5px; @@ -75,6 +122,11 @@ box .workspaces { } } +box .status { + background-color: $status_bg; + border-radius: 5px; +} + box .weather { color: $weather; margin-left: 2px; @@ -105,63 +157,112 @@ box .weather { color: mix($weather_end, $weather, 100%); } } -box .clock { - background-color: $widget_bg; - border-radius: 5; - color: $clock; - margin-bottom: 30px; - padding: 2pt 2pt 2pt 2pt; +.volume { + background-color: transparent; + color: $volume; + border-left: 2px solid $volume; + margin-bottom: 1px; + margin-top: 1px; + highlight { + background-color: $volume; + } +} +.microphone { + background-color: transparent; + color: $microphone; + border-left: 2px solid $microphone; + margin-bottom: 1px; + margin-top: 1px; + highlight { + background-color: $microphone; + } } .media { font-family: "Noto Serif"; - padding-left: 5px; - padding-right: 5px; + min-height: 15px; + min-width: 15px; + font-size: 15px; color: $media; border: none; + + .media-text-playing { + padding-left: 10px; + } + .media-text-paused { + padding-left: 10px; + color: $media-paused; + } + .media-text-stopped { + padding-left: 10px; + color: $media-stopped; + } + .media-playing { + background-color: $media-progress-bg; + } + .media-paused { + background-color: $media-paused-progress-bg; + color: $media-paused; + } + .media-stopped { + background-color: $media-paused-progress-bg; + color: $media-stopped; + } } -.status { - font-family: monospace; +box .temperature { + color: $temperature; + border-left: 2px solid $temperature-bg; + margin-bottom: 1px; + margin-top: 1px; + +} +.temperature-icon { + padding-left: 5px; + font-size: 20px; + color: mix($temperature, transparent, 70%); +} +.temperature-progress-cpu trough progress { + background-color: mix($cpu, $temperature, 50%); +} +.temperature-progress-gpu trough progress { + background-color: $temperature; +} +.temperature-progress-critical trough progress { + background-color: $temperature-critical; } -// Styles on classes (see eww.yuck for more information) - -.status slider { - all: unset; - color: #ffd5cd; +box .cpu { + .progress { + background-color: $cpu-bg; + } + color: $cpu; + border-left: 2px solid $cpu; + margin-bottom: 1px; + margin-top: 1px; } - -.metric scale trough highlight { - all: unset; - background-color: #D35D6E; - color: #000000; - border-radius: 10px; +box .memory { + .progress { + background-color: $memory-bg; + } + color: $memory; + border-left: 2px solid $memory; + margin-bottom: 1px; + margin-top: 1px; } -.metric scale trough { - all: unset; - background-color: #4e4e4e; - border-radius: 50px; - min-height: 3px; - min-width: 50px; - margin-left: 10px; - margin-right: 20px; +box .clock { + background-color: transparent; + color: $clock; + margin-top: 1px; + font-family: Ariel; + border-left: 2px solid $clock; + .icon { + color: mix($clock, transparent, 50%); + } } -.metric scale trough highlight { - all: unset; - background-color: #D35D6E; - color: #000000; - border-radius: 10px; -} -.metric scale trough { - all: unset; - background-color: #4e4e4e; - border-radius: 50px; - min-height: 3px; - min-width: 50px; - margin-left: 10px; - margin-right: 20px; -} -.label-ram { - font-size: large; +.systray { + //background-color: $tray_bg; + color: $tray; + border-left: 2px dotted $tray; + border-bottom: 2px dotted $tray-bg; } diff --git a/eww/bar/eww.yuck b/eww/bar/eww.yuck index 2604de7..be1ffa0 100644 --- a/eww/bar/eww.yuck +++ b/eww/bar/eww.yuck @@ -1,95 +1,257 @@ -(defvar eww "eww --config $HOME/.config/eww/bar") +(defvar amixer "amixer -D pulse") +(defvar temperature-monitor "psensor") -(defwindow bar +(defwindow vbar :exclusive true :monitor 0 :windowtype "dock" :geometry (geometry :x "0%" :y "0%" - :width "20px" - :height "100%" + :width "25px" + :height "99%" :anchor "center left" ) :reserve (struts :side "left" :distance "20px") - (widget_bar)) -(defwidget widget_bar [] - (centerbox :orientation "v" - (box :orientation "v" :space-evenly false :valign "start" - (box :class "launcher" :valign "start" "☯") - (widget_workspaces) + (centerbox + :orientation "v" + (box + :orientation "v" :space-evenly false :valign "start" + (label + :class "launcher" + :valign "start" + :width "20px" :height "20px" + :unindent true + :tooltip active-window-title + :text "☯") + (widget-workspaces) + ) + (widget-media) + (box + :class "status" + :orientation "v" :space-evenly false :valign "end" + (widget-tray) + (widget-volume) + (widget-microphone) + (widget-temperature) + (widget-cpu) + (widget-memory) + (widget-clock) ) - (widget_weather :orientation "v") - (widget_clock) - ;(media) - ;(widget_status) )) -(defwidget widget_workspaces [] +(defwidget widget-workspaces [] (box :class "workspaces" :orientation "v" :space-evenly true - :valign "start" :spacing 10 + :spacing 10 + :valign "start" :halign "center" (for workspace in workspaces (button :class "${workspace.class}" - :onclick "scripts/workspace.sh ${workspace.id}" + :onclick "scripts/compositor-control set-workspace ${workspace.id}" "${workspace.text}")) )) (deflisten workspaces :initial "[]" - "scripts/get-workspaces") + "scripts/compositor-control workspaces") +(deflisten active-window-title :initial "" + "scripts/compositor-control active-title") -; Weather - -(defwidget widget_weather [orientation] +(defwidget widget-media [] (box - :class "weather" - :orientation orientation + :class "media" + :orientation "v" :space-evenly false - :valign "start" - :halign "center" - :spacing 10 - (button :onclick "scripts/popup weather" "W") + :valign "end" + :tooltip "${media-status == 'Paused' ? '' : media-status == 'Playing' ? '' : ''} ${media-position-text}" + (eventbox + :onclick "playerctl play-pause" + (circular-progress + :class { media-status == "Paused" ? "media-paused" : media-status == "Stopped" ? "media-stopped" : "media-playing" } + :width 20 + :height 20 + :thickness 5 + :value {100.0 * media-position / (media-length / 1000000.0)} + :visible {media-current != "" && media-status != "Stopped"} + )) + (label + :class { media-status == "Paused" ? "media-text-paused" : media-status == "Stopped" ? "media-text-stopped" : "media-text-playing" } + :angle 270 + :xalign 0.5 + :yalign 0.5 + :justify "center" + :limit-width 120 + :text "『${media-current}』" + ))) + + +(deflisten media-current :initial "" + "playerctl --follow metadata --format '{{ artist }} / {{album}} / {{ title }}' || true") +(deflisten media-position-text :initial "" + "playerctl --follow metadata --format '{{duration(position)}} / {{duration(mpris:length)}}' || true") +(defpoll media-position + :interval "1s" :run-while {media-current != ""} + "playerctl position") +(deflisten media-length :initial 1 + "playerctl --follow metadata mpris:length") +(deflisten media-status :initial "Stopped" + "playerctl --follow status") + +(defwidget widget-volume [] + (eventbox + :onhover "${EWW_CMD} update show-volume=true" + :onhoverlost "${EWW_CMD} update show-volume=false" + :onclick "${amixer} sset Master toggle" + (box + :class "volume" + :orientation "v" + :space-evenly "false" + :spacing "2" + :tooltip "Volume: ${current-volume}% [${current-volume-state}]" + (revealer :transition "slideup" :reveal show-volume + (scale + :class "scale" + :value current-volume + :orientation "v" + :flipped true + :marks true + :max 101 + :min 0 + :onchange "${amixer} sset Master {}%" )) + (label + :class "icon" + :width 25 :height 20 + :xalign 0.5 :yalign 0.5 + :noindent true + :text { current-volume-state == "off" ? "" : (current-volume > 50 ? "" : "") })))) +(defwidget widget-microphone [] + (eventbox + :onhover "${EWW_CMD} update show-microphone=true" + :onhoverlost "${EWW_CMD} update show-microphone=false" + :onclick "${amixer} sset Capture toggle" + (box + :class "microphone" + :orientation "v" + :space-evenly "false" + :spacing "2" + :tooltip "Capture : ${current-microphone}% [${current-microphone-state}]" + (revealer :transition "slideup" :reveal show-microphone + (scale + :class "scale" + :value current-microphone + :orientation "v" + :flipped true + :marks true + :max 101 + :min 0 + :onchange "${amixer} sset Capture {}%" )) + (label + :class "icon" + :width 25 :height 20 + :xalign 0.5 :yalign 0.5 + :noindent true + :text { current-microphone-state == "off" ? "" : "" })))) +(defpoll current-volume :interval "1s" "amixer sget Master | grep 'Left:' | awk -F'[][]' '{ print $2 }' | tr -d '%'") +(defpoll current-volume-state :interval "1s" "amixer sget Master | grep 'Left:' | awk -F'[][]' '{ print $4 }'") +(defpoll current-microphone :interval "1s" "amixer sget Capture | grep 'Left:' | awk -F'[][]' '{ print $2 }' | tr -d '%'") +(defpoll current-microphone-state :interval "1s" "amixer sget Capture | grep 'Left:' | awk -F'[][]' '{ print $4 }'") +(defvar show-volume false) +(defvar show-microphone false) + +; FIXME: Maybe use a env var here instead +(defvar cpu-temp-key "ASUS_WMI_SENSORS_CPU_TEMPERATURE") +(defvar gpu-temp-key "AMDGPU_MEM") +(defvar temperature-threshold 80) + +(defwidget widget-temperature [] + (eventbox + :onclick temperature-monitor + (overlay + (box + :class "temperature" + :orientation "h" + :tooltip "CPU ${EWW_TEMPS[cpu-temp-key]}°C; GPU ${EWW_TEMPS[gpu-temp-key]}°C" + :space-evenly true + :width 25 + :halign "" :valign "center" + (progress + :class { EWW_TEMPS[cpu-temp-key] > temperature-threshold ? "temperature-progress-critical" : "temperature-progress-cpu" } + :halign "center" :valign "center" + :flipped "true" + :width 3 + :orientation "v" + :value {EWW_TEMPS[cpu-temp-key]} + ) + (progress + :class { EWW_TEMPS[gpu-temp-key] > temperature-threshold ? "temperature-progress-critical" : "temperature-progress-gpu" } + :halign "center" :valign "center" + :flipped "true" + :width 3 + :orientation "v" + :value {EWW_TEMPS[gpu-temp-key]} + ) + ) + (label + :valign "end" + :class "temperature-icon" + :text "") + ))) +(defwidget widget-cpu [] + (box + :class "cpu" + :orientation "v" + (circular-progress + :class "progress" + :width 25 + :height 25 + :thickness 4 + :tooltip " ${round(EWW_CPU.avg, 2)}%" + :value {EWW_CPU.avg} + ))) +(defwidget widget-memory [] + (box + :class "memory" + :orientation "v" + (circular-progress + :class "progress" + :width 25 + :height 25 + :thickness 4 + :tooltip " ${round(100 * EWW_RAM.used_mem / EWW_RAM.total_mem, 2)}%" + :value {EWW_RAM.used_mem_perc} + ))) +(defwidget widget-tray [] + (systray + :class "systray" + :orientation "v" + :space-evenly true + :icon-size 25 + :prepend-new true )) -(defpoll weather_text :initial "" :interval "180s" - "curl --max-time 2 wttr.in") - -(defwindow weather - :geometry (geometry :x "70px" - :y "50%" - :width "270px" - :height "60px") - (box weather_text)) - - -(defwindow calendar - :geometry (geometry :x "70px" - :y "65%" - :width "270px" - :height "60px") - (cal)) - -(defwidget widget_clock [] +(defwidget widget-clock [] (box :class "clock" :orientation "v" :valign "end" :spacing 1 - (box :class "icon" "") - "${clock.H}" "${clock.M}" - (box :class "icon" "") - "${clock.m}" "${clock.d}" + :width 20 + :tooltip {formattime(EWW_TIME, "%F (%a) %T [%Z]")} + ;(box :class "icon" "") + (label :text "${clock.m}") + (label :text "${clock.d}") + (label :class "icon" :text "") + (label :text "${clock.H}") + (label :text "${clock.M}") )) (defpoll clock :initial "{}" :interval "10s" "date '+{\"H\":\"%H\", \"M\":\"%M\", \"d\":\"%d\", \"m\":\"%m\", \"b\":\"%b\", \"Y\":\"%Y\"}'") - ; Calendar (defwindow calendar @@ -97,7 +259,7 @@ :y "65%" :width "270px" :height "60px") -(cal)) + (cal)) (defwidget cal [] @@ -115,56 +277,25 @@ (defpoll calendar_year :interval "10h" "date '+%Y'") -; Unused widgets +; Weather -(defwidget widget_status [] +(defwidget widget-weather [orientation] (box - :class "status" - :orientation "v" + :class "weather" + :orientation orientation :space-evenly false - :valign "end" - (metric :label "" - :value volume - :onchange "amixer -D pulse sset Master {}%") - (metric :label "" - :value {EWW_RAM.used_mem_perc} - :onchange "") - (widget_clock))) - - -(defwidget widget_media [] - (box :class "media" - :orientation "v" - :space-evenly false - :valign "center" - {music_listener != "" ? "『${music_listener}』" : ""} - (box :class "music_status" - :orientation "h" - :space-evenly false - :halign "center" - {music_listener != "" ? "${music_status_listener}" : ""}) + :valign "start" + :halign "center" + :spacing 10 + (button :onclick "scripts/popup weather" "W") )) -(deflisten music_listener :initial "" - "playerctl --follow metadata --format '{{ artist }} / {{album}} / {{ title }}' || true") -(deflisten music_status_listener :initial "" - "playerctl --follow metadata --format '{{duration(position)}}/{{duration(mpris:length)}}' || true") +(defpoll weather-text :initial "" :interval "180s" + "curl --max-time 2 wttr.in") - -(defwidget metric [label value onchange] - (box - :orientation "v" - :class "metric" - :space-evenly false - (box :class "label" label) - (circular-progress :value value) - ;(scale - ; :min 0 :max 101 - ; :active {onchange != ""} - ; :orientation "v" - ; :value value - ; :onchange onchange) - )) - -(defpoll volume :initial 0 :interval "1s" - "scripts/get-volume.sh") +(defwindow weather + :geometry (geometry :x "70px" + :y "50%" + :width "270px" + :height "60px") + (box weather-text)) diff --git a/eww/bar/scripts/compositor-control b/eww/bar/scripts/compositor-control new file mode 100755 index 0000000..656bf38 --- /dev/null +++ b/eww/bar/scripts/compositor-control @@ -0,0 +1,193 @@ +#!/usr/bin/env python + +""" +Utility to generate the workspace buttons for eww bar widget. + +Currently it fetches information from monitor 0. If all monitors have +synchronised workspaces this should not be a problem. +""" +import os, sys, socket, json, subprocess +from typing import Optional, Self, override + +WORKSPACE_ICONS = [ + (1, "☱"), + (2, "☲"), + (3, "☳"), + (4, "☴"), + (5, "☵"), + (6, "☶"), + (7, "☷"), + (8, "☰"), +] +EXTRA_WORKSPACE_ICONS = [ + (0, "⚌"), + (1, "⚍"), + (2, "⚎"), + (3, "⚏"), +] + +Workspaces = dict[int, bool] + +def get_widgets(workspaces: Workspaces) -> str: + """ + Create widget sexp from workspace information + """ + def get_class(k): + key = workspaces.get(k, None) + if key is None: + return "inactive" + elif key: + return "focused" + else: + return "active" + + buttons = [ + f'"id": "{k}", "text": "{icon}", "class": "{get_class(k)}"' + for k, icon in WORKSPACE_ICONS + ] + buttons = ", ".join(["{" + b + "}" for b in buttons]) + return "[" + buttons + "]" + +class CompositorHandler: + @staticmethod + def create() -> Optional[Self]: + """ + Main entry point, detects the type of compositor used + """ + if signature := os.environ.get("HYPRLAND_INSTANCE_SIGNATURE", None): + # See https://wiki.hyprland.org/IPC/ + xdg_runtime_dir = os.environ["XDG_RUNTIME_DIR"] + socket_addr = f"/{xdg_runtime_dir}/hypr/{signature}/.socket2.sock" + return HyprlandHandler(socket_addr) + if signature := os.environ.get("SWAYSOCK", None): + return SwayHandler() + return None + + def listen_workspaces(self): + pass + def listen_active_window_title(self): + pass + def set_workspace(self, i): + pass + +class HyprlandHandler(CompositorHandler): + def __init__(self, socket_addr): + self.socket_addr = socket_addr + + def listen(self, callback): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + sock.connect(self.socket_addr) + except Exception as e: + print(f"Could not connect to {self.socket_addr}", file=sys.stderr) + raise e + + callback(data=None) + while sock: + data = sock.recv(1024) + callback(data) + + @staticmethod + def get_workspace_info() -> Workspaces: + workspaces = json.loads(os.popen("hyprctl workspaces -j").read()) + monitors = json.loads(os.popen("hyprctl monitors -j").read()) + if not monitors: + print("No monitor found!", file=sys.stderr) + return [] + + monitor, active = [ + (m["name"], m["activeWorkspace"]["id"]) for m in monitors if m["id"] == 0 + ][0] + workspaces = { + w["id"]: w["id"] == active + for w in workspaces if w["monitor"] == monitor + } + return workspaces + + @override + def listen_workspaces(self): + def callback(data): + if data is None or b"workspace" in data: + workspace_info = HyprlandHandler.get_workspace_info() + print(get_widgets(workspace_info), flush=True) + self.listen(callback) + + @override + def listen_active_window_title(self): + def callback(data): + if data is None: + active_window = json.loads(os.popen("hyprctl activewindow -j").read()) + print(active_window["title"], flush=True) + return + + prefix = b"activewindow>>" + payload = next((l[len(prefix):] + for l in reversed(data.split(b'\n')) + if l.startswith(prefix)), None) + + if payload is None: + return + + if b',' in payload: + _, title = payload.decode('utf-8').split(',', 1) + print(title, flush=True) + else: + print("", flush=True) + + self.listen(callback) + + @override + def set_workspace(self, i): + result = os.popen(f"hyprctl dispatch workspace {i}").read() + if result != "ok\n": + raise RuntimeError(f"Failed to set workspace: {result}") + + # FIXME: Set the wallpaper too. + # ~/.config/hypr/wallpaper.sh $1 + + +class SwayHandler(CompositorHandler): + @staticmethod + def get_workspace_info() -> Workspaces: + workspaces = json.loads(os.popen("swaymsg --raw -t get_workspaces").read()) + # REVIEW: This has not been tested on a multi-monitor setup. + workspaces = { + int(w["num"]): w["focused"] + for w in workspaces + } + return workspaces + + def listen_workspaces(self): + with subprocess.Popen(["swaymsg", "-t", "subscribe", "-m", '["workspace"]'], stdout=subprocess.PIPE) as proc: + workspace_info = SwayHandler.get_workspace_info() + print(get_widgets(workspace_info), flush=True) + while line := proc.stdout.readline(): + # FIXME: Use the swaymsg subscribe output + # Not needed + #info = json.loads(line) + workspace_info = SwayHandler.get_workspace_info() + print(get_widgets(workspace_info), flush=True) + + +if __name__ == "__main__": + if len(sys.argv) == 1: + print("Usage: wm-control workspaces|title") + + handler = CompositorHandler.create() + if handler is None: + print("No compositor found.", file=sys.stderr) + + key = sys.argv[1] + + if key == "workspaces": + handler.listen_workspaces() + elif key == "active-title": + handler.listen_active_window_title() + elif key == "set-workspace": + if len(sys.argv) != 3: + print(f"Set workspace must be accompanied by an argument", file=sys.stderr) + + arg = sys.argv[2] + handler.set_workspace(arg) + else: + print(f"Unknown key: {key}", file=sys.stderr) diff --git a/eww/bar/scripts/get-volume.sh b/eww/bar/scripts/get-volume.sh deleted file mode 100755 index a868b03..0000000 --- a/eww/bar/scripts/get-volume.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -amixer -D pulse sget Master | grep 'Left:' | awk -F'[][]' '{ print $2 }' | tr -d '%' | head -1 diff --git a/eww/bar/scripts/get-workspaces b/eww/bar/scripts/get-workspaces deleted file mode 100755 index 4c2070d..0000000 --- a/eww/bar/scripts/get-workspaces +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python - -""" -Utility to generate the workspace buttons for eww bar widget. - -Currently it fetches information from monitor 0. If all monitors have -synchronised workspaces this should not be a problem. -""" -import os, sys, socket, json, subprocess -from typing import Optional - -WORKSPACE_ICONS = [ - (1, "☱"), - (2, "☲"), - (3, "☳"), - (4, "☴"), - (5, "☵"), - (6, "☶"), - (7, "☷"), - (8, "☰"), -] -EXTRA_WORKSPACE_ICONS = [ - (0, "⚌"), - (1, "⚍"), - (2, "⚎"), - (3, "⚏"), -] - -Workspaces = dict[int, bool] - -def get_widgets(workspaces: Workspaces) -> str: - """ - Create widget sexp from workspace information - """ - def get_class(k): - key = workspaces.get(k, None) - if key is None: - return "inactive" - elif key: - return "focused" - else: - return "active" - - buttons = [ - f'"id": "{k}", "text": "{icon}", "class": "{get_class(k)}"' - for k, icon in WORKSPACE_ICONS - ] - buttons = ", ".join(["{" + b + "}" for b in buttons]) - return "[" + buttons + "]" - - -# Compositor specific information - -def hypr_get_workspace_info() -> Workspaces: - workspaces = json.loads(os.popen("hyprctl workspaces -j").read()) - monitors = json.loads(os.popen("hyprctl monitors -j").read()) - if not monitors: - print("No monitor found!", file=sys.stderr) - return [] - - monitor, active = [ - (m["name"], m["activeWorkspace"]["id"]) for m in monitors if m["id"] == 0 - ][0] - workspaces = { - w["id"]: w["id"] == active - for w in workspaces if w["monitor"] == monitor - } - return workspaces - - -def hypr_listen(socket_addr: str): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - try: - sock.connect(socket_addr) - except: - print(f"Could not connect to {socket_addr}", file=sys.stderr) - raise - - # The flush here is very important since python by default buffers! - workspace_info = hypr_get_workspace_info() - print(get_widgets(workspace_info), flush=True) - while sock: - data = sock.recv(1024) - if b"workspace" in data: - workspace_info = hypr_get_workspace_info() - print(get_widgets(workspace_info), flush=True) - - -def sway_get_workspace_info() -> Workspaces: - workspaces = json.loads(os.popen("swaymsg --raw -t get_workspaces").read()) - # REVIEW: This has not been tested on a multi-monitor setup. - workspaces = { - int(w["num"]): w["focused"] - for w in workspaces - } - return workspaces - -def sway_listen(): - proc = subprocess.Popen( - ["swaymsg", "-t", "subscribe", "-m", '["workspace"]'], stdout=subprocess.PIPE - ) - workspace_info = sway_get_workspace_info() - print(get_widgets(workspace_info), flush=True) - while line := proc.stdout.readline(): - # Not needed - info = json.loads(line) - workspace_info = sway_get_workspace_info() - print(get_widgets(workspace_info), flush=True) - - -def detect(): - """ - Main entry point, detects the type of compositor used - """ - if signature := os.environ.get("HYPRLAND_INSTANCE_SIGNATURE", None): - socket_addr = f"/tmp/hypr/{signature}/.socket2.sock" - return hypr_listen(socket_addr) - if signature := os.environ.get("SWAYSOCK", None): - return sway_listen() - - print("No compositor found.", file=sys.stderr) - return None - - -if __name__ == "__main__": - detect() diff --git a/eww/bar/scripts/workspace.sh b/eww/bar/scripts/workspace.sh deleted file mode 100755 index 1cc571b..0000000 --- a/eww/bar/scripts/workspace.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -hyprctl dispatch workspace $1 -~/.config/hypr/wallpaper.sh $1 diff --git a/hypr/hyprland.conf b/hypr/hyprland.conf index ad7c0b5..296e22b 100644 --- a/hypr/hyprland.conf +++ b/hypr/hyprland.conf @@ -10,8 +10,7 @@ monitor=,preferred,auto,auto # See https://wiki.hyprland.org/Configuring/Keywords/ for more -# waybar is executed after eww to have the intersection effect at top left -exec-once = hyprpaper & swaync & fcitx5 & eww --config ~/.config/eww/bar open bar & waybar +exec-once = hyprpaper & swaync & fcitx5 & flameshot & eww --config ~/.config/eww/bar open vbar # Source a file (multi-file configs) # source = ~/.config/hypr/myColors.conf @@ -52,10 +51,6 @@ decoration { # See https://wiki.hyprland.org/Configuring/Variables/ for more rounding = 10 - blur = yes - blur_size = 3 - blur_passes = 1 - blur_new_optimizations = on drop_shadow = yes shadow_range = 4 @@ -89,7 +84,7 @@ dwindle { master { # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more - new_is_master = true + #new_is_master = true } gestures { @@ -135,8 +130,8 @@ bind = $mainMod, space, exec, wofi --show drun -I -G #bind = $mainMod, X, exec, hyprctl switchxkblayout wooting-wootingtwo next # code:107 = PrintSc -bind = $mainMod, code:107, exec, grimblast copy screen -bind = $mainMod SHIFT, code:107, exec, grimblast copy area +bind = $mainMod, code:107, exec, flameshot gui +#bind = $mainMod SHIFT, code:107, exec, grimblast copy area # Move focus with mainMod + arrow keys bind = $mainMod, left, movefocus, l @@ -199,3 +194,6 @@ bind = $mainMod, mouse_up, workspace, e-1 # Move/resize windows with mainMod + LMB/RMB and dragging bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow + +bind = SUPER,Tab,cyclenext, # change focus to another window +bind = SUPER,Tab,bringactivetotop, # bring it to the top diff --git a/sway/launch.conf b/sway/launch.conf index ddd1921..f835fc7 100644 --- a/sway/launch.conf +++ b/sway/launch.conf @@ -1,9 +1,9 @@ exec /usr/share/swayfx/scripts/inactive-windows-transparency --opacity 0.8 -exec_always eww --config ~/.config/eww/bar open bar -bar { - position top - swaybar_command waybar -} +exec_always eww --config ~/.config/eww/bar open vbar +#bar { +# position top +# swaybar_command waybar +#} exec_always multibg-sway ~/.config/sway/wallpapers exec swaync exec fcitx5