;; ============== ;; переменные ;; ============== ;; состояния раскрытия для каждого монитора (defvar stats_reveal_0 false) (defvar vol_reveal_0 false) (defvar time_reveal_0 false) (defvar stats_reveal_1 false) (defvar vol_reveal_1 false) (defvar time_reveal_1 false) ;; слушатели (deflisten ws_data :initial "{}" "python3 $HOME/.config/eww/scripts/workspaces.py") (deflisten volume :initial '{"volume": 0, "muted": false}' "python3 -u $HOME/.config/eww/scripts/volume.py") (deflisten layout :initial "EN" "socat -u UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock - | stdbuf -oL awk -F'>>' '/activelayout/ {split(\$2, a, \",\"); print toupper(substr(a[2], 1, 2))}'") (deflisten tray_count :initial "0" "python3 $HOME/.config/eww/scripts/tray_monitor.py") (deflisten kb_leds :initial '{"caps":"0","num":"0"}' "python3 $HOME/.config/eww/scripts/kb_leds.py") ;; пуллы (defpoll timestr :interval "1s" "date '+%H:%M'") (defpoll datestr :interval "1m" "date '+%A, %B %d'") (defpoll temp :interval "5s" :initial "0" "cat /sys/class/hwmon/$(grep -l 'coretemp' /sys/class/hwmon/hwmon*/name | cut -d/ -f5)/temp1_input | awk '{print int($1/1000)}'") (defpoll gpu_temp :interval "30s" :initial "0" "nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits") (defpoll disk_free :interval "1m" "python3 $HOME/.config/eww/scripts/disk.py") ;; ============== ;; воркспейсы ;; ============== ;; слот под воркспейс (defwidget workspace_slot [data id] (revealer :reveal {data[id] != "null" && data[id].exists} :transition "slideleft" :duration "300ms" (box :class "ws-pill ${data[id].urgent ? 'urgent' : data[id].focused ? 'focused' : data[id].active ? 'active' : ''}" :space-evenly false :valign "center" (eventbox :onclick "hyprctl dispatch workspace ${id}" (box :space-evenly false :valign "center" (label :class "ws-id" :text "${id}") (revealer :reveal {arraylength(data[id].icons) > 0} :transition "slideright" :duration "350ms" (box :class "ws-icons-box" :space-evenly false :spacing 8 (for icon in {data[id].icons} (label :class "ws-icon-item" :text "${icon}"))))))))) ;; контейнер для 10 воркспейсов (defwidget workspaces [ws_data] (box :class "workspaces-rail" :space-evenly false (for i in "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" (workspace_slot :data ws_data :id i)))) ;; =========== ;; виджеты ;; =========== ;; трей (defwidget tray_dynamic [] (revealer :reveal {tray_count > 0} :transition "crossfade" :duration "400ms" (box :class "tray-capsule" (systray :icon-size 16 :spacing 8 :prepend-new true)))) ;; раскладка (defwidget kb_widget [] (box :class "capsule kb-pill ${kb_leds.caps == '1' ? 'caps-on' : ''} ${kb_leds.num == '1' ? 'num-on' : ''}" :space-evenly false (label :text {layout ?: "EN"} :class "kb-label"))) ;; звук (defwidget volumewidget [reveal_state reveal_var] (eventbox :cursor "pointer" :onclick "eww update ${reveal_var}=${!reveal_state}" :onrightclick "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle" :onscroll "echo {} | sed -e 's/up/5%+/g' -e 's/down/5%-/g' | xargs wpctl set-volume -l 1.35 @DEFAULT_AUDIO_SINK@" (box :class "capsule volume-pill ${reveal_state ? 'active' : ''} ${volume.muted || volume.volume == 0 || volume.volume == '0' ? 'muted' : ''}" :space-evenly false (label :class "icon" :text {volume.muted || volume.volume == 0 || volume.volume == "0" ? "" : (volume.volume < 50 ? "" : "")}) (label :class "stat-label" :text "${volume.volume}%" :width 38) (revealer :reveal reveal_state :transition "slideleft" (box :class "slide-wrapper" (scale :class "vol-bar" :min 0 :max 101 :value {volume.volume} :onchange "wpctl set-volume @DEFAULT_AUDIO_SINK@ {}%")))))) ;; часы (defwidget timewidget [reveal_state reveal_var] (eventbox :cursor "pointer" :onclick "eww update ${reveal_var}=${!reveal_state}" (box :class "capsule time-pill ${reveal_state ? 'active' : ''}" :space-evenly false (label :text timestr) (revealer :reveal reveal_state :transition "slideleft" (box :class "slide-wrapper" :space-evenly false (label :class "icon" :text "󰃭") (label :text datestr)))))) ;; cтатистика (defwidget statswidget [reveal_state reveal_var] (eventbox :cursor "pointer" :onclick "eww update ${reveal_var}=${!reveal_state}" (box :class "capsule stats-pill ${reveal_state ? 'active' : ''} ${(EWW_CPU.avg > 90 || EWW_RAM.used_mem_perc > 90 || (temp ?: 0) > 75 || (gpu_temp ?: 0) > 75) ? 'alert' : ''}" :space-evenly false (group :icon "" :value "${round(EWW_CPU.avg, 0)}%" :alert {EWW_CPU.avg > 90}) (group :icon "󰍛" :value "${round(EWW_RAM.used_mem_perc, 0)}%" :alert {EWW_RAM.used_mem_perc > 90}) (revealer :reveal reveal_state :transition "slideleft" (box :space-evenly false :class "slide-wrapper" (group :icon "󱛟" :value "${round(disk_free, 1)}GB" :alert {disk_free < 10}) (group :icon "" :value "${temp}°" :alert {(temp ?: 0) > 75}) (group :icon "󰢮" :value "${gpu_temp}°" :alert {(gpu_temp ?: 0) > 75})))))) ;; шаблон для иконки с текстом (defwidget group [icon value alert] (box :space-evenly false :class "stat-group" (label :class "icon ${alert ? 'alert' : ''}" :text icon :width 24) (label :class "stat-label ${alert ? 'alert' : ''}" :text value :width {icon == "󱛟" ? 65 : 40} :halign "start"))) ;; =============== ;; сборка бара ;; =============== ;; основной бар (с треем) (defwidget main_bar [mon_key t_rev t_var s_rev s_var v_rev v_var] (centerbox :class "bar-inner" (box :halign "start" (workspaces :ws_data {ws_data[mon_key]})) (box :halign "center" (timewidget :reveal_state t_rev :reveal_var t_var)) (box :halign "end" :space-evenly false (tray_dynamic) (kb_widget) (statswidget :reveal_state s_rev :reveal_var s_var) (volumewidget :reveal_state v_rev :reveal_var v_var)))) ;; дополнительный бар (defwidget side_bar [mon_key t_rev t_var s_rev s_var v_rev v_var] (centerbox :class "bar-inner" (box :halign "start" (workspaces :ws_data {ws_data[mon_key]})) (box :halign "center" (timewidget :reveal_state t_rev :reveal_var t_var)) (box :halign "end" :space-evenly false (tray_dynamic) (kb_widget) (statswidget :reveal_state s_rev :reveal_var s_var) (volumewidget :reveal_state v_rev :reveal_var v_var)))) ;; ======== ;; окна ;; ======== ;; окно бара для dvi (defwindow bar_0 :monitor 0 :exclusive false :stacking "fg" :geometry (geometry :width "100%" :anchor "top center") (side_bar :mon_key "DVI_I_1" :t_rev time_reveal_0 :t_var "time_reveal_0" :s_rev stats_reveal_0 :s_var "stats_reveal_0" :v_rev vol_reveal_0 :v_var "vol_reveal_0")) ;; окно бара для hdmi (defwindow bar_1 :monitor 1 :exclusive false :stacking "fg" :geometry (geometry :width "100%" :anchor "top center") (main_bar :mon_key "HDMI_A_1" :t_rev time_reveal_1 :t_var "time_reveal_1" :s_rev stats_reveal_1 :s_var "stats_reveal_1" :v_rev vol_reveal_1 :v_var "vol_reveal_1")) ;; обои (defwindow wallpaper_0 :monitor 0 :stacking "bg" :focusable false :geometry (geometry :width "100%" :height "100%") (box :style "background-image: url('/home/pyrschtjag/Pictures/wallhaven-0wl9jp.jpg'); background-size: cover;")) (defwindow wallpaper_1 :monitor 1 :stacking "bg" :focusable false :geometry (geometry :width "100%" :height "100%") (box :style "background-image: url('/home/pyrschtjag/Pictures/wallhaven-1jygr3.jpg'); background-size: cover;"))