better workspace bar

This commit is contained in:
soraefir
2026-06-16 03:02:34 +02:00
parent c95c417c18
commit 60e8119c21
5 changed files with 204 additions and 111 deletions

View File

@@ -93,6 +93,10 @@ tooltip {
.green { color: $base0B; } .green { color: $base0B; }
.blue { color: $base0C; } .blue { color: $base0C; }
.workspace-sep {
border-top: 2px solid $base03;
}
/* WINDOW WRAPPER CSS */ /* WINDOW WRAPPER CSS */
.winevent { .winevent {

View File

@@ -4,17 +4,17 @@
(module (module
(eventbox (eventbox
:onscroll "echo {} | sed -e 's/up/-1/' -e 's/down/+1/' | xargs -I % hyprctl eval \"hl.dispatch(hl.dsp.focus({ workspace = '%' }))\"" :onscroll "echo {} | sed -e 's/up/-1/' -e 's/down/+1/' | xargs -I % hyprctl eval \"hl.dispatch(hl.dsp.focus({ workspace = '%' }))\""
(box (box
:class "module workspaces" :class "module workspaces"
:orientation "v" :orientation "v"
(for ws in workspace (for ws in workspace
(button (button
:onclick "hyprctl eval \"hl.dispatch(hl.dsp.focus({ workspace = '${ws.number}' }))\"" :class `${ws.sep ? "workspace-sep" : ""}`
:onclick "hyprctl eval \"hl.dispatch(hl.dsp.focus({ workspace = '${ws.target}' }))\""
(label (label
:show-truncated false :show-truncated false
:class "icon-text ${ws.color}" :class `icon-text ${ws.color}`
:text `${ws.focused ? "󰜗" : "󰝥"}` :text `${ws.state == "focused" ? "󰜗" : ws.state == "active" ? "󰝥" : "○"}`
) )
) )
) )

View File

@@ -1,86 +1,174 @@
#!/usr/bin/env bash #!/usr/bin/env bash
colors=("blue" "blue" "green" "red") declare -A ws_windows=()
empty="grey" declare -A ws_name=()
declare -A ws_urgent=()
declare -A mon_active=()
focused_ws=""
focused_monitor=""
_state=""
_color=""
# get initial focused workspace load_workspaces() {
focusedws=$(hyprctl -j monitors | jaq -r '.[] | select(.focused == true) | .activeWorkspace.id') local raw
raw=$(hyprctl -j workspaces 2>/dev/null) || return
ws_windows=()
ws_name=()
while read -r id windows name; do
ws_windows[$id]=$windows
ws_name[$id]=$name
done < <(printf '%s' "$raw" | jaq -jr '.[] | (.id | tostring), " ", (.windows | tostring), " ", .name, "\n"' 2>/dev/null)
}
declare -A o=([1]=0 [2]=0 [3]=0 [4]=0 [5]=0 [6]=0 [7]=0 [8]=0 [9]=0 [10]=0) load_monitors() {
declare -A monitormap local raw
declare -A workspaces raw=$(hyprctl -j monitors 2>/dev/null) || return
mon_active=()
focused_ws=""
focused_monitor=""
while read -r name active_id is_focused; do
mon_active[$name]=$active_id
if [ "$is_focused" = "true" ]; then
focused_ws=$active_id
focused_monitor=$name
fi
done < <(printf '%s' "$raw" | jaq -jr '.[] | .name, " ", (.activeWorkspace.id | tostring), " ", (.focused | tostring), "\n"' 2>/dev/null)
}
# set color for each workspace load_urgent() {
status() { local raw
if [ "${o[$1]}" -eq 1 ]; then raw=$(hyprctl -j clients 2>/dev/null) || return
mon=${monitormap[${workspaces[$1]}]} ws_urgent=()
echo -n "${colors[$mon]}" while read -r wsid; do
ws_urgent[$wsid]=1
done < <(printf '%s' "$raw" | jaq -r '.[] | select(.urgent == true) | (.workspace.id | tostring)' 2>/dev/null)
}
ws_state_color() {
local id=$1
_state="empty"
_color="grey"
if [ "$id" = "$focused_ws" ]; then
_state="focused"
else else
echo -n "$empty" local mon
for mon in "${!mon_active[@]}"; do
if [ "${mon_active[$mon]}" = "$id" ]; then
_state="active"
break
fi
done
if [ "$_state" = "empty" ] && [ "${ws_windows[$id]:-0}" -gt 0 ]; then
_state="running"
fi
fi
if [ "$_state" != "empty" ]; then
if [ "${ws_urgent[$id]:-0}" -eq 1 ]; then
_color="red"
else
_color="blue"
fi
fi fi
} }
# handle workspace create/destroy ws_entry() {
workspace_event() { local id=$1 name=$2 target=$3 sep=${4:-false}
while read -r k v; do workspaces[$k]="$v"; done < <(hyprctl -j workspaces | jaq -jr '.[] | .id, " ", .monitor, "\n"') ws_state_color "$id"
} printf '{"id":%s,"name":"%s","target":"%s","state":"%s","color":"%s","sep":%s}' \
# handle monitor (dis)connects "$id" "$name" "$target" "$_state" "$_color" "$sep"
monitor_event() {
while read -r k v; do monitormap["$k"]=$v; done < <(hyprctl -j monitors | jaq -jr '.[] | .name, " ", .id, "\n"')
} }
# get all apps titles in a workspace
applist() {
ws="$1"
apps=$(hyprctl -j clients | jaq -jr '.[] | select(.workspace.id == '"$ws"') | .title + "\\n"')
echo -En "${apps%"\n"}"
}
# generate the json for eww
generate() { generate() {
echo -n '[' printf '['
local first=true
for i in {1..10}; do local neg_ids=() id
echo -n ''"$([ "$i" -eq 1 ] || echo ,)" '{"number": "'"$i"'", "color": "'"$(status "$i")"'", "focused": '"$([ "$focusedws" = "$i" ] && echo "true" || echo "false")"'}' #, "tooltip": "'$(applist "$i")'" }' for id in "${!ws_name[@]}"; do
if [[ "$id" == -* ]] && [ "${ws_name[$id]}" != "special:magic" ]; then
neg_ids+=("$id")
fi
done done
echo ']' local has_neg=false
if [ ${#neg_ids[@]} -gt 0 ]; then
has_neg=true
IFS=$'\n' sorted_neg=($(printf '%s\n' "${neg_ids[@]}" | sort -n)); unset IFS
for id in "${sorted_neg[@]}"; do
$first || printf ','
first=false
ws_entry "$id" "${ws_name[$id]}" "name:${ws_name[$id]}"
done
fi
local first_pos=true
for i in {1..9}; do
$first || printf ','
first=false
if $first_pos && $has_neg; then
ws_entry "$i" "$i" "$i" true
else
ws_entry "$i" "$i" "$i"
fi
first_pos=false
done
printf ']\n'
} }
# setup load_workspaces
load_monitors
# add monitors load_urgent
monitor_event
# add workspaces
workspace_event
# check occupied workspaces
for num in "${!workspaces[@]}"; do
o[$num]=1
done
# generate initial widget
generate generate
# main loop while read -r line; do
socat -u UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/"$HYPRLAND_INSTANCE_SIGNATURE"/.socket2.sock - | rg --line-buffered "workspace|mon(itor)?" | while read -r line; do event="${line%>>*}"
case ${line%>>*} in data="${line#*>>}"
case "$event" in
"workspace") "workspace")
focusedws=${line#*>>} # data is the workspace name, not id — resolve to id for named workspaces
focused_ws="$data"
for _k in "${!ws_name[@]}"; do
[ "${ws_name[$_k]}" = "$data" ] && { focused_ws="$_k"; break; }
done
unset "ws_urgent[$focused_ws]"
[ -n "$focused_monitor" ] && mon_active[$focused_monitor]="$focused_ws"
;;
"workspacev2")
focused_ws="${data%%,*}"
unset "ws_urgent[$focused_ws]"
[ -n "$focused_monitor" ] && mon_active[$focused_monitor]="$focused_ws"
;; ;;
"focusedmon") "focusedmon")
focusedws=${line#*,} focused_monitor="${data%%,*}"
_wsname="${data#*,}"
focused_ws="$_wsname"
for _k in "${!ws_name[@]}"; do
[ "${ws_name[$_k]}" = "$_wsname" ] && { focused_ws="$_k"; break; }
done
unset "ws_urgent[$focused_ws]"
mon_active[$focused_monitor]="$focused_ws"
;; ;;
"createworkspace") "urgent")
o[${line#*>>}]=1 wsid=$(hyprctl -j clients 2>/dev/null | jaq -r --arg addr "$data" '.[] | select(.address == $addr) | (.workspace.id | tostring)' 2>/dev/null)
[ -n "$wsid" ] && ws_urgent[$wsid]=1
;; ;;
"destroyworkspace") "createworkspace"*|"destroyworkspace"*|"moveworkspace"*)
o[${line#*>>}]=0 load_workspaces
load_monitors
;;
"openwindow"|"movewindow"*)
load_workspaces
;;
"closewindow")
load_workspaces
load_urgent
;; ;;
"monitor"*) "monitor"*)
monitor_event load_monitors
;; ;;
esac esac
generate generate
done done < <(socat -u UNIX-CONNECT:"$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" - | \
rg --line-buffered "^(workspace|focusedmon|createworkspace|destroyworkspace|openwindow|closewindow|movewindow|moveworkspace|monitor|urgent)")

View File

@@ -18,6 +18,7 @@ in {
{output = baseOutput//{ {output = baseOutput//{
criteria = "LG Electronics LG ULTRAGEAR+ 511NTDVGC194"; criteria = "LG Electronics LG ULTRAGEAR+ 511NTDVGC194";
mode = "2560x1440@480.168"; mode = "2560x1440@480.168";
# mode = "2560x1440x240.083";
# mode = "1920x1080x240.084"; # mode = "1920x1080x240.084";
};} };}
{output = baseOutput//{ {output = baseOutput//{
@@ -64,16 +65,25 @@ in {
]; ];
exec = [ exec = [
"${pkgs.eww}/bin/eww open bar --screen 0" "${pkgs.eww}/bin/eww open bar --screen 0"
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '1', monitor = 'DP-1', default = true });\"" "${pkgs.writeShellScript "kanshi-hyprland-init" ''
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '2', monitor = 'DP-2', default = true });\"" #!/usr/bin/env bash
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '3', monitor = 'DP-1', default = true });\"" ${pkgs.hyprland}/bin/hyprctl eval '
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '4', monitor = 'DP-1', default = true });\"" hl.workspace_rule({ workspace = "1", monitor = "DP-1", default = true })
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '5', monitor = 'DP-1', default = true });\"" hl.workspace_rule({ workspace = "2", monitor = "DP-2", default = true })
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '6', monitor = 'DP-1', default = true });\"" hl.workspace_rule({ workspace = "3", monitor = "DP-1", default = true })
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '7', monitor = 'DP-1', default = true });\"" hl.workspace_rule({ workspace = "4", monitor = "DP-1", default = true })
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '8', monitor = 'DP-1', default = true });\"" hl.workspace_rule({ workspace = "5", monitor = "DP-1", default = true })
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '9', monitor = 'DP-1', default = true });\"" hl.workspace_rule({ workspace = "6", monitor = "DP-1", default = true })
"${pkgs.hyprland}/bin/hyprctl eval \"hl.workspace_rule({ workspace = '0', monitor = 'DP-3', default = true });\"" hl.workspace_rule({ workspace = "7", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "8", monitor = "DP-2", default = true })
hl.workspace_rule({ workspace = "9", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "name:X", monitor = "DP-3", default = true })
'
${pkgs.hyprland}/bin/hyprctl eval 'hl.dispatch(hl.dsp.focus({ monitor = "DP-2" })); hl.dispatch(hl.dsp.focus({ workspace = "2" }));'
${pkgs.hyprland}/bin/hyprctl eval 'hl.dispatch(hl.dsp.focus({ monitor = "DP-3" })); hl.dispatch(hl.dsp.focus({ workspace = "name:X" }));'
#${pkgs.hyprland}/bin/hyprctl eval 'hl.monitor({ output = "DP-3", cm = "hdr" });'
''}"
"${pkgs.awww}/bin/awww restore" "${pkgs.awww}/bin/awww restore"
]; ];
};} };}
@@ -82,14 +92,34 @@ in {
outputs = [ outputs = [
{ {
criteria = "AOC 24E1W1 GNSKCHA086899"; criteria = "AOC 24E1W1 GNSKCHA086899";
transform = "180";
position = "0,0"; position = "0,0";
} }
{ {
criteria = "AOC 24E1W1 GNSKBHA080346"; criteria = "AOC 24E1W1 GNSKBHA080346";
position = "1920,0"; position = "0,1080";
} }
]; ];
exec = [ "${pkgs.eww}/bin/eww open bar --screen 1" ]; exec = [
"${pkgs.eww}/bin/eww open bar --screen 0"
"${pkgs.writeShellScript "kanshi-hyprland-init" ''
#!/usr/bin/env bash
${pkgs.hyprland}/bin/hyprctl eval '
hl.workspace_rule({ workspace = "1", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "2", monitor = "DP-2", default = true })
hl.workspace_rule({ workspace = "3", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "4", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "5", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "6", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "7", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "8", monitor = "DP-2", default = true })
hl.workspace_rule({ workspace = "9", monitor = "DP-1", default = true })
'
${pkgs.hyprland}/bin/hyprctl eval 'hl.dispatch(hl.dsp.focus({ monitor = "DP-2" })); hl.dispatch(hl.dsp.focus({ workspace = "2" }));'
''}"
"${pkgs.awww}/bin/awww restore"
];
};} };}
{profile = { {profile = {
name = "tower_1"; name = "tower_1";

View File

@@ -69,6 +69,10 @@ in {
scale = "auto"; scale = "auto";
bitdepth = 10; bitdepth = 10;
cm = "auto"; #dcip3 cm = "auto"; #dcip3
sdrbrightness = 1.4;
# sdrsaturation = 1.0;
# sdr_max_luminance = 220;
# sdr_min_luminance = 0.005;
}]; }];
#Fullscreen HDR is possible without the hdr cm setting if "render:cm_auto_hdr" is enabled. #Fullscreen HDR is possible without the hdr cm setting if "render:cm_auto_hdr" is enabled.
@@ -100,7 +104,7 @@ in {
disable_splash_rendering = true; disable_splash_rendering = true;
animate_mouse_windowdragging = false; animate_mouse_windowdragging = false;
animate_manual_resizes = false; animate_manual_resizes = false;
vrr = 2; vrr = 0; #vrr=2;
}; };
debug = { debug = {
vfr = false; vfr = false;
@@ -253,37 +257,6 @@ in {
]; ];
# windowrule = [ "noshadow, floating:0" ];
# windowrulev2 = [
# "workspace 2 silent, class:^(org.telegram.desktop)$"
# "workspace 2 silent, class:^(discord)$"
# "workspace 8 silent, class:^(org.keepassxc.KeePassXC)$"
# "workspace 8 silent, title:^(Nextcloud)$"
# "workspace 8 silent, class:^(Tk)$,title:^(Server Configuration)$"
# "float,class:^(org.keepassxc.KeePassXC)$,title:^(KeePassXC - Access Request)$"
# "pin,class:^(org.keepassxc.KeePassXC)$,title:^(KeePassXC - Access Request)$"
# "float,class:^(org.keepassxc.KeePassXC)$,title:^(Unlock Database - KeePassXC)$"
# "pin,class:^(org.keepassxc.KeePassXC)$,title:^(Unlock Database - KeePassXC)$"
# "float,title:^(Open)$"
# "float,title:^(Choose Files)$"
# "float,title:^(Save As)$"
# "float,title:^(Confirm to replace files)$"
# "float,title:^(File Operation Progress)$"
# "float,class:^(firefox)$,title:^(Picture-in-Picture)$"
# "pin,class:^(firefox)$,title:^(Picture-in-Picture)$"
# "suppressevent fullscreen,class:^(firefox)$,title:^(Picture-in-Picture)$"
# "float,class:^(firefox)$,title:^(Firefox — Sharing Indicator)$"
# "suppressevent fullscreen,class:^(firefox)$,title:^(Firefox — Sharing Indicator)$"
# "float,class:^(firefox)$,title:^(Extension:.* Mozilla Firefox)$"
# "suppressevent fullscreen,class:^(firefox)$,title:^(Extension:.* Mozilla Firefox)$"
# "float,class:^(org.telegram.desktop)$,title:^(Media viewer)$"
# "center,class:^(org.telegram.desktop)$,title:^(Media viewer)$"
# "idleinhibit fullscreen, class:^(.*)"
# "idleinhibit focus, class:^(steam_app_.*)$"
# "idleinhibit focus, class:^(mpv)$"
# ];
layer_rule = [ { layer_rule = [ {
match.namespace = "^eww%-blur$"; match.namespace = "^eww%-blur$";
blur = true; blur = true;
@@ -329,8 +302,6 @@ in {
(bind "SUPER + SHIFT + 8" (dsp.moveToWorkspace 8)) (bind "SUPER + SHIFT + 8" (dsp.moveToWorkspace 8))
(bind "SUPER + 9" (dsp.focusWorkspace 9)) (bind "SUPER + 9" (dsp.focusWorkspace 9))
(bind "SUPER + SHIFT + 9" (dsp.moveToWorkspace 9)) (bind "SUPER + SHIFT + 9" (dsp.moveToWorkspace 9))
(bind "SUPER + 0" (dsp.focusWorkspace 0))
(bind "SUPER + SHIFT + 0" (dsp.moveToWorkspace 0))
(bind "XF86AudioPlay" (dsp.exec "${lib.getExe pkgs.playerctl} play-pause")) (bind "XF86AudioPlay" (dsp.exec "${lib.getExe pkgs.playerctl} play-pause"))
(bind "XF86AudioPrev" (dsp.exec "${lib.getExe pkgs.playerctl} previous")) (bind "XF86AudioPrev" (dsp.exec "${lib.getExe pkgs.playerctl} previous"))
(bind "XF86AudioNext" (dsp.exec "${lib.getExe pkgs.playerctl} next")) (bind "XF86AudioNext" (dsp.exec "${lib.getExe pkgs.playerctl} next"))